テーブルビューの基本

macOS Swift

テーブルビューの基本(NSTableView)

macOS Mojava 10.14.6 / Xcode 11.3.1 / Swift 5.0
[image1.png]

テーブルビューの構造

テーブルビューオブジェクトは関連するオブジェクトの複合体である。中核となるクラスは NSTableViewクラスで、テーブルビューの各要素に対応する複数のクラスから構成される。また NSTableViewクラスはビューのスクロールを制御する NSClipViewと NSScrollViewクラスに包まれる。
[image11.png]
NSTableColumnオブジェクトはテーブルの列を表し、その中に表の個々のデータを表す NSTableCellViewオブジェクトをテーブルの行数分だけ持つ。これは一般的にセルと呼ばれるものに相当する。NSTableCellViewオブジェクトは中に NSTextFieldを持ち、データとして表示する文字列を表す。NSTableHeaderCellは、個々の列の見出しを表す。
NSTableHeaderViewは、見出し行を表すオブジェクト、NSTableRowViewは表の一行一行を表すオブジェクトで、これらは行を一つのオブジェクトとして扱うときに利用する。

テーブルビューオブジェクトを作成する

インタフェースビルダにより、xibファイルに TableViewオブジェクトを追加したとき、テーブルビューを構成するオブジェクト群が自動的に生成される。
[image2.png]

プロパティの設定

Interface Builderからプロパティを設定する。(プログラムからの設定も可能)
[image3.png]

データソースを作成する

テーブルビューに表示するデータはどのような形式のデータでも構わないが配列を使うことが多い。列が複数の場合は、配列の要素に配列または辞書を定義する。
本例では2次元配列をデータソースとする。1次元目の配列が行に、その中の要素が行の中のセルに相当する。

デリゲート&データソースメソッドを実装する

テーブルビューのデータは、いわゆるデリゲートパターンにより表示される。テーブルビューオブジェクトは、テーブルビューにデータを表示する必要が生じたとき、NSTableViewDataSourceプロトコルに準拠したデリゲートメソッドを自動的に起動する。
クラス宣言でデリゲートメソッドを実装することを宣言する。
NSTableViewオブジェクトと接続する

numberOfRows ( in: ) メソッドの実装

テーブルビューのレコード数を返す。

tableView ( _: viewFor: row: ) メソッドの実装

テーブルの各セルに表示するデータを返す。メソッドの引数は列オブジェク(col)と行番号(row)で、これにより表の行列の位置が特定できる。この位置に表示するデータをメソッドの戻り値とする。
戻り値の型は NSTableCellViewクラスである。戻り値となるオブジェクトは makeViewメソッドにより作成する。これにより作成したオブジェクトは使い回されるようなので、パフォーマンスの向上が見込まれる。このオブジェクトが保持する NSTextFieldオブジェクトに表示する文字列を設定する。
文字列以外のオブジェクトとして属性付き文字列、イメージ、ボタンなどを表示することもできる。具体的な方法については、テーブルビューの応用(4)セルにイメージ、ボタンを表示する を参照のこと

テーブルビューを表示する

reloadDataメソッドは、データソースからデータを読み込みテーブルビューを更新する。このメソッドは、まず、テーブルビューオブジェクトがロードされた時点で自動的に起動するが、データソースの値が変化してテーブルビューを再表示したいときにもプログラムから呼び出すことができる。
[image1.png]

全ソースコード AppDelegate

これ以降、テーブルビューのカスタマイズ方法についていくつか紹介する

スクロールビューの高さを計算する

テーブルビューは保持する行がスクロールビューに全て収まらない場合はその中でスクロールする。スクロールビューには、その大きさに応じた行が表示されるが、できれば最後の行が途中で切れることなく収まるようにしたい。行の高さと行数からスクロールビューの適切な高さを求める計算式は次の通りとなる。

スクロールビューの高さ =(1行の高さ+セル間隔)× 行数 + ヘッダの高さ

各要素のプロパティ名とデフォルト値(単位ピクセル)
本例では 5行のレコードを表示するので、スクロールビューの高さを 120ピクセルとしている。Interface Builderで定義するか、プログラムからプロパティに設定する。
120 = (17 + 2) x 5 + 25

指定した行を選択状態にする

行番号(0〜)を IndexSetに変換して、selectRowIndexesメソッドを呼ぶ。(byExtendingSelection引数は真偽値のどちらを指定しても動作は同じ。用途不明)
1行目を選択状態にする
[image7.png]
次の例は、データソースの最後の行を選択状態にするものである。テーブルビューに全件のレコードを表示することができない場合は scrollRowToVisibleメソッドにより最後の行がテーブルビューに現れるようにビューをスクロールさせる。
[image8.png]

複数の行を選択状態にする

allowsMultipleSelectionプロパティを指定すれば、一度に複数の行を選択することができる。
[image10.png]
行番号を取得するには selectedRowIndexesプロパティを参照する。この値は IndecSetという Indexを表す整数の集合で、mapメソッドにより整数の配列に変換することができる。

行が選択されたときに起動するデリゲートメソッド

任意の行をマウスでクリックすると、その行が青色反転し選択状態になる。また、そこから上下の矢印キーでカーソルを移動すると、移った先の行が選択状態になる。また、selectRowIndexesメソッドによりプログラムから指定した行を選択状態にできる。このとき起動するデリゲートメソッドが tableViewSelectionDidChangeである。
選択された行の行番号は NSTableViewオブジェクトの selectedRowプロパティから得られる。NSTableViewオブジェクトは、引数の Notificationオブジェクトから、またはインスタンス変数に代入されたオブジェクトから取得する。
見出し行をクリックすると、行番号は -1 になる。

列見出しをクリックしてデータをソートする

[image5.png]
列見出しをマウスでクリックすると
デリゲートメソッド tableView( _: mouseDownInHeaderOf: ) が起動する。
mouseDownInHeaderOf引数に設定された NSTableColumnオブジェクトの identifierプロパティから、クリックされた列が判る。 列に対応したデータのソートを行い、reloadDataメソッドによりテーブルビューを再表示する。
次のコードは「列1」のヘッダをクリックすると、列1の値をキーにしてデータソースのレコードを並べ替えるものである。 ソートの方向(昇順/降順)は、現在表示中のレコードの並びから決定する。昇順に並んでいたら好順にソート、降順に並んでいたらその逆となる。また、ソートの方向を示した記号(▲ or ▼)をヘッダの見出しに表示する。
なお、テーブルビューの値は文字列なので、数値としてソートしたい場合は値をInt型に変換する必要がある。
[注意事項]
このメソッドの中で、指定した行を選択状態にする selectRowIndexesメソッドを実行しても正しく動作しない。上記のコードではソートの後に1行目を選択しようとしている。厳密には一瞬選択状態になるがすぐに消えてしまう。ただし列見出しのクリックをゆっくりするとうまくいく。原因は不明。

reloadDataメソッドの注意事項

awakeFromNibメソッドの中で reloadDataメソッドを実行してはならない。下図のように一部の行の文字列が逆さまに表示される場合がある。理由はわからない。
[image4.png]