如何在 Cocoa MacOS Objective C 中为 NSSavePanel 创建自定义 NSView?

发布于 2025-01-10 10:32:17 字数 547 浏览 0 评论 0原文

输入图片此处描述

我需要将一个保存扩展选择器添加到我的 NSSavePanel 中,旁边有一个文本标签。在所附的屏幕截图中,我尝试证明我已成功使用 setAccessoryView 函数将 NSComboBox 添加到我的面板中。但是我不知道如何创建自定义 NSView,其中包括 NSComboBox 和 NSTextView 或等效项。我在互联网上没有找到任何教程(或者如果我找到一个它也非常过时)展示如何在 MacOS 上的 Cocoa 中的 Objective-C 中创建自定义 NSView。

如何创建包含组合框和文本标签的自定义 NSView ?或者如何将两个“库存”NSView 添加到同一个 NSSavePanel 中?请尽可能详细地回答,因为我的 Objective-C 经验非常有限。

enter image description here

I need to add a save extension selector with a text label next to it to my NSSavePanel. In the screenshot attached I try to demonstrate that I succeeded in adding an NSComboBox to my panel with the function setAccessoryView. However I have no idea how to create a custom NSView, which includes both an NSComboBox and an NSTextView or equivalent. I found no tutorials on the internet (or if I found one it was extremely outdated) showing how to create custom NSViews in objective-C in Cocoa on MacOS.

How can I create a custom NSView containing a combobox and a text label? Or how can I add two "stock" NSViews to the same NSSavePanel? Please be as detailed in your answer as possible, as I have very limited objective-c experience.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

早乙女 2025-01-17 10:32:17

您询问如何在 Objective-C 中创建一个 NSView 并使用 NSTextFieldNSComboBox 作为子视图。

基本上,您可以在 Interface Builder 中定义它们,并以编程方式将 Objective-C 中的结果视图设置为 NSSavePanelaccessoryView。或者,可以完全用 Objective-C 创建自定义 NSView,这可能是更简单的选择。

实例化 NSView 后,您可以使用 addSubview: 相应地添加 NSTextFieldNSComboBox 。然后,您可以使用 NSLayoutConstraints 设置自动布局,它负责调整 accessoryView 的大小并根据对话框的宽度正确排列子视图。

如果您以编程方式创建视图并使用自动布局,则必须将 translatesAutoresizingMaskIntoConstraints 显式设置为 NO

如果您想设置 allowedContentTypes ,通过 NSDictionary 将显示的扩展文本映射到 UTType 可能会很有用。

如果您将 NSComboBox 的委托设置为 self,那么您将通过 通知您 NSComboBox 中用户选择的更改comboBoxSelectionDidChange:

如果所讨论的内容在代码中得到了适当的实现,那么对于一个独立的示例来说,它可能看起来像这样:

#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import "ViewController.h"

@interface ViewController () <NSComboBoxDelegate>

@property (nonatomic, strong) NSSavePanel *savePanel;
@property (nonatomic, strong) NSDictionary<NSString *, UTType*> *typeMapping;

@end


@implementation ViewController

- (instancetype)initWithCoder:(NSCoder *)coder {
    if (self = [super initWithCoder:coder]) {
        _typeMapping = @{
            @"jpeg": UTTypeJPEG,
            @"png": UTTypePNG,
            @"tiff": UTTypeTIFF
        };
    }
    return self;
}

- (NSView *)accessoryView {
    NSTextField *label = [NSTextField labelWithString:@"Filetypes:"];
    label.textColor = NSColor.lightGrayColor;
    label.font = [NSFont systemFontOfSize:NSFont.smallSystemFontSize];
    label.alignment = NSTextAlignmentRight;
    
    NSComboBox *comboBox = [NSComboBox new];
    comboBox.editable = NO;
    for (NSString *extension in self.typeMapping.allKeys) {
        [comboBox addItemWithObjectValue:extension];
    }
    [comboBox setDelegate:self];
    
    NSView *view = [NSView new];
    [view addSubview:label];
    [view addSubview:comboBox];
    
    comboBox.translatesAutoresizingMaskIntoConstraints = NO;
    label.translatesAutoresizingMaskIntoConstraints = NO;
    
    [NSLayoutConstraint activateConstraints:@[
        [label.bottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:-12],
        [label.widthAnchor constraintEqualToConstant:64.0],
        [label.leadingAnchor constraintEqualToAnchor:view.leadingAnchor constant:0.0],

        [comboBox.topAnchor constraintEqualToAnchor:view.topAnchor constant:8.0],
        [comboBox.leadingAnchor constraintEqualToAnchor:label.trailingAnchor constant:8.0],
        [comboBox.bottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:-8.0],
        [comboBox.trailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:-20.0],
    ]];
    return view;
}

- (void)comboBoxSelectionDidChange:(NSNotification *)notification {
    NSComboBox *comboBox = notification.object;
    NSString *selectedItem = comboBox.objectValueOfSelectedItem;
    NSLog(@"### set allowedContentTypes to %@ (%@)", selectedItem, self.typeMapping[selectedItem]);
    [self.savePanel setAllowedContentTypes:@[ self.typeMapping[selectedItem] ]];
}

- (IBAction)onSave:(id)sender {
    NSWindow *window = NSApplication.sharedApplication.windows.firstObject;
    self.savePanel = [NSSavePanel new];
    self.savePanel.accessoryView = [self accessoryView];
    [self.savePanel beginSheetModalForWindow:window completionHandler:^(NSModalResponse result) {
        if (result != NSModalResponseOK) {
            return;
        }
        NSURL *fileURL = self.savePanel.URL;
        NSLog(@"### selectedFile: %@", fileURL);
    }];
}

- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];
}

@end

最后,上面的演示代码的屏幕截图看起来像这样:
演示截图

You asked how to create an NSView in Objective-C with an NSTextField and an NSComboBox as subviews.

Basically, you could define them in Interface Builder and programmatically set the resulting view in Objective-C as the accessoryView of the NSSavePanel. Alternatively, the custom NSView could be created entirely in Objective-C, which is probably the easier option here.

After instantiating an NSView, you can use addSubview: to add an NSTextField and an NSComboBox accordingly. Then you can use NSLayoutConstraints to set up Auto Layout, which takes care of sizing the accessoryView and arranging the subviews properly based on the width of the dialog.

If you create the views programmatically and use Auto Layout, you must explicitly set translatesAutoresizingMaskIntoConstraints to NO.

Should you want to set the allowedContentTypes, a textual mapping of the displayed extension to UTType via a NSDictionary might be useful.

If you set the delegate of the NSComboBox to self, then you will be informed about changes of the user selection in the NSComboBox via comboBoxSelectionDidChange:.

If the things discussed are implemented appropriately in code, it might look something like this for a self-contained example:

#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import "ViewController.h"

@interface ViewController () <NSComboBoxDelegate>

@property (nonatomic, strong) NSSavePanel *savePanel;
@property (nonatomic, strong) NSDictionary<NSString *, UTType*> *typeMapping;

@end


@implementation ViewController

- (instancetype)initWithCoder:(NSCoder *)coder {
    if (self = [super initWithCoder:coder]) {
        _typeMapping = @{
            @"jpeg": UTTypeJPEG,
            @"png": UTTypePNG,
            @"tiff": UTTypeTIFF
        };
    }
    return self;
}

- (NSView *)accessoryView {
    NSTextField *label = [NSTextField labelWithString:@"Filetypes:"];
    label.textColor = NSColor.lightGrayColor;
    label.font = [NSFont systemFontOfSize:NSFont.smallSystemFontSize];
    label.alignment = NSTextAlignmentRight;
    
    NSComboBox *comboBox = [NSComboBox new];
    comboBox.editable = NO;
    for (NSString *extension in self.typeMapping.allKeys) {
        [comboBox addItemWithObjectValue:extension];
    }
    [comboBox setDelegate:self];
    
    NSView *view = [NSView new];
    [view addSubview:label];
    [view addSubview:comboBox];
    
    comboBox.translatesAutoresizingMaskIntoConstraints = NO;
    label.translatesAutoresizingMaskIntoConstraints = NO;
    
    [NSLayoutConstraint activateConstraints:@[
        [label.bottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:-12],
        [label.widthAnchor constraintEqualToConstant:64.0],
        [label.leadingAnchor constraintEqualToAnchor:view.leadingAnchor constant:0.0],

        [comboBox.topAnchor constraintEqualToAnchor:view.topAnchor constant:8.0],
        [comboBox.leadingAnchor constraintEqualToAnchor:label.trailingAnchor constant:8.0],
        [comboBox.bottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:-8.0],
        [comboBox.trailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:-20.0],
    ]];
    return view;
}

- (void)comboBoxSelectionDidChange:(NSNotification *)notification {
    NSComboBox *comboBox = notification.object;
    NSString *selectedItem = comboBox.objectValueOfSelectedItem;
    NSLog(@"### set allowedContentTypes to %@ (%@)", selectedItem, self.typeMapping[selectedItem]);
    [self.savePanel setAllowedContentTypes:@[ self.typeMapping[selectedItem] ]];
}

- (IBAction)onSave:(id)sender {
    NSWindow *window = NSApplication.sharedApplication.windows.firstObject;
    self.savePanel = [NSSavePanel new];
    self.savePanel.accessoryView = [self accessoryView];
    [self.savePanel beginSheetModalForWindow:window completionHandler:^(NSModalResponse result) {
        if (result != NSModalResponseOK) {
            return;
        }
        NSURL *fileURL = self.savePanel.URL;
        NSLog(@"### selectedFile: %@", fileURL);
    }];
}

- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];
}

@end

Finally, a screenshot of the above demo code in action looks like this:
demo screenshot

情独悲 2025-01-17 10:32:17

按 Cmd-N 将新文件添加到您的项目中。选择一个视图文件以添加具有自定义视图的 xib 文件。

输入图片此处描述

打开 xib 文件并将控件添加到自定义视图。按项目窗口工具栏中的“添加”按钮以访问用户界面元素。

使用NSNIb类加载xib文件并获取自定义视图。

Press Cmd-N to add a new file to your project. Choose a View file to add a xib file that has a custom view.

enter image description here

Open the xib file and add the controls to the custom view. Press the Add button in the project window toolbar to access the user interface elements.

Use the NSNib class to load the xib file and get the custom view.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文