Mac Cocoa NSOutlineView 資料綁定

此篇實作是接續「NSOutlineView 使用程式呈現樹狀資料」,那次是用程式來處理,本篇要使用 Cocoa Binding 的方式來綁定資料。

關於 Cocoa Binding,可先參考這篇「Mac Cocoa 資料綁定 (Binding) 實作測試」的基本概念。

簡單來說,就是利用資料綁定的方法來呈現樹狀目錄,而不是寫一堆程式來處理。

準備資料

為了配合綁定的需求,把上一個例子的資料稍為修改如下,主要是加上 class 要加上 @objcMembers,變數要加上 @objc 和 dynamic。

底下就是全部的程式了。

 

import Cocoa

 

// MARK: 資料結構

@objcMembers class Sutra: NSObject {

    dynamic var name: String = ""

    dynamic var sub: [Sutra] = []

    init (_ name: String) {

        self.name = name

    }

}

 

class ViewController: NSViewController {

    

    @objc dynamic var sutra: [Sutra] = []

 

    override func viewDidLoad() {

        super.viewDidLoad()

 

        // 資料實作

        makeSutra()

    }

 

    override var representedObject: Any? {

        didSet {

        // Update the view, if already loaded.

        }

    }

        

    // MARK: 自訂成員函式,資料實作

    fileprivate func makeSutra() {

        sutra.append(Sutra("阿含"))

        sutra[0].sub.append(Sutra("雜阿含"))

        sutra[0].sub.append(Sutra("中阿含"))

        sutra[0].sub.append(Sutra("長阿含"))

        

        sutra.append(Sutra("般若"))

        sutra[1].sub.append(Sutra("心經"))

        sutra[1].sub.append(Sutra("金剛經"))

        sutra[1].sub[1].sub.append(Sutra("能斷金剛"))

        sutra[1].sub[1].sub.append(Sutra("般若金剛"))

    }

}

 

綁定設定

接下來的綁定設定才是重頭戲,有些細節我也還不明白,請依順序操作。

綁定 Tree Controller

首先,在元件庫找到 Tree Controller,將它拉到畫面位置,這是我第一次使用這個元件,看起來是要成為資料與 Outline View 的協調元件。

image

接著點選 Tree Controller,選 Bindings inspector,下拉 Content Array,勾選 Bind to,並選擇 View Controller。

Model Key Path 則填入 self.sutra。

表示 Tree Controller 和我們的資料 sutra 綁定了。

image

再選擇屬性頁,將它的 Children 填入 sub。

表示子層就是由 sutra 的 sub 來處理。

image

綁定 Outline View

再來設定 Outline View,選 Outline View,再選 Bindsing inspector,下拉 Content,勾選 Bind to,並選擇 Tree Controller。

Controller Key 保留 arrangedObjects,Model Key Path 則保持空白。

我也不懂這些設定是什麼意思,只知道這是 Outline View 又與 Tree Controller 綁在一起了。

image

小心 Table Cell View

底下是額外的設定,也是一個坑。

在前一篇的實作中,Outline View 第一個 Column 的第一個 Table Cell View 曾經把它的 Identifier 設定為 outlineViewCell,在這裡要把它清掉,設任何名稱都不行,否則會造成第一欄沒有文字呈現,原因我也不明白。

前不知道這個問題,一直做不出結果來,最後把 Outline View 刪掉,重拉一個新的,一切重新設定才成功,再逐一還原設定,才知道是這裡在搞鬼。

image

綁定 Table View Cell

接著點選第一個 Table View Cell。注意,不是剛剛那個 Table Cell View。再選 Bindings inspector,下拉 Value,勾選 Bind to,並選擇 Table Cell View。

Model Key Path 則填入 objectValue.name。

這裡就設定了要呈現 Sutra 的 name 屬性。

我猜想上一個步驟若 Table Cell View 設定了 Identifier,這裡就無法正確綁定了。至於要如何綁定有設 Identifier 的 Table Cell View,就要再研究或等某一天找到答案了。

image

執行程式

以上,就是設定好資料,並且綁定了三個元件:

 

Tree Controller  -> 綁定 View Controller 的資料源

Outline View  -> 綁定 Tree Controller

Table View Cell -> 綁定 Table Cell View

 

執行後,全部展開就可以看到如下成果。

image

因為第二個 Table View Cell 沒有綁定,所以它呈現 Table View Cell。

使用綁定似乎比使用程式處理簡單多了,但綁定的屬性有點複雜,目前我也只會照抄,不明白每一個細節。

另外我也做了一個實驗,加一個按鈕,按下去會增加 sutra 的資料。

在使用綁定的情況下,按下按鈕就可以立刻看到資料增加。

而使用程式碼處理的情況下,要重新打開該層,才會看到該層的變化,綁定看起來是比較具有即時性的。

判斷 Click 的內容

前一個實驗已經記錄了三種處理 Click 的方法,這裡只記載差異處。

首先,要把 Outline View 元件拉 Outlet 到 ViewController 中,前一個實驗有拉,綁定資料因為幾乎沒用到程式,所以一開始沒拉。

底下是 Click 需要的程式。

 

    override func viewDidLoad() {

        super.viewDidLoad()

 

        // 資料實作

        makeSutra()

 

        // 處理 click

        outlineView.target = self

        outlineView.action = #selector(self.onItemClicked)

    }

    

    // 處理 click

    @objc private func onItemClicked(sender: Any) {

        if let node = outlineView.item(atRow: outlineView.clickedRow) as? NSTreeNode {

            if let item = node.representedObject as? Sutra {

                print("\(item.name)")

                print("(\(outlineView.clickedRow),\( outlineView.clickedColumn))")

            }

        }

    }

綁定資料與用程式處理資料的處理法有一點不同。

程式處理所 Click 的 Item 是直接轉成 Sutra,而綁定則是先轉換成 NSTreeNode,再把它的 representedObject 轉成 Sutra,就可以由 Sutra 取得相關的資料了。

 

重要度:
文章分類:

發表新回應

借我放一下廣告