NSOpenPanel
和 NSSavePanel
是 macOS 应用中的两个重要控件,分别用于文件和文件夹的选择(打开)以及文件的保存(保存)。
NSOpenPanel
NSOpenPanel
是用于展示系统的打开文件对话框的类,用户可以通过它来选择文件或文件夹。
基本使用
Objective-C
#import <Cocoa/Cocoa.h>
// 创建并配置 NSOpenPanel
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
// 允许用户选择文件
[openPanel setCanChooseFiles:YES];
// 允许用户选择文件夹
[openPanel setCanChooseDirectories:YES];
// 允许多选
[openPanel setAllowsMultipleSelection:YES];
// 设置对话框标题
[openPanel setTitle:@"选择文件或文件夹"];
// 显示对话框,并异步处理用户选择
[openPanel beginWithCompletionHandler:^(NSModalResponse result) {
if (result == NSModalResponseOK) {
// 获取用户选择的 URL 列表
NSArray<NSURL *> *urls = [openPanel URLs];
for (NSURL *url in urls) {
NSLog(@"选择的文件/文件夹: %@", url.path);
}
} else {
NSLog(@"用户取消了选择");
}
}];
Swift
import Cocoa
// 创建并配置 NSOpenPanel
let openPanel = NSOpenPanel()
// 允许用户选择文件
openPanel.canChooseFiles = true
// 允许用户选择文件夹
openPanel.canChooseDirectories = true
// 允许多选
openPanel.allowsMultipleSelection = true
// 设置对话框标题
openPanel.title = "选择文件或文件夹"
// 显示对话框,并异步处理用户选择
openPanel.begin { result in
if result == .OK {
// 获取用户选择的 URL 列表
let urls = openPanel.urls
for url in urls {
print("选择的文件/文件夹: \(url.path)")
}
} else {
print("用户取消了选择")
}
}
配置文件类型过滤
Objective-C
// 只允许选择特定类型的文件(例如:只选择图片文件)
[openPanel setAllowedFileTypes:@[@"jpg", @"png", @"gif"]];
Swift
// 只允许选择特定类型的文件(例如:只选择图片文件)
openPanel.allowedFileTypes = ["jpg", "png", "gif"]
指定初始目录
Objective-C
// 设置初始目录
[openPanel setDirectoryURL:[NSURL fileURLWithPath:@"/Users/username/Documents"]];
Swift
// 设置初始目录
openPanel.directoryURL = URL(fileURLWithPath: "/Users/username/Documents")
处理用户取消操作
Objective-C
[openPanel beginWithCompletionHandler:^(NSModalResponse result) {
if (result == NSModalResponseOK) {
// 用户选择了文件或文件夹
} else {
// 用户取消了操作
NSLog(@"用户取消了选择");
}
}];
Swift
openPanel.begin { result in
if result == .OK {
// 用户选择了文件或文件夹
} else {
// 用户取消了操作
print("用户取消了选择")
}
}
NSSavePanel
NSSavePanel
是用于展示系统的保存文件对话框的类,用户可以通过它来选择保存文件的位置和名称。
基本使用
Objective-C
#import <Cocoa/Cocoa.h>
// 创建并配置 NSSavePanel
NSSavePanel *savePanel = [NSSavePanel savePanel];
// 设置对话框标题
[savePanel setTitle:@"保存文件"];
// 设置默认文件名
[savePanel setNameFieldStringValue:@"Untitled.txt"];
// 显示对话框,并异步处理用户选择
[savePanel beginWithCompletionHandler:^(NSModalResponse result) {
if (result == NSModalResponseOK) {
NSURL *saveURL = [savePanel URL];
NSLog(@"保存路径: %@", saveURL.path);
// 在这里可以进行文件保存操作,例如将数据写入到 saveURL 所指示的文件路径中
} else {
NSLog(@"用户取消了保存");
}
}];
Swift
import Cocoa
// 创建并配置 NSSavePanel
let savePanel = NSSavePanel()
// 设置对话框标题
savePanel.title = "保存文件"
// 设置默认文件名
savePanel.nameFieldStringValue = "Untitled.txt"
// 显示对话框,并异步处理用户选择
savePanel.begin { result in
if result == .OK {
if let saveURL = savePanel.url {
print("保存路径: \(saveURL.path)")
// 在这里可以进行文件保存操作,例如将数据写入到 saveURL 所指示的文件路径中
}
} else {
print("用户取消了保存")
}
}
配置文件类型限制
Objective-C
// 只允许保存特定类型的文件(例如:只保存为文本文件)
[savePanel setAllowedFileTypes:@[@"txt"]];
Swift
// 只允许保存特定类型的文件(例如:只保存为文本文件)
savePanel.allowedFileTypes = ["txt"]
指定初始目录和文件名
Objective-C
// 设置初始目录
[savePanel setDirectoryURL:[NSURL fileURLWithPath:@"/Users/username/Documents"]];
// 设置默认文件名
[savePanel setNameFieldStringValue:@"MyDocument.txt"];
Swift
// 设置初始目录
savePanel.directoryURL = URL(fileURLWithPath: "/Users/username/Documents")
// 设置默认文件名
savePanel.nameFieldStringValue = "MyDocument.txt"
强制文件扩展名
Objective-C
// 强制附加的文件扩展名
[savePanel setExtensionHidden:NO];
Swift
// 强制附加的文件扩展名
savePanel.isExtensionHidden = false
封装工具类
为了更方便地使用 NSOpenPanel
和 NSSavePanel
,可以封装一个工具类,提供常见功能的高层接口。
Objective-C
#import <Cocoa/Cocoa.h>
@interface FileDialogHelper : NSObject
+ (void)showOpenPanelWithTitle:(NSString *)title
canChooseFiles:(BOOL)canChooseFiles
canChooseDirectories:(BOOL)canChooseDirectories
allowsMultipleSelection:(BOOL)allowsMultipleSelection
allowedFileTypes:(NSArray<NSString *> *)allowedFileTypes
completionHandler:(void (^)(NSArray<NSURL *> *urls))completionHandler;
+ (void)showSavePanelWithTitle:(NSString *)title
defaultFileName:(NSString *)defaultFileName
allowedFileTypes:(NSArray<NSString *> *)allowedFileTypes
completionHandler:(void (^)(NSURL *url))completionHandler;
@end
@implementation FileDialogHelper
+ (void)showOpenPanelWithTitle:(NSString *)title
canChooseFiles:(BOOL)canChooseFiles
canChooseDirectories:(BOOL)canChooseDirectories
allowsMultipleSelection:(BOOL)allowsMultipleSelection
allowedFileTypes:(NSArray<NSString *> *)allowedFileTypes
completionHandler:(void (^)(NSArray<NSURL *> *urls))completionHandler {
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel setTitle:title];
[openPanel setCanChooseFiles:canChooseFiles];
[openPanel setCanChooseDirectories:canChooseDirectories];
[openPanel setAllowsMultipleSelection:allowsMultipleSelection];
[openPanel setAllowedFileTypes:allowedFileTypes];
[openPanel beginWithCompletionHandler:^(NSModalResponse result) {
if (result == NSModalResponseOK) {
completionHandler([openPanel URLs]);
} else {
completionHandler(nil);
}
}];
}
+ (void)showSavePanelWithTitle:(NSString *)title
defaultFileName:(NSString *)defaultFileName
allowedFileTypes:(NSArray<NSString *> *)allowedFileTypes
completionHandler:(void (^)(NSURL *url))completionHandler {
NSSavePanel *savePanel = [NSSavePanel savePanel];
[savePanel setTitle:title];
[savePanel setNameFieldStringValue:defaultFileName];
[savePanel setAllowedFileTypes:allowedFileTypes];
[savePanel beginWithCompletionHandler:^(NSModalResponse result) {
if (result == NSModalResponseOK) {
completionHandler([savePanel URL]);
} else {
completionHandler(nil);
}
}];
}
@end
Swift
import Cocoa
class FileDialogHelper {
// 显示打开对话框
static func showOpenPanel(title: String,
canChooseFiles: Bool,
canChooseDirectories: Bool,
allowsMultipleSelection: Bool,
allowedFileTypes: [String]?,
completionHandler: @escaping ([URL]?) -> Void) {
let openPanel = NSOpenPanel()
openPanel.title = title
openPanel.canChooseFiles = canChooseFiles
openPanel.canChooseDirectories = canChooseDirectories
openPanel.allowsMultipleSelection = allowsMultipleSelection
openPanel.allowedFileTypes = allowedFileTypes
openPanel.begin { result in
if result == .OK {
completionHandler(openPanel.urls)
} else {
completionHandler(nil)
}
}
}
// 显示保存对话框
static func showSavePanel(title: String,
defaultFileName: String,
allowedFileTypes: [String]?,
completionHandler: @escaping (URL?) -> Void) {
let savePanel = NSSavePanel()
savePanel.title = title
savePanel.nameFieldStringValue = defaultFileName
savePanel.allowedFileTypes = allowedFileTypes
savePanel.begin { result in
if result == .OK {
completionHandler(savePanel.url)
} else {
completionHandler(nil)
}
}
}
}
使用示例
Objective-C
// 使用示例:显示打开对话框
[FileDialogHelper showOpenPanelWithTitle:@"选择文件或文件夹"
canChooseFiles:YES
canChooseDirectories:YES
allowsMultipleSelection:YES
allowedFileTypes:@[@"jpg", @"png"]
completionHandler:^(NSArray<NSURL *> *urls) {
if (urls) {
for (NSURL *url in urls) {
NSLog(@"选择的文件/文件夹: %@", url.path);
}
} else {
NSLog(@"用户取消了选择");
}
}];
// 使用示例:显示保存对话框
[FileDialogHelper showSavePanelWithTitle:@"保存文件"
defaultFileName:@"Untitled.txt"
allowedFileTypes:@[@"txt"]
completionHandler:^(NSURL *url) {
if (url) {
NSLog(@"保存路径: %@", url.path);
} else {
NSLog(@"用户取消了保存");
}
}];
Swift
// 使用示例:显示打开对话框
FileDialogHelper.showOpenPanel(title: "选择文件或文件夹",
canChooseFiles: true,
canChooseDirectories: true,
allowsMultipleSelection: true,
allowedFileTypes: ["jpg", "png"]) { urls in
if let urls = urls {
for url in urls {
print("选择的文件/文件夹: \(url.path)")
}
} else {
print("用户取消了选择")
}
}
// 使用示例:显示保存对话框
FileDialogHelper.showSavePanel(title: "保存文件",
defaultFileName: "Untitled.txt",
allowedFileTypes: ["txt"]) { url in
if let url = url {
print("保存路径: \(url.path)")
} else {
print("用户取消了保存")
}
}
深入探讨
自定义面板行为
有时候,你可能希望自定义 NSOpenPanel
或 NSSavePanel
的行为,例如在用户选择某个文件或目录时执行特定的检查。
Objective-C
// Example of custom delegate for NSOpenPanel
@interface CustomOpenPanelDelegate : NSObject <NSOpenPanelDelegate>
@end
@implementation CustomOpenPanelDelegate
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url {
// 只允许选择特定的文件或目录
if ([url.pathExtension isEqualToString:@"txt"]) {
return YES;
}
return NO;
}
@end
// 使用自定义代理
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
CustomOpenPanelDelegate *delegate = [[CustomOpenPanelDelegate alloc] init];
[openPanel setDelegate:delegate];
Swift
// Example of custom delegate for NSOpenPanel
class CustomOpenPanelDelegate: NSObject, NSOpenPanelDelegate {
func panel(_ sender: Any, shouldEnable url: URL) -> Bool {
// 只允许选择特定的文件或目录
if url.pathExtension == "txt" {
return true
}
return false
}
}
// 使用自定义代理
let openPanel = NSOpenPanel()
let delegate = CustomOpenPanelDelegate()
openPanel.delegate = delegate
面板定制界面
你可以在 NSOpenPanel
和 NSSavePanel
中添加额外的用户界面元素,例如文本字段或复选框。
Objective-C
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
// 创建自定义视图,例如一个 NSTextField
NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
[textField setStringValue:@"请输入额外信息"];
// 添加自定义视图到面板
[openPanel setAccessoryView:textField];
Swift
let openPanel = NSOpenPanel()
// 创建自定义视图,例如一个 NSTextField
let textField = NSTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 24))
textField.stringValue = "请输入额外信息"
// 添加自定义视图到面板
openPanel.accessoryView = textField
总结
通过了解 NSOpenPanel
和 NSSavePanel
的基本使用、配置文件类型和初始目录、处理用户操作、自定义面板行为以及添加自定义界面等技巧,并封装工具类,将能够更高效地使用这两个类创建和管理文件选择和保存对话框。