TDBCtrlGridの背景色を個別に変える@Delphi

ちょっと、思いつきで頼まれた仕事のサンプルを作成中。
見積もり以前の段階なのに、ここまで作りこんでしまうのも、どうかと思うが。

今回、TDBCtrlGridに個別の配色をしたく、試行錯誤した。

***

まず、OnPanelPaintのイベント。

>> http://delphiexamples.com/databases/colorctgrid.html

にあるように、

if Odd(index) then? begin
  DBCtrlGrd1.Color:=clSkyBlue;
end else begin
   DBCtrlGrd1.Color:=clCream;

end;

※奇数、偶数で、配色を変えるコード

やりたいことは、レコードに保存した色で、パネル毎の背景色を変えたいので、
ちょっと、これでは物足りず。

Canvasに直接描画するも、そのパネルがどのデータを持っているか、取り出せないので、
アクティブ・レコードの時にしか、色データを取り出せず・・・

 

数時間、WEBを探し回るが、そんなサンプルに出会えず、
やっと見つけた、これ↓

>>?https://github.com/Evil-Spirit/Nutmeg/blob/master/Library/AlphaControls/AlphaDB/acDBCtrlGrid.pas

DB系コンポーネントは、どれもそうだけど、
DataLinkというプロパティーで、データを取得している。
特に、TDBGridや、TDBCtrlGridは、アクティブ・レコード以外のデータを
参照する必要があるため、内部的にDataLinkを参照しているのだけど、

これが、

private 宣言なので、外部のユニットからは、参照出来ないわけで。

上記は、コンポーネントなんだけど、
DataLink プロパティーの値を引いてくることが出来る、簡単なコードがあった!!

Result := TDBCtrlGrid_(Self).FDataLink;

TDBCtrlGrid_ というのは、TDBCtrlGridから派生させたもので、

  TDBCtrlGrid_ = class(TWinControl)
  private
    FDataLink: TDBCtrlGridLink;
  end;

たった、これだけのもの。

 

privateは、同一ファイル上でしか、アクセスできないけど、
プロジェクト内のフォーム(TForm1)上で、TDBCtrlGrid_を
派生させて、キャストすれば、同一ファイル上になるので、
アクセスが出来るようになるという、方法。

 

DataLinkをpublic宣言に置き換えた、コンポーネントを作れば可能なんだけど、
それを、キャストでやってしまうというのは、

 

目からウロコでした!!

 

このやり方で、

procedure DBCtrlGridPaintPanel(DBCtrlGrid: TDBCtrlGrid; Index: Integer);
var
  DL: TDataLink;
  SaveActive: Integer;
begin
  // paint color //
  with DBCtrlGrid do
    if Index <> PanelIndex then
    begin
      DL := TDBCtrlGrid_(DBCtrlGrid).FDataLink;

      if not VarIsNull(DL.DataSet.FieldValues['color']) then begin
        Color := DL.DataSet.FieldValues['color'];

      end else
        Color := DBCtrlGrid_Color;

    end;

※DataLink上のデータは、ActiveRecord = Index(イベントの変数)で、取得できる

課題として、

大量の描画イベントが発生してしまうため、その対応を検討中。


していましたが、

完成しました!!

 

TDBCtrlGridの背景色を個別に変える@Delphi
左下の薄い青が、選択した項目で、 右上はデータと連動して、背景色を変わってます。

 

試行錯誤の過程は、あえてコメントアウトして、残していますが、
コメント行は、全消しでOK。

procedure TfMain.DBCtrlGridPaintPanel(DBCtrlGrid: TDBCtrlGrid; Index: Integer);
var
  DL: TDataLink;
  SaveActive: Integer;
begin
  // paint color //
  with DBCtrlGrid do
    if Index <> PanelIndex then begin
      DL := TDBCtrlGrid_(DBCtrlGrid).FDataLink;

//      SaveActive := DL.ActiveRecord;
//      DL.ActiveRecord := Index;
      try
//        DebugPrint(DL.DataSet.FieldValues['color']);

        if not VarIsNull(DL.DataSet.FieldValues['color']) then begin
          // http://delphimaster.net/view/3-51640
//          Canvas.Brush.Color := DL.DataSet.FieldValues['color'];
//          Canvas.FillRect(Rect(0, 0, PanelHeight, PanelWidth));

          Panel1.Color := DL.DataSet.FieldValues['color'];

        end else
          Panel1.Color := DBCtrlGrid_Color;

      finally
//        DL.ActiveRecord := SaveActive;

      end;
    end else
      Panel1.Color := DBCtrlGrid.SelectedColor;

 end;

Panel1というのは、TDBCtrlGrid上に置いた、
何の変哲もないTPanelですが、ちゃんと理由ははあります。

TDBCtrlGrid上には、TDBEditを幾つか置いていますが、
編集モードでない時は、カーソル表示させたくないので、
Enabled := false としたところ、文字が灰色になってしまうため、
(ReadOnlyだと、カーソルは表示されてしまう)

Panelを置き、それをEnabled := falseにすることで、
色は変わらず、カーソルが表示されない様になります。

 

偶然の結果ですが、
Panel1というのは、TDBCtrlGrid上に置いたことが、重要でした!!

最初は、Canvasの背景を描画して、
その上に、透明のTDBEditを置けばいいだろうとやっていたんですが、うまく行かず、

直接、TDBCtrlGrid.Colorを書き換えると、再描画が無限に行われますが、
TPanelのColorを書き換えてみたところ、うまく行きました。

 

APIでゴリゴリやろうかとも思っていましたが、
結果が同じなら、コード自体はシンプルな方がいいものです。

苦労した分、能書きが長くなりましたが(笑

 

PS.

あと、TDBEditの背景が透明にできるコンポーネントもあると、楽ですね。

>> 背景透明化可能 拡張エディット&メモ

DB非対応のTEditなのですが、TEdit > TDBEditと置き換えてやればいい。
※詳しくは、コンポーネントの作り方を学習してね

とやっていたのですが、
編集画面を作っている時に、落ち度が・・・ = ちゃんと描画されない

ので、
オリジナルのTDBEditに戻して、Panel1同様に、

    DBEdit.Color   := Panel1.Color;

を、足してやると、背景色が同色のまま、処理されます。

 

TDBCtrlGridの背景色を個別に変える@Delphi