FMX TStringGrid で列の固定

解決


yTake  2021-06-13 02:39:40  No: 149710  IP: [192.*.*.*]

いつもお世話になります。yTakeです。

今回はFMXでTStringGridの列固定の方法についてです。
列を複数用意した場合、コンポーネントの幅より列数の表示幅の方が大きい場合、横スクロールが可能になって、
全ての列内容を確認できますが、最左列をヘッダーの様にその行の項目名などに使用していた場合、横スクロールで最左列もスクロールされるので、その行に項目名を確認する為にスクロールバックして最左列を表示し直さないと確認できません。
最左列(若しくは左から指定列までの複数列)を横スクロールしない様にしたいのですが、
TStringColumnに"Locked"と言うプロパティがありましたが、横スクロールとは関係ない様です。
ヘルプを調べた限りでは横スクロールのOn/Offに関するプロパティは見つからない様です。
本掲示板でも投稿はなかった様です。

何かこれを実現する方法はあるでしょうか?
関連するサイトがある様であれば、その情報でも構いません。

よろしくお願いします。


Windows 10 Pro + DELPHI XE6
です。

編集 削除
take  2021-06-14 01:26:33  No: 149712  IP: [192.*.*.*]

FMX の TStringGrid における 固定行、固定列
http://afsoft.jp/program/delxe3/p12_169.html

この辺どうですか

編集 削除
yTake  2021-06-14 11:08:34  No: 149717  IP: [192.*.*.*]

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

試してみましたが、列は固定されませんでした。

StringGrid1.Columns[ 0 ].ReadOnly :=  True;
StringGrid1.Columns[ 0 ].Enabled  :=  False;
或いは
StringColumn1.ReadOnly  :=  True;
StringColumn1.Enabled  := False;
で、試してみました。

この列のセルへの入力は不可になっていますので、Enabled :=Falseは効いている様です。
やり方が間違っているでしょうか?

ただ、この参照先でも実際に列の固定を確認されてる分けではなさそうです。



色々調べて、参考になる動画を見つけました。
StringGridを2つ使って実現する様です。両者を並べて配置し、左側には固定列のみを表示させ、右側には全てを表示します。左側のスクロール・バーは非表示になっています。
これで、両者の縦スクロールを同期させれば、OKの様です。
スクロールするのは右側だけなので、横スクロールさせても左側のStringGridでは常に固定列が見えています。
両者を同期させているので、縦スクロールさせても左右のStringGridで行は一致しています。

ただ、方向性は確認出来ましたが、実現の仕方が分かりません。
画像の解像度も悪く、今市、正確に理解できていません。
動画の17分過ぎ頃でしょうか?
procedure  TStringGridonSelectCell
のところで同期させている様に思いますが、コーディングまでわかっていません。
繰り返し確認し解明したいと思います。

動画サイトは次の通りです。
https://www.youtube.com/watch?v=swnNz4VCYVA

編集 削除
KONNOYA  2021-06-15 03:07:07  No: 149720  IP: [192.*.*.*]

列幅を固定したいだけなら、
TStringGird の StringColumn の OnResizedイベントハンドラに
StringColumn1.Width := 100;
とか記述すれば、その列が固定幅になるかと思います。

編集 削除
yTake  2021-06-15 08:00:37  No: 149721  IP: [192.*.*.*]

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

私の説明が分かり難かった様ですみません。
固定したいのは列幅ではなくて、スクロールです。

vclのTStringGridでは、FixedCols, FixedRowsと言うプロパティがあって、そこで設定した行或いは列数だけヘッダーとして固定されます。そして、TStringGridの縦横スクロールバーでスクロールしてもその行或いは列はスクロールされません。
これをFMXのTStringGridで実現したいと考えています。

編集 削除
KONNOYA  2021-06-16 03:05:17  No: 149724  IP: [192.*.*.*]

> 列幅を固定したいだけなら、
> TStringGird の StringColumn の OnResizedイベントハンドラに
> StringColumn1.Width := 100;
> とか記述すれば、その列が固定幅になるかと思います。

小細工をろうしなくても、
TStringGrid.Options.Colimnプロパティで列幅は固定できますね。
但し、全ての列が固定化されてしまう為、特定の列だけ固定化させたい時は上記の例で(^^;
とにかく質問の意図を正しく汲み取っておらず、失礼しました(汗


> 色々調べて、参考になる動画を見つけました。
> StringGridを2つ使って実現する様です。両者を並べて配置し、左側には固定列のみを表示させ、右側には全てを表示します。左側のスクロール・バーは非表示になっています。
> これで、両者の縦スクロールを同期させれば、OKの様です。

FMXのTStringGirdには、FixedCols, FixedRowsプロパティに相当する機能が無い様なので、
ちょっと変則ですけど、2つのTStringGirdを並べるというアイデアは私も思い付いていました。
但し、2つのTStringGirdのスクロール位置を同期させねばならない。

下記のコードではどうでしょうか。
コンポーネントの配置的には、
まず TLayout を置いて全体の矩形の大きさを決定し、
次にタイトル部分の TStringGrid を Align=Left で配置、
最後にデータ部分の TStringGri dを Align=Client で配置する様な事をやっています。

【 FMXコード 】
uses
  …, FMX.BehaviorManager;

type
  TForm1 = class( TForm )
    Layout1 : TLayout;
    StringGrid1 : TStringGrid;       // 左 ( タイトル側 )
    StringGrid2 : TStringGrid;       // 右 ( データ側 )
    procedure FormCreate( Sender : TObject );
    procedure ViewportPositionChange1( Sender : TObject; const OldPosition, NewPosition : TPointF; const Changed : Boolean );
    procedure ViewportPositionChange2( Sender : TObject; const OldPosition, NewPosition : TPointF; const Changed : Boolean );
  private
  public
  end;

var
  Form1: TForm1;

implementation

procedure TForm1.FormCreate( Sender : TObject );
begin
  // 左 ( タイトル側 )のスクロールバーを消去
  StringGrid1.ShowScrollBars  := FALSE;

  // スクロール慣性移動を禁止
  StringGrid1.ScrollAnimation := TBehaviorBoolean.False;
  StringGrid2.ScrollAnimation := TBehaviorBoolean.False;

  // スクロールバウンスを禁止
  StringGrid1.Bounces         := TBehaviorBoolean.False;
  StringGrid2.Bounces         := TBehaviorBoolean.False;

  // スクロール位置が変更になった時のメソッド割り当て
  StringGrid1.OnViewportPositionChange := ViewportPositionChange1;
  StringGrid2.OnViewportPositionChange := ViewportPositionChange2;
end;

procedure TForm1.ViewportPositionChange1( Sender : TObject; const OldPosition, NewPosition : TPointF; const Changed : Boolean );
begin
  // 左TStringGridを動かしたら右TStringGridを動かす
  StringGrid2.ViewportPosition := StringGrid1.ViewportPosition;
end;

procedure TForm1.ViewportPositionChange2( Sender : TObject; const OldPosition, NewPosition : TPointF; const Changed : Boolean );
begin
  // 右TStringGridを動かしたら左TStringGridを動かす
  StringGrid1.ViewportPosition := StringGrid2.ViewportPosition;
end;

スクロール慣性移動やバウンスの有無はお好みで。
左 ( タイトル側 )のセルの色などは StyleBook で変えると良いと思います。

編集 削除
yTake  2021-06-18 01:15:45  No: 149732  IP: [192.*.*.*]

KONNOYAさん

ありがとうございます。
試してみましたら、あっさりヘッダー列が固定されてスクロール出来ました。

StringGridを二つ配置して実現するなど、思いもよりませんでした。柔軟性ですね。

少し教えて下さい。
ViewportPositionと言うプロパティは、オブジェクト・インスペクタでリストされていません。ヘルプでも出てこない様です。どの様に知る事ができたのでしょう?
また、ViewportPositionChangeと言うメソッドは、元々ないと思います。マウスによるスクロールバー位置変更を検知した場合の処理と思います。
マウスによるスクロールバー・イベントであると言う事はどこで知るのでしょう?変数のOldPosition, NewPositionやChanged はその手続き処理に中で使用されていない為、定義してあること自体必要なのでしょうか?

プログラムの指針は理解できるのですが、具体的な処理内容が良く分かっていません。

基本的な事かも知れませんが、ご教示頂けたら幸いです。参考のサイトだけでも結構です。

編集 削除
KONNOYA  2021-06-18 03:09:05  No: 149733  IP: [192.*.*.*]

TStringGirdのオブジェクトインスペクタには、
ViewportPositionという項目は表示されていませんが、
コード中に「StringGird1」と書き、「.」を打てば、
プロパティやメソッド、イベントハンドラが列挙されて表示されます。
そういうので存在を知ります。

また「StringGrid1.ViewportPosition」と書き「ViewportPosition」の文字列を
CTRLキーを押しながらマウスクリックすると、ViewportPosition が定義されているコードに飛びます。
※ TStringGrid なら FMX.ScrollBoxユニット

次にその ViewportPosition が持つ機能を知る為、検索サイトで検索。
ヒットした記事を読み、理解します。

昔みたいにTips本があれば良いのですが、
本に出来ない位にプロパティやメソッドが肥大化していますので、
このようにして調べたりします。

あとは知った物で軽く遊んでみる事が重要かも。

編集 削除
KONNOYA  2021-06-18 03:34:00  No: 149734  IP: [192.*.*.*]

補足ですが、TStringGird.ViewportPositionはTPointF型なので、
そのまま代入してしまうと、X座標もY座標も動いてしまいます。
今回は左 ( タイトル側 )のTStringGridが1列だと思い込んでしまっていたので、
Y座標だけ変える正しい方法は、

StringGrid2.ViewportPosition := TPointF.Create( 0, StringGrid1.ViewportPosition.Y );

の様に書いた方が良いのかも。

編集 削除
yTake  2021-06-18 07:21:47  No: 149735  IP: [192.*.*.*]

KONNOTAさん
正しいY座標のみスクロールさせる方法をありがとうございます。
奥が深いですね。

ご推察の通り、固定したいヘッダ列は1つでした。


また、変数名の件ですが、そう言えば、コンポーネントやクラスなどでそのメンバをアクセスする際に、"."を入力して候補がポップアップするコンプリージョン機能をふんだんに使っていました。
コントロールキーを押しながらコンポーネントの変数名の文字列をクリックするとその定義ヵ所へ飛ぶ事、知りませんでした。いつもヘルプから探していました。

何に付けても、”遊び”が重要ですね。

ありがとうございました。

編集 削除