如何在 Cocoa MacOS objective C 中为 NSSavePanel 创建自定义 NSView?
How to create a custom NSView for NSSavePanel in Cocoa MacOS objective C?
我需要在 NSSavePanel
旁边添加一个带有文本标签的保存扩展选择器。在随附的屏幕截图中,我尝试证明我成功地使用函数 setAccessoryView
将 NSComboBox
添加到我的面板。但是我不知道如何创建自定义 NSView,其中包括 NSComboBox
和 NSTextView
或等效项。我在 Internet 上找不到任何教程(或者如果我找到一个它已经非常过时了)显示如何在 MacOS 上的 Cocoa 中的 objective-C 中创建自定义 NSView
s。
如何创建包含组合框和文本标签的自定义 NSView
?或者如何将两个“库存”NSView
添加到同一个 NSSavePanel
?请在您的回答中尽可能详细,因为我的 objective-c 经验非常有限。
按 Cmd-N 将新文件添加到您的项目中。选择一个视图文件以添加具有自定义视图的 xib 文件。
打开xib文件,将控件添加到自定义视图中。按项目 window 工具栏中的添加按钮访问用户界面元素。
使用 NSNib
class 加载 xib 文件并获取自定义视图。
您询问了如何在 Objective-C 中创建一个 NSView
并将 NSTextField
和 NSComboBox
作为子视图。
基本上,您可以在 Interface Builder 中定义它们,并以编程方式将 Objective-C 中的结果视图设置为 NSSavePanel
的 accessoryView
。或者,自定义 NSView
可以完全在 Objective-C 中创建,这可能是这里更简单的选择。
实例化一个NSView
后,您可以使用addSubview:
相应地添加一个NSTextField
和一个NSComboBox
。然后您可以使用 NSLayoutConstraints
设置自动布局,它负责调整 accessoryView
的大小并根据对话框的宽度正确排列子视图。
如果以编程方式创建视图并使用自动布局,则必须将 translatesAutoresizingMaskIntoConstraints
显式设置为 NO
。
如果您想设置 allowedContentTypes
,通过 NSDictionary
将显示的扩展名文本映射到 UTType
可能会有用。
如果您将 NSComboBox
的委托设置为 self
,那么您将通过 comboBoxSelectionDidChange:
收到有关 NSComboBox
中用户选择更改的通知。
如果所讨论的内容在代码中得到了适当的实现,self-contained 示例可能看起来像这样:
#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
最后,上面的演示代码的截图如下所示:
我需要在 NSSavePanel
旁边添加一个带有文本标签的保存扩展选择器。在随附的屏幕截图中,我尝试证明我成功地使用函数 setAccessoryView
将 NSComboBox
添加到我的面板。但是我不知道如何创建自定义 NSView,其中包括 NSComboBox
和 NSTextView
或等效项。我在 Internet 上找不到任何教程(或者如果我找到一个它已经非常过时了)显示如何在 MacOS 上的 Cocoa 中的 objective-C 中创建自定义 NSView
s。
如何创建包含组合框和文本标签的自定义 NSView
?或者如何将两个“库存”NSView
添加到同一个 NSSavePanel
?请在您的回答中尽可能详细,因为我的 objective-c 经验非常有限。
按 Cmd-N 将新文件添加到您的项目中。选择一个视图文件以添加具有自定义视图的 xib 文件。
打开xib文件,将控件添加到自定义视图中。按项目 window 工具栏中的添加按钮访问用户界面元素。
使用 NSNib
class 加载 xib 文件并获取自定义视图。
您询问了如何在 Objective-C 中创建一个 NSView
并将 NSTextField
和 NSComboBox
作为子视图。
基本上,您可以在 Interface Builder 中定义它们,并以编程方式将 Objective-C 中的结果视图设置为 NSSavePanel
的 accessoryView
。或者,自定义 NSView
可以完全在 Objective-C 中创建,这可能是这里更简单的选择。
实例化一个NSView
后,您可以使用addSubview:
相应地添加一个NSTextField
和一个NSComboBox
。然后您可以使用 NSLayoutConstraints
设置自动布局,它负责调整 accessoryView
的大小并根据对话框的宽度正确排列子视图。
如果以编程方式创建视图并使用自动布局,则必须将 translatesAutoresizingMaskIntoConstraints
显式设置为 NO
。
如果您想设置 allowedContentTypes
,通过 NSDictionary
将显示的扩展名文本映射到 UTType
可能会有用。
如果您将 NSComboBox
的委托设置为 self
,那么您将通过 comboBoxSelectionDidChange:
收到有关 NSComboBox
中用户选择更改的通知。
如果所讨论的内容在代码中得到了适当的实现,self-contained 示例可能看起来像这样:
#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
最后,上面的演示代码的截图如下所示: