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
的基本使用、配置檔案型別和初始目錄、處理使用者操作、自定義皮膚行為以及新增自定義介面等技巧,並封裝工具類,將能夠更高效地使用這兩個類建立和管理檔案選擇和儲存對話方塊。