Macアプリで NSTableView の row の background color を設定する
Macアプリ で NSTableView の row の background colorを設定するのが意外とややこしかったので、メモしておきます。
公式ドキュメントを参照すると、 tableView(_:willDisplayCell:for:row:) というメソッドがありました。
Discussion
The delegate can modify the display attributes of aCell to alter the appearance of the cell.
Because aCell is reused for every row in aTableColumn, the delegate must set the display attributes both when drawing special cells and when drawing standard cells.
デリゲートはセルの外観を変更するためにaCellの表示属性を変更できます。
aCellはaTableColumnのすべての行に再利用されるため、デリゲートは特殊セルを描画するときと標準セルを描画するときの両方で表示属性を設定する必要があります。(Google翻訳)
メソッドの説明を読むと、よさそうな感じです。
さらに調べると、 NSTableRowView に backgroundColor のプロパティがあったので、試してみました。
code: Swift
func tableView(_ tableView: NSTableView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, row: Int) {
if let tableRowView = tableView.rowView(atRow: row, makeIfNecessary: false) {
tableRowView.backgroundColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
print("tableRowView \(row)")
}
}
しかし、色が変わりません。
調べてみると、こちらの記事 Coloring a Row in an NSTableView を見つけました。
Only if you're using a view-based table. If we're talking about cell-based tables, as I think we are, then the rowViewAtRow:... method will always return nil.
ビューベースのテーブルを使用している場合に限ります。 私たちが思うように、セルベースのテーブルについて話しているのであれば、rowViewAtRow:...メソッドは常にnilを返します。(Google翻訳)
なんと、 rowView(atRow:makeIfNecessary:) は View Based の NSTableView の場合だけ使えるとのことです(NSTableRowView を返すメソッドだから、よく考えたら当たり前ですが)。
今回は Cell Based に設定していたので、 nil が返ってきていました。
https://gyazo.com/ad309baa04da21e12a88a91505d38e19
というわけで、View Based に変更しました。
今度こそいけるだろうと思って実行すると、またまた色が変わりません。調べてみると、 tableView(_:willDisplayCell:for:row:) が呼ばれていませでした。willDisplayCell だから、Cell Based でないと呼ばれないのかもしれません。
あちらを立てればこちらが立たず、で行き詰まりかけましたが、ふと思いついて tableView(_:viewFor:row:) で色を変えてみたらいけました!
code: Swift
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let tableRowView = tableView.rowView(atRow: row, makeIfNecessary: false)
tableRowView?.backgroundColor = #colorLiteral(red: 0, green: 0.9768045545, blue: 0, alpha: 1)
let cell = tableView.makeView(withIdentifier: (tableColumn?.identifier)!, owner: self) as! NSTableCellView
if let tcol = tableColumn {
if(tcol.identifier.rawValue == "No.") {
cell.textField?.stringValue = "\(row)"
} else if(tcol.identifier.rawValue == "Text") {
cell.textField?.stringValue = "\(row)ですよ"
}
}
return cell
}
https://gyazo.com/ecbfc822f99b286d83ed07e183f4cbe1
任意のタイミングで row の色を変えたかったので、そちらも試してみました。
Textセルをクリックすると赤色に変更して、No.セルをクリックするとその行を reload して緑色に戻るようにしました。
code: Swift
@IBAction func clickTableView(_ sender: NSTableView) {
switch sender.clickedColumn {
case 0:
let row = IndexSet(integer: sender.clickedRow)
let column = IndexSet(integer: sender.clickedColumn)
sender.beginUpdates()
sender.reloadData(forRowIndexes: row, columnIndexes: column)
sender.endUpdates()
case 1:
let tableRowView = sender.rowView(atRow: sender.clickedRow, makeIfNecessary: false)
tableRowView?.backgroundColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
default:
print("default")
}
}
https://gyazo.com/014be0a941239ad840e1c3a71b3d959a
赤色と緑色に変更できるようになりました。
NSTableView の構造や View Based ・ Cell Based の違いがよくわかっていないのですっかりハマってしまいました。
こちらの公式ドキュメント About Table Views in OS X Applications を読んで、NSTableViewへの理解を深めないとです。
あと、 こちらの HMDTさんのサイト も情報がまとまっているので、合わせて読み進めます。