特定の条件を満たす行は、黄緑にしたい。
かつ、選択したら青くしたい。
だから、特定の条件を満たし、かつ、選択したら混ぜた色にしたい。
面倒くさいなぁ。
背景色を変えるだけなら単純。
NSTableViewオブジェクト.GetRowView(変更したい行, true).BackgroundColor = NSColor.FromRGB(R値, G値, B値);
さらに、選択行を変更したら、
- 選択を解除した行の色を元に戻す
- 選択した行の色に青味を足す
をしなきゃいけない。
これに加えて、選択した行が見えなくなるまでグリッドをスクロールし、戻ってくると、選択色が解除される問題にも取り掛かる。
どうやらスクロールして戻ってくると、NSTableViewオブジェクト.DelegateのGetViewForItem関数が実行され、そのときに背景色を変に初期化しちゃうと元に戻っちゃう……ぽい?
そんなわけで、NSTableViewオブジェクト.Delegateに割り当てるDelegateクラスを実装する。
public class MyDelegate : NSTableViewDelegate
{
// 使う色を定義しておく
private static readonly NSColor BaseColor = NSColor.FromRgb(背景色のRGB値);
private static readonly NSColor HitColor = NSColor.FromRgb(144, 238, 144); // 黄緑
private static readonly NSColor SelectColor = NSColor.FromRgb(98, 167, 222); // 青
private static readonly NSColor HitAndSelectColor = NSColor.FromRgb(58, 167, 185); // 混ぜた色
// 選択した行を覚えておく
private int SelectedRow { get; set; } = -1;
// テーブルの列定義辞書
public new Dictionary<string, funcDelegate> TableColumnsDict = new Dictionary<string, funcDelegate>()
{
//{"DisplayName", "" },
};
/// <summary>
/// テーブル列の値設定用デリゲート
/// </summary>
/// <param name="rowView">設定先の行コントロール</param>
/// <param name="obj">設定先セルのテキストコントロール</param>
/// <param name="row">何行目か</param>
/// <param name="isSelectRow">選択された行か</param>
public delegate void funcDelegate(NSTableRowView rowView, NSObject obj, nint row, bool isSelectRow);
/// <summary>
/// 行選択イベント
/// </summary>
/// <param name="tableView">選択変更前のテーブル</param>
/// <param name="row">選択行</param>
/// <returns>行変更を許可するならtrue</returns>
public override bool ShouldSelectRow(NSTableView tableView, nint row)
{
// 行の色変更
// ここで変更しないとクリック時に色が変わらない
SetBackColor(tableView, (int)tableView.SelectedRow, this.SelectedRow);
return true;
}
/// <summary>
/// テーブルの背景色の設定
/// </summary>
/// <param name="table">テーブル</param>
/// <param name="preRow">選択が外れる行</param>
/// <param name="selectRow">選択行</param>
protected virtual void SetBackColor(NSTableView table, int preRow, int selectRow)
{
// 選択が外れる行の背景色を設定
if (0 <= preRow)
{
table.GetRowView(preRow, true).BackgroundColor = 特定の条件 ? HitColor : BaseColor;
}
// 選択した行の背景色を選択
if (0 <= selectRow)
{
table.GetRowView(selectRow, true).BackgroundColor = 特定の条件 ? HitAndSelectColor : SelectColor;
}
}
/// <summary>
/// テーブルの各列の値設定用デリゲートを実行する
/// </summary>
/// <param name="tableView">テーブル</param>
/// <param name="tableColumn">カラム</param>
/// <param name="row">何行目か</param>
/// <returns></returns>
public override NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, nint row)
{
NSTextField view = (NSTextField)tableView.MakeView("Cell", this);
if (view == null)
{
view = new NSTextField();
view.Identifier = "Cell";
// ひとまず透過で初期化
view.BackgroundColor = NSColor.Clear;
}
if (TableColumnsDict.ContainsKey(tableColumn.Identifier))
{
TableColumnsDict[tableColumn.Identifier](tableView.GetRowView(row, true), view, row, row == this.SelectedRow);
}
return view;
}
/// <summary>
/// テーブル列の値設定用デリゲート
/// </summary>
/// <param name="rowView">設定先の行コントロール</param>
/// <param name="obj">設定先セルのテキストコントロール</param>
/// <param name="row">何行目か</param>
/// <param name="isSelectRow">選択された行か</param>
public static void FuncSetColumn(NSTableRowView rowView, NSObject obj, nint row, bool isSelectRow)
{
// 値を設定したり、文字色変えたり
// 行全体の色を設定
// ここで色を設定しないとスクロールしたときに戻ってしまう
rowView.BackgroundColor = isSelectRow ? SelectColor : BaseColor;
if(特定の条件)
{
rowView.BackgroundColor = isSelectRow ? HitAndSelectColor : HitColor;
}
}
}
んで、テーブルを作るときに上のDelegateを登録しておきましょう。
面倒なので、ここでは「名前」の1列しかないテーブルと仮定します。
NSTableViewオブジェクト.AddColumn(new NSTableColumn("名前"));
var delg = new MyDelegate();
delg.TableColumnsDict.Add("名前", MyDelegate.FuncSetColumn);
NSTableViewオブジェクト.Delegate = delg;
ただ、Columnを設定する度に1行まるっと色を染めているのは、列が増えると効率が悪い気がするなぁ。
もっとうまい方法はありそう。
CoreGetRowViewとかでやった方がいいのかなぁー
他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。