- Xcode 用 Storyboard 開發程式記錄
- Cocoa 用程式操控視窗 (上)
- Cocoa 用程式操控視窗 (中)
- Cocoa 用程式操控視窗 (下)
在這系列【Xcode 用 Storyboard 開發程式記錄】已經學會了建立視窗與畫面,開啟視窗,以及為元件寫簡單程式。
底下這一系列就要學習如何用程式來開啟視窗,以及跨視窗操作視窗和元件等各種功能,最後再實作一個總複習,讓視窗與元件的控制可以自在無礙,這也是未來設計 CBReader Mac 版的的前測試。
程式開啟視窗 (使用 Segue)
如果不由 Button 建立 Segue 自動開啟視窗,而想由程式控制,方法如下:
不要由 Button 連結到第二個視窗,而是由第一個視窗的 View Controller 連結到子視窗。
選擇 Show。
點選藍色的 Segue,並為其命名 toOption。
在 Button 建立程式碼:
@IBAction func btToOption(_ sender: Any) {
performSegue(withIdentifier: "toOption", sender: self)
}
如此就可以由程式來開啟 Option 視窗了。
程式開啟視窗 (不使用 Segue)
設計一個按鈕,直接由 storyboard 取得資料,產生 WindowController,並使之呈現。
@IBAction func btToOption(_ sender: Any) {
// 取得 storyboard
let storyboard = NSStoryboard(name: "Main", bundle: nil)
// 取得 WindowController
let OptionWinController = storyboard.instantiateController(withIdentifier: "OptionWindowController") as! NSWindowController
// 取得 window
let OptionWin = OptionWinController.window
// 呈現視窗
OptionWin!.orderFront(self)
}
取消多重視窗設定
在 View Controller 的 Presentation 設定 Single 就不會開啟重複的視窗。
隱藏 View
view.isHidden = true
這功能可以把視窗清空,但視窗還在,只有內容隱藏。
隱藏 Window
如果只是要隱藏視窗,可以使用
view.windows!.orderOut(nil)
而呈現則是用
window!.orderFront(self)
不過這應該是要由另一個 View 或功能來呼叫一個已經隱藏的 Window,因為原來的 Widow 已經隱藏起來了。
補充:orderFront 會把視窗顯現出來,但並不會取得焦點,可以改用 makeKeyAndOrderFront 就可以了。
程式關閉視窗
建立一個 Button,在 Button 撰寫關閉視窗的程式,網路上有三種方法:
windowController.close()
self.view.window!.windowController!.close()
這是 NSWindowController 的 close(),這個方法不會要求用戶確認而直接關閉視窗。[官方說明]
Window.close()
self.view.window!.close()
這是 NSWindow 的 close(),它會通知發佈 willCloseNotification 到默認通知中心。[官方說明]
window.performClose()
self.view.window!.performClose(nil)
或
self.view.window!.performClose(self)
這個方法比較靈活。
如果窗口的委託或窗口本身實現 windowShouldClose(_:),則以窗口作為參數發送該消息。(僅發送一條這樣的消息;如果委託和 NSWindow 對像都實現了該方法,則只有委託接收該消息。)如果 windowShouldClose(_:) 該方法返回 false,則不會關閉窗口。如果返回 true,或者未實現,則 performClose(_:) 調用 close() 該方法以關閉窗口。
如果窗口沒有關閉按鈕或無法關閉(例如,如果委託人回復 false 給windowShouldClose(_:) 訊息),則系統會發出警報聲。[官方說明]
執行 windoShouldClose
視窗關閉時,如果有實作 windowShouldClose(_:),則會執行它,若傳回 true 才會關閉視窗,傳回 false 則不會關閉。
實作的方法有二種:
1. 在 ViewController 實作
第一種方法是在 ViewController 自身中實作。底下程式中,紅色是後來加上去的。
1. 在 class 要繼承 NSWindowDelegate,因為 windowShouldClose 是 NSWindowDelegate 的成員函式。
2. 撰寫 override viewWillAppear,並在其中加入
self.view.window!.delegate = self
表示 View 的 Window 的代理就是 ViewController 這個 class。
之前是寫在 viewDidLoad 中,所以一直失敗,因為此時 view.window 還沒產生,無法指定代理。
根據 Window 與 View 的生命周期,viewDidLoad 之後才有 windowDidLoad,所以在 viewWillAppear 中指定代理就可以了。
- viewDidLoad
- windowDidLoad
- viewWillAppear
- ......
3. 之後就可以實作 windowShouldClose 和 windowWillClose 了。
import Cocoa
// 繼承 NSWindowDelegate
class ViewController: NSViewController , NSWindowDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
// 在 viewWillAppear 指定 window 的代理
override func viewWillAppear() {
view.window!.delegate = self
}
func windowShouldClose(_ sender: NSWindow) -> Bool {
print("Window Should Close")
return true
}
func windowWillClose(_ notification: Notification) {
print("Window Will Close")
}
}
2. 子類化 NSWindowController
第二種方法是子類化 NSWindowController,在其自身實作。
1. 建立新的 Cocoa Class 檔案,選 NSWindowController,命名為 MainWindowController。
2. 在 Storyboard 的 Window 點選上方紅框 Window Controller,然後在左邊的 Class 選 MainWindowController,表示指定 Window Controller 是剛剛建立的 Class。
3. 在 MainWindowController 中,先繼承 NSWindowDelegate,因為 windowShouldClose 是 NSWindowDelegate 的成員函式。
4. 之後就可以實作 windowShouldClose 和 windowWillClose 了。
import Cocoa
// 繼承 NSWindowDelegate
class MainWindowController: NSWindowController, NSWindowDelegate {
override func windowDidLoad() {
super.windowDidLoad()
//window!.delegate = self
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
func windowShouldClose(_ sender: NSWindow) -> Bool {
print("Window Should Close")
return true
}
func windowWillClose(_ notification: Notification) {
print("Window Will Close")
}
}
看起來第二個方法好像稍為麻煩一點。
附註:
如果用第二種方法,而視窗又是用程式開啟,也就是上面不使用 Segue 開啟的視窗,則關閉時好像無法執行 windowShouldClose,目前原因不明。日後待查!
- Xcode 用 Storyboard 開發程式記錄
- Cocoa 用程式操控視窗 (上)
- Cocoa 用程式操控視窗 (中)
- Cocoa 用程式操控視窗 (下)
- 瀏覽次數:9202
發表新回應