LoginSignup
1
3

More than 5 years have passed since last update.

[cocoa][swift]テーブルビューを使ったmacOSアプリケーション

Posted at

macOSとiOSのUI関連のフレームワークには差異があり、前者はNeXTSTEPから受け継がれたスタイルとなっていて、後者は貧弱な計算機リソースでの利用を想定した設定となっている。

ただ、最近ではmacOSのフレームワークの方がiOSの方に合わせることが可能な部分については似せてきていて、テーブルビューの場合は昔からのCell BasedとiOSと同様なView Basedの二通りの方式があるという状況だ。前者については非推奨となっているため、後者についてサンプルを作りながら説明する。

新規プロジェクトを生成。macOSでCocoa Appを選択。

新規プロジェクト.png

"Use Storyboards"と"Create Document-Bassed Application"を選択する。

プロジェクトの種類.png

nib(ファイル名のsuffixはxib)でなくStoryboardを選んだ場合、iOSに似たViewControllerを利用した構成となる。iOS向けの開発経験者にとっては、その方が分かりやすいと思うが、macOSプログラミングの書籍の多くはnibの場合の説明となっているので、どちらが学習しやすいか悩ましい問題だ。ただ、今後はStoryboardだと思うので茨の道だがこちらの道を選択することにした。

Storyboardで、ViewにライブラリからTable Viewを配置し、TableViewのContent ModeがView Basedになっていることを確認する。

ViewBased.png

サンプルでは、テーブルの列を2にしたが、列に識別子をつけるのは大事だ。iOSの場合、列は1個のみなので、行番号となるインデックスのみで良かったが、macOSでは列を識別するものが必要だ。また、列の順番を変更することができるので、列インデックスでは対応できない。

列の識別子.png

Storyboardを選ぶと、ビューコントローラが生成されるが、これとTable ViewをdataSourceとdelegateで繋げる。

繋げる.png

ターブルビューの行数や、表示する欄の設定は、iOSのUITableViewと似ている。

ViewControllerの親にNSTableViewDataSourceとNSTableViewDelegateを追加する。

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
    ...
}

行数を返す。

    public func numberOfRows(in tableView: NSTableView) -> Int {
        return 64
    }

欄の内容をビューで返す。

    public func tableView(_ tableView: NSTableView, viewFor
        tableColumn: NSTableColumn?, row: Int) -> NSView? {
        print(#function + " column:" +
            tableColumn!.identifier.rawValue + " row:" + String(row))
        var result: NSTextField? =
            tableView.makeView(withIdentifier:NSUserInterfaceItemIdentifier(rawValue:
                "MyView"), owner: self) as? NSTextField
        if result == nil {
            result = NSTextField(frame: NSZeroRect)
            result?.identifier =
                NSUserInterfaceItemIdentifier(rawValue: "MyView")
        }
        if let view = result {
            print("view:" + view.identifier!.rawValue + " row:" + String(row))
            if let column = tableColumn {
                if column.identifier.rawValue == "TableColumn1" {
                    view.stringValue = "column 01"
                }
                else if column.identifier.rawValue == "TableColumn2" {
                    view.stringValue = "column 02"
                }
            }
        }
        return result
    }

Storyboardで設定した識別子で列がわかるので、列に対応したビューを返している。

好奇心公正な人なら、非推奨だと分かっていても、以前のCell Basedが気になっていると思うので調べてみた。

行数を返すのは同様だ。

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    NSInteger count=0;
    if (self.namesArray)
        count=[self.namesArray count];
    return count;
}

欄の内容を返すのも似ている。

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
    id returnValue=nil;
    NSString *columnIdentifer = [aTableColumn identifier];
    NSString *theName = [namesArray objectAtIndex:rowIndex];
    if ([columnIdentifer isEqualToString:@"name"]) {
        returnValue = theName;
    }
    return returnValue;
}

ただ、メソッドの戻り値の型がidだ。どういう事なのだろうか?

Cell Basedでは、ビューを管理するセルが存在する。デフォルトでは文字列を表示するビューが用意され、それを管理するセルに対して、値となるNSStringを返しているということのようだ。

複雑な欄を表示したい場合、それ様のセルを用意することになるが、それが一手間となるし、セルはビューでないので、ビューの重なりも独自に保持しないといけない。

大変そうなので、Cell Basedの探求はここまでにしておこう。

ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/mac/VisiCalc - GitHub

【関連情報】
Table View Programming Guide for Mac

Cocoa.swift 2019-03

Cocoa.swift 2019-04

Cocoa.swift

Cocoa勉強会 関東

MOSA

Cocoa練習帳

Qiita

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3