TabContorolのTab毎に背景色を変えたい(FMX)

解決


yTake  2024-03-28 12:19:00  No: 151417

yTakeといいます。
TabControlに3つTabItemを設定し、各々のTabで背景色を変えたいと思います。

TabItemに色のプロパティは見当たらない様ですので、
各TabItemにTPanelを配置して、そのパネルを塗りつぶす事を考えましたが、塗りつぶし自体は出来たのですが、問題があります。

各パネル上にはTPaintBoxやTCharなどが配置してあるのですが、パネルの塗りつぶしが最前面に来ていて、PaintBoxやChartが隠れてしまっています。
コンポーネントの配置上は、TPanelが背面、チャート等は前面に置いています。

ボタンをクリックするとPaintBoxへ図形を描画する様にして、描画後そのPaintBoxを”BringToFron”してみましたが、変わりません。

procedure TForm1.Panel1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
begin
    case pa1 of
        0:  ;
        1:
        begin
            Canvas.ClearRect( aRect, TAlphaColors.Red );
        end;
    end;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
    aRect : TRectF;
    pt1, pt2  : TPointF;
    aBr   : TStrokeBrush;
begin
    aRect :=  TRectF.Create( 0, 0, PaintBox1.Width, PaintBox1.Height );
    aBr   :=  TStrokeBrush.Create( TBrushKind.Solid, TAlphaColors.Darkmagenta );

    pt1 :=  TPointF.Create(  50,  50 );
    pt2 :=  TPointF.Create( 250, 250 );

    case pb1 of
        0:  ;
        1:
        begin
            Canvas.ClearRect( aRect, TAlphaColors.Cornsilk );
            Canvas.DrawLine( pt1, pt2, 1, aBr );
        end;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin

    pb1 :=  1 ;
    PaintBox1.Repaint();
    PaintBox1.BringToFront();
end;

pa1とpb1はグローバルで定義してあって、pa1はForm1のCreateで’1’に設定しています。

どの様に解決出来るでしょうか?

当方、DELPHI XE6 FMX+Windows10です。


vram  2024-03-28 13:00:17  No: 151418

うーん、なんか余計な情報ばかりで肝心な情報が抜けてて誰もアドバイス出来ないような

TabControlに3つのTab
その3つのタブを使って何を切り替えて表示したいのですか?

TChart(teechart)をパネルの上に置いて背景色を変えたい
と読めますが
TChart(teechart)の背景色を変えるのはダメなのか?
パネルの色を変えるのはダメなのか?

そもそも見出しが「TabContorol」で始まるけどこれってTabContorolの問題じゃないような?
パネルにTChart(teechart)置いたときだけ発生しますか?

TabContorolのTab毎に背景色を変えたい
って質問が来たら
各タブ(マウスをクリックして切り替えるところ)の色の変えかたの質問のように読めてしまいます


yTake  2024-03-28 13:20:01  No: 151419

vramさん、ありがとうございます。

質問の趣旨が分かり難かった様ですみません。
TabControlのTab部分(マウスをクリックして切り替えるところ)の背景色ではありません。
Tabで切り替わった描画領域の背景色を変えたいと言う趣旨です。

パネルにチャートやPaintBoxを配置しています。チャートの背景色を変えるのでは違います。パネルの色を変える事でOKですが、チャートやPaintBoxがパネルの色で隠れてしまいます。

これで趣旨は伝わるでしょうか?
また、不足の情報などあるでしょうか?


vram  2024-03-28 13:59:23  No: 151420

チャートはまあグラフを表示するのに使っているのだと思いますが
PaintBoxは何に使っていますか?

もしかしてチャートに何かを示す線を表示したくて
 Canvas.DrawLine( pt1, pt2, 1, aBr );
としている感じですか?

> チャートやPaintBoxがパネルの色で隠れてしまいます。

配置がこうなっているとか?

TabControl
|
+- Panel
+- PaintBox1
+- TChart

パネルが親なら上にはこないような

TabControl
|
+- Panel
  |
  +- PaintBox1
  +- TChart

あとPaintBoxは少々クセがありますが使用経験はありますか?


yTake  2024-03-28 14:36:55  No: 151421

PaintBoxはチャートの描画とは関係なく、Bitmap画像を描画する為に配置しています。
その画像に合わせて線を引いたりします。

ツリー構造でも、Panelの子としてチャートとPaintBoxが存在しています。
チャートとPaintBoxは並列です。

TabControl1
  +TabItem1
      +Panel1
          +Char1
          +PaintBox1
  +TabItem2
      +Panel2
          +Char2
          +PaintBox2
  +TabItem3
      +Panel3
          +Char3
          +PaintBox3

の様になっています。

PaintBoxは使った事があります。
自動で再描画されないので、自分でRepaintを呼ぶなど強制的に再描画させる必要がある点に注意でしょうか。


AAAAA  2024-03-28 21:06:48  No: 151422

Panel1Paintで塗りつぶすと 上にあるコンポーネントまで 塗りつぶされて、 repaint しても再描画されないね
なでの

  TAB_HEIGHT: Single;
  BRECT: TRECTF;

procedure TForm1.TabControl1Paint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
var
    I: Integer;
    W: Single;
begin
    W := 0;
    for I:=0 to TabControl1.TabCount -1 do
    begin
      W := W + TabControl1.Tabs[I].WIdth;
    end;

    BRECT      := ARECT;
    BRECT.Left := -W;
    BRECT.Top  := TAB_HEIGHT;
end;

procedure TForm1.TabItem1Paint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
begin
    TAB_HEIGHT := ARECT.Height;
    TabControl1.Canvas.BeginScene;
    TabControl1.Canvas.ClearRect(BRECT,$B2006ACC);
    TabControl1.Canvas.EndScene;
end;

procedure TForm1.TabItem2Paint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
begin
    TAB_HEIGHT := ARECT.Height;

    TabControl1.Canvas.BeginScene;
    TabControl1.Canvas.ClearRect(BRECT,$B200CC6A);
    TabControl1.Canvas.EndScene;
end;

procedure TForm1.TabItem3Paint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
begin
    TAB_HEIGHT := ARECT.Height;

    TabControl1.Canvas.BeginScene;
    TabControl1.Canvas.ClearRect(BRECT,$B2CC006A);
    TabControl1.Canvas.EndScene;

end;


yTake  2024-03-29 08:37:32  No: 151423

AAAAAさん、ありがとうございます。

私の使い方の問題ではなく、TPanelの"on Paint"では上にあるコンポーネントまで上書きされてしまうのは仕様なのでしょうか?

TabItemの"on Paint"で試してみましたが、TPanelにonPaintした場合の様に上のコンポーネントまで上書きされてしまっています。
使い方に問題があるでしょうか?
先ずは、ご提示のサンプルをそのまま試したつもりですが、、、

TPamelにしろTTabItemにしろ色を変える前のオリジナルの状態では、上に置いたコンポーネントは前面に存在し、見えています。
色を変える事で隠れてしまいます。"Bring to Front"でも前に来ません。

別案として、元々の背景色を変える事は出来ないでしょうか?
例えば、StyleBookを採用すると背景色が選択できます。(ただ、一部コンポーネントで拝啓色を変更したい場合に同じ問題に直面します)

何か妙案があるでしょうか?


KONNOYA  2024-03-29 10:08:29  No: 151424

試していませんが、そのPanelのOnPaintイベントで、
自身の描画の後で、子コンポーネントの Repaintメソッドを呼び出してやるとか?

procedure TForm1.Panel1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
var
  ControlNo: Integer;
begin
  // 何らかの自身の描画
  ・・・

  // 子コンポーネントループ
  for ControlNo := 0 to Panel1.ControlsCount - 1 do
  begin
    Panel1.Controls[ControlNo].Repaint;
  end;
end;


yTake  2024-03-29 13:52:04  No: 151425

KONNOYAさん、ありがとうございます。

子コンポーネントのRepaintをループで回してみましたが、変わりませんでした。

ControlsCountも値が、実際に載っているコンポーネントの数より1大きいのですが、なぜでしょう。
例えば、2つしか載せてないのにControlsCount=3となっていて、3回廻しても特にエラーにはなっていません。
不思議です。


KONNOYA  2024-03-29 14:44:09  No: 151426

確認ですが、TPanel = TabControl の背景という認識で宜しいでしょうか?
もしそうであるならば、TabControl のスタイルを追加して、その背景色をコードから変えるやり方です。

・TabControlを右クリックでポップアップメニューを表示させ、「カスタムスタイルの編集」を選択
・スタイルデザイナの編集画面に移行するので、
  追加されている tabcontrol1style 直下の styleobject1 に、ツールパレットから TRectangle コンポーネントをドロップする
  tabcontrol1style
    +styleobject1 ← ここにドロップ
      +rectangle1style ← 追加された物
・追加された rectangle1style の Align プロパティを Client にする
・スタイルデザイナの「適用して閉じる」ボタンを押す
・下記のサンプルコードを実行

uses
  ・・・
  System.UIConsts, FMX.Styles.Objects, FMX.Objects;

implementation

procedure TForm1.TabControl1Change(Sender: TObject);
var
  Back : TRectangle;
begin
  // 操作するスタイルを取得
  Back := TabControl1.FindStyleResource('rectangle1style') as TRectangle;
  if Assigned(Back) then
  begin
    // タブ番号?
    case TabControl1.TabIndex of
    0 : Back.Fill.Color := claRed;
    1 : Back.Fill.Color := claGreen;
    2 : Back.Fill.Color := claBlue;
    end;
  end;
end;

procedure TForm1.TabControl1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
begin
  // 最初の更新の為
  TabControl1Change(TabControl1);
end;

TabControl の背景色を変えるので、TPanel は必要ありません。


mam  2024-03-29 15:50:53  No: 151427

あ、KONNOYA様と被ってしまったかもです。

まず、フォームにTTabControlを配置して、タブを3つ入れます。
FormのOnCreateでTabItem1~3のそれぞれにTRectを入れてしまい、もともと配置してあるコンポーネントは各TRectに配置してしまう方法です。
DelphiXE10.2 FMXで動かしたのですが、DELPHI XE6で動作するかどうかは不明です。
外していたらすいません。

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.TabControl;

type
  TForm1 = class(TForm)
    TabControl1: TTabControl;
    TabItem1: TTabItem;
    TabItem2: TTabItem;
    TabItem3: TTabItem;
    procedure FormCreate(Sender: TObject);
  private
    { private 宣言 }
    procedure TabItemPaint(Sender: TObject; Canvas: TCanvas;
      const ARect: TRectF);
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

//各タブの色
const TabCol:array[0..2] of TAlphaColor=($FFFF0000,$FF00FF00,$FF0000FF);

implementation

{$R *.fmx}

uses FMX.Objects;

procedure TForm1.FormCreate(Sender: TObject);
var i,j,k:Integer;
    r:TRectAngle;
begin
  for i := 0 to TabControl1.TabCount-1 do
  begin
    TabControl1.Tabs[i].OnPaint:=TabItemPaint;

    r:=TRectangle.Create(self);
    r.Fill.Color:=TabCol[i];
    r.Stroke.Color:=TabCol[i];
    r.Parent:=TabControl1.Tabs[i];
    r.Align:=TAlignLayout.Client;
    for j := TabControl1.Tabs[i].Children[1].ChildrenCount-1 downto 0 do
    begin
      if not(TabControl1.Tabs[i].Children[1].Children[j] is TRectangle) then
        TabControl1.Tabs[i].children[1].Children[j].Parent:=r;
    end;
  end;

end;

procedure TForm1.TabItemPaint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
begin
  Canvas.BeginScene();
  Canvas.Fill.Color:=TabCol[TTabItem(Sender).Index];
  Canvas.FillRect(ARect,0,0,[],1);
  Canvas.Fill.Color:=$FF000000;
  Canvas.FillText(ARect,TTabItem(Sender).Text,true,1,[],TTextAlign.Center,TTextAlign.Center);
  Canvas.EndScene;
end;

end.


yTake  2024-03-29 18:27:27  No: 151428

KONNOYAさん、mamさん
ありがとうございます。

”FormのOnCreateでTabItem1~3のそれぞれにTRectを入れてしまい、もともと配置してあるコンポーネントは各TRectに配置してしまう方法”
で、背景色として塗りつぶしが出来ました。上のコンポーネントは全て見えています。
TPanelを使わずにTRectAngleを用いたのが良かったと言う事でしょうか?
イマイチ、良く分かっていません。

StyleBookの方は、Tabを切り替えても背景色が変わりません。
ご教授によりますと、
    +styleobject1 ← ここにドロップ
と言う事ですが、
  tabcontrol1style
の下には、
      +background:TRectangle
があるだけで、
    +styleobject1
は見つかりません。
なので、
  tabcontrol1style
に、TRectAngleコンポーネントをドロップしてみました。
従って、tabcontrol1style下に
      +background:TRectangle
      +rectangle1:TRectangle
の様に並列に配置されています。
コーディングはご教授の通りに記述しました。
正常に動作しないのは、
    +styleobject1
が、存在しない為、でしょうか?


AAAAA  2024-03-29 19:52:56  No: 151429

エラーで書き込みできない テスト


AAAAA  2024-03-29 19:54:07  No: 151430

エラーが発生しました。
お探しのページは現在利用できません。
サーバーが停止しているか、ネットワークが混みあっている可能性があります。

//DELPHI 10/XE6 動作版

var
  TAB_HEIGHT: Single;
  BRECT: TRECTF;

procedure TForm1.XXXXX(ACOLOR: TAlphaColor);
var
    I: Integer;
    W: Single;
begin

    W := 0;
    for I:=0 to TabControl1.TabCount -1 do
    begin
      W := W + TabControl1.Tabs[I].Width;
    end;

    BRECT.Left := -W;
    BRECT.Top  := TAB_HEIGHT;

    TabControl1.Canvas.BeginScene;
    TabControl1.Canvas.ClearRect(BRECT,ACOLOR);
    TabControl1.Canvas.EndScene;

    for I := 0 to Form1.ComponentCount -1 do
    begin
      try
        if Form1.Components[I] is TControl then
        begin
          if TControl(Form1.Components[I]).Parent.ClassName = 'TTabItemContent' then
          begin
            TControl(Form1.Components[I]).Repaint;
          end;
        end;
      except
      end;
    end;

end;

procedure TForm1.TabControl1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
begin
    BRECT := ARECT;
end;

procedure TForm1.TabItem1Painting(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
begin
    TAB_HEIGHT := ARECT.Height;
    XXXXX($B2006ACC);
end;

procedure TForm1.TabItem2Painting(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
begin
     TAB_HEIGHT := ARECT.Height;
     XXXXX($B200CC6A);
end;

procedure TForm1.TabItem3324324324324Painting(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
begin
    TAB_HEIGHT := ARECT.Height;
    XXXXX($B2CC6A00);
end;


yTake  2024-03-31 17:14:18  No: 151431

AAAAAさん、ありがとうございます。
一部、文字化けてしまっていましたが、背景色の変更が出来ました。

TPanelを使用しないで背景色を変える手段が分かりました。

皆さん、ありがとうございました。


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加