NSTableView ViewBasedを試してみる(macos)

NSTableView CellBasedを試してみたのだが、ViewBasedという実装方法もあるらしいので、試してみた。

ディレクトリを選択したら、配下のファイルを表示させる。

tableview_viewbased

のだが、なんのために使い分けるのかよくわからない。。。

関連クラスのマニュアルを一部抜粋

NSTableView

  • NSTableViewのサブクラス化は通常必要ありません。
  • その代わりに、NSTableViewDelegate プロトコルに準拠したデリゲートオブジェクトおよび、NSTableViewDataSource プロトコルに準拠したデータソースオブジェクトを使用してテーブルビューをカスタマイズします。
  • または、以下のサブコンポーネントのいずれかをサブクラス化することで、実現できます。
    • セル(NSCellベースのテーブルビューを使用する場合)
    • 行セルビューまたは行ビュー(NSViewベースのテーブルビューを使用する場合)

NSTableViewDelegate

  • TableViewの振る舞いをカスタマイズするために実装するオプションメソッドのセット
  • TableViewのサブクラスを作成せずに動作をカスタマイズすることができます。テーブルの行と列のビューを提供し、列の並べ替えやサイズ変更、行の選択などの機能をサポート

NSCell

  • NSViewのサブクラスのオーバーヘッドなしで、ビューオブジェクトにテキストや画像を表示するためのメカニズム
  • セルは、NSControlクラスのほとんどで、その内部動作を実装するために使用されている

NSView

  • アプリ内で描画、印刷、イベント処理などを行うための基盤
  • 通常、NSViewオブジェクトを直接使用することはありません。代わりに、NSViewから派生したクラスのオブジェクトを使用するか、NSViewを自分でサブクラス化し、必要な動作を実装するためにそのメソッドをオーバーライドします。NSViewクラス(またはそのサブクラス)のインスタンスは、一般的にビューオブジェクトとして、または単にビューとして知られています

NSTableColumn を選択し idenfifer を指定 tableView メソッドが呼び出されるときに、identifer をキーに値を取得させる。

Nstableview viewbased00003

ViewBasedとか、CellBasedという切り口で切り分けるのはちょっと違う感がするな。

とりあえず、メモしておく。

import Cocoa
import Foundation

class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
    private static let fm = FileManager.default
    private var files: [File] = []
    
    @IBOutlet weak var fileTable: NSTableView!
    @IBOutlet weak var directoryPath: NSPathControl!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    
    func numberOfRows(in tableView: NSTableView) -> Int {
        return files.count;
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
       
        let file = files[row]
        let cell = tableView.makeView(withIdentifier: (tableColumn!.identifier), owner: self) as? NSTableCellView
        let celval = file.get(key: tableColumn!.identifier.rawValue)
        cell?.textField?.stringValue = celval!

        return cell
    }
    
    @IBAction func chooseDir(_ sender: Any) {
        let dialog = NSOpenPanel();

        dialog.title                   = "Choose Directory"
        dialog.showsResizeIndicator    = true
        dialog.showsHiddenFiles        = false
        dialog.allowsMultipleSelection = false
        dialog.canChooseDirectories    = true
        dialog.canChooseFiles          = false

        if (dialog.runModal() ==  NSApplication.ModalResponse.OK) {
            let result = dialog.url

            if (result != nil) {
                let path: String = result!.path
                directoryPath.url = URL(fileURLWithPath: path)
                
                self.files.removeAll()
                
                loadFiles(basePath: path)
                
                self.fileTable.reloadData()
            }
        }
    }
    private func loadFiles(basePath: String) {
        if !isDirectory(path: basePath) {
            return
        }
        files.append(File(path: basePath, name: basePath, isDirectory: true, isOn: false))
        
        do {
            let fileNames = try ViewController.fm.contentsOfDirectory(atPath: basePath)
            
            for fileName in fileNames {
                let childPath = basePath + "/" + fileName
                if isDirectory(path: childPath) {
                    loadFiles(basePath:childPath)
                }
                print("\t" + childPath)
                files.append(File(path: childPath, name: fileName, isDirectory: false, isOn: true))
            }
            
            
        } catch {
            print(error)
        }
    }
    
    private func isDirectory(path: String) -> Bool {
        var isDir = ObjCBool(false)
        ViewController.fm.fileExists(atPath: path, isDirectory: &isDir)
        return isDir.boolValue
    }
    
    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
}

public class File {
    let path: String
    let name: String
    let isDirectory: Bool
    var isOn: Bool = false
    
    init(path: String, name: String, isDirectory: Bool, isOn: Bool) {
        self.path = path
        self.name = name
        self.isDirectory = isDirectory
        self.isOn = isOn
    }
    public func get(key: String) -> String? {
        switch key {
        case "path":
            return self.path
        case "name":
            return self.name
        default:
            return nil
        }
    }
}

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です