私のプログラムはリリース後の状態ですので、ご容赦ください。
シナリオ
私のプログラムは、オフィス データ管理システム (車両メンテナンス指向) のさまざまな機能のさまざまなページの複数のレイアウトに基づいています。これらの機能の主要なカテゴリは、明らかにデータ入力です。さまざまな聴衆に合わせて、さまざまなスタイルを使用してきました。
要点を言えば、インターフェイスの 1 つには Excel スタイルのグリッドと、印刷/保存/リセット機能用の 3 つのボタンがあります。フォームの印刷には FastReports を使用しています。
グリッド列のカスタム クラスを開発して、その場でセルの代わりに事前定義されたコントロールのリストに対応できるようにしていますが、今のところ、必要なコントロールをコード内のセルの子にしました。
ページには 3 つのセクション (レイアウト) があります。
一番上のものは、すべてのページに固有の一種の目的 (追加/変更/部分追加) セレクターであり、必要のない場所では表示されない場合があります。
中央のものは、変更するフォームの受信番号、他のフォームに埋め込まれた情報などを受け取るためのコントロールです。ほとんどの場合、すべてではありませんが、すべてのページにあります。
最後の 1 つには、前述のようにグリッドと 3 つのボタンであるページのコンテンツがあります。
コード
これは、問題のあるページの 1 つを表示するためのコード スニペットです。すべてのデータ処理が完了し、サーバーが遷移を OK すると実行されます。
伝説
AState : ステート マシンの状態変数。表示されているページの現在の状態を示します。
AMode : ステート マシン状態列挙子。予約 (データ入力) など、アプリケーション全体のモードを示します。この問題が発生するために AState の遷移中にスキップされるため、これに関連するコードはスキップしました。
fMode : 上記と同じですが、目的のためのフォームのメイン フィールドです。
UI_CA_Controls1 : 予約モードの目的セレクター (コンボ リスト ボックス) を含むレイアウト。
EV_Mode : 便宜上の変数です。パーパス セレクタのアイテム インデックスを格納します。
UI_CA_Grid : UI_CA_Content に含まれるレイアウトと、それ自体に UI_CA_FieldGrid (TGrid) が含まれます。
fEditColumn : TEdit を持つグリッドの 2 番目の列。
fGridDataset : TStringList に関連付けられたグリッド。
///
procedure TUI.SetFormState ( AState : Byte; AMode : TMode = UIM_Unselected );
var
EV_Mode, I : Byte;
begin
// ---------------------------------------------------------------------------
fFormState := AState;
// The children of the grid cells
fCalEdit1.Parent := nil; // Calender Edits
fCalEdit2.Parent := nil;
fVehicleClass.Parent := nil; // Combo List Boxes
fEmployee1.Parent := nil;
fEmployee2.Parent := nil;
fEmployee3.Parent := nil;
fEmployee4.Parent := nil;
// ---------------------------------------------------------------------------
if AState = 0 then
begin
for I := 0 to 20 do
DPCM.fGridDataset.Strings [I] := ''; // The Grid Associated TStringList
UI_CA_ReceiptNo.ReadOnly := False;
UI_CA_ReceiptNo.Text := '';
end;
// ---------------------------------------------------------------------------
UI_CA_Content.BeginUpdate;
case fMode of
// Skipped unrelated modes
UIM_Booking :
begin
UI_CA_Controls1.Visible := True;
EV_Mode := UI_CA_EV_ModeSelect.ItemIndex;
// -----------------------------------------------------------------------
if fFormState = 0 then
begin
// Skipped handling of other EV_Mode values
if EV_Mode < 7 then
begin
UI_CA_ReceiptControl.Visible := True;
UI_CA_Content.Visible := False;
end;
end
// -----------------------------------------------------------------------
else if fFormState = 1 then // The problematic area
begin
if ( EV_Mode = 3 ) or ( EV_Mode = 4 ) then
begin
UI_CA_FieldGrid.RowCount := 6;
UI_CA_Grid.Height := 160;
fCalEdit1.Parent := fEditColumn.CellControlByRow ( 0 );
fCalEdit1.Date := Date;
fCalEdit2.Parent := nil;
fVehicleClass.Parent := fEditColumn.CellControlByRow ( 2 );
fVehicleClass.ItemIndex := 0;
end;
UI_CA_Content.Visible := True;
end;
end;
// -------------------------------------------------------------------------
end;
// ---------------------------------------------------------------------------
// Workaround 1
if UI_CA_Content.Visible then
begin
UI_CA_FieldGrid.UpdateColumns;
UI_CA_Content.EndUpdate;
UI_CA_FieldGrid.SetFocus;
UI_CA_C2_Reset.SetFocus;
UI_CA_C2_Print.SetFocus;
UI_CA_C2_Save.SetFocus;
UI_CA_FieldGrid.SetFocus;
end
else UI_CA_Content.EndUpdate;
end;
問題
問題は、領収書セクションが表示されるたびに、コンテンツ セクションがその場で表示されないことです。動作は、それらの子コントロールと 3 つのボタンが表示されるはずの場所にマウスを置くと表示されますが、クリックするとグリッドが表示されるというものです。
この問題は、UI コードを変更することなく自然に発生し、3 日間私を困惑させました。私は、ネットワーク側 (個別のデータ モジュール) でのプロトコルとデータ処理の最適化のみを行いました。
順序
ユーザーは、すでに予約されている車両のデータを変更したいと考えています。
ユーザーは予約受付番号を入力します。( AState = 0、AMode = UIM_Booking )
クライアント クエリはサーバーであり、サーバーは完全なデータセット (存在する場合) を返します。
クライアントはデータを取得し、それをグリッドに関連付けられた TStringlist および子フィールドの文字列にコピーします。
クライアントは、データと 3 つのボタンを含むグリッドを表示しません。( AState = 1、AMode = UIM_Booking )
今まで何を試してきた
BeginUpdate/EndUpdate を使用すると、アライメント アーティファクトが悪化しました。
グリッドとボタンで SetFocus を使用した結果、一部がランダムに表示され、場合によっては完全に表示されましたが、毎回ではありませんでした。
Application.ProcessMessages を変更せずに使用するのではなく、UI スレッドがスタックして戻らないことがありました。別のスレッドで使用し、変更なしで毎秒呼び出しました。
さらに多くの問題があるメソッドに別のスレッドを使用しました。
古い作業コードを変更せずに追跡して復元しました (本当に腹が立ちました)。
更新 1: グリッドを非表示にしてからコードの最後に表示しようとしました。グリッドの一部のセルがランダムに表示されるようになりました。
回避策 1
- グリッドとボタンは、それぞれに対して SetFocus メソッドが呼び出されたときに表示できます。
- ボタンの呼び出しの順序は不安定です。最初にリセットを呼び出してから、印刷して SetFocus メソッドを保存する必要があったように、それ以外の場合は、そのうちの 1 つだけが表示されました。
- コントロールのサイズ変更を示す一瞬の再調整の不具合がありますが、それは無視できると思います。
回避策 2
- 即時ではなく、キューに入れられた再描画を行います。警告はありませんが、結局のところ、すべての再描画の間に遅延があるという問題があります。リンク: https://stackoverflow.com/a/8424750/1388291
ですから、何か提案があれば、本当に感謝しています。