6

私のアプリケーションには、データベースにいくつかの画像をロードする機能を備えたメインフォームがあります。画像の読み込み中に、進行状況インジケーター (bsNone 境界線スタイル) を使用してフォームを表示したいと考えています。

しかし、ShowModalでフォームを表示すると、メインフォームの実行が止まってしまうので、それができません。

Show を呼び出すと、ユーザーは他のすべてのフォーム コンポーネントにアクセスできますが、写真が完全に読み込まれていない間は危険です。

ロードが完了していない間、メインフォームのすべてを無効にする方法を見つける必要があります。

どうすればそれが可能か、私にアドバイスしてください。

4

5 に答える 5

6

まず、あなたの質問に対する直接的な答えです。

メインフォームのすべてを無効にする方法が必要です。

メイン フォームに関連付けられたウィンドウを無効にするには、 に設定MainForm.Enabledします。False再度有効にするには、True代わりに設定します。


ただし、根本的な問題は、GUI スレッドで実行時間の長いタスクを実行していることです。それは常に悪い考えであり、解決策は、これらの長時間実行されるタスクを別のスレッドで実行することです。

長時間実行されるタスクを別のスレッドに移動すると、それShowModalがまさに進行状況フォームを表示するために必要なものであることがわかります。

于 2013-07-06T16:12:00.557 に答える
2

他の回答で説明したように、長時間実行されるタスクを GUI スレッド以外のスレッドに配置することが理想的なソリューションです。GUI スレッドは、メッセージ キューを常にタイムリーに処理できるように、実行時間の短いタスクを処理する必要があります。

ただし、実行時間の長いタスクが GUI スレッドで実行されることを前提とするコードが既にある場合は、より適切なアプローチを採用して、リファクタリングをスレッド化されたコードに延期することをお勧めします。その場合、私の見解ではShowModal、進捗フォームを表示するために使用する方が良いでしょう。

しかし、それを機能させるには、ShowModal呼び出し内で実行時間の長いタスクを実行できるようにする必要があります。次のように実行できます。

  1. を呼び出す前にShowModal、タスクをフォームに渡します。たとえばTProc、進捗フォームのコンストラクタに a を渡します。
  2. 進捗フォームのActivateメソッドをオーバーライドします。ShowModalこれは、関数がモーダル メッセージ ループを開始する直前に実行されます。の実装ではActivate、フォームにメッセージを投稿します。
  3. フォームがそのメッセージを処理するとき、コンストラクターに渡されたタスクを呼び出します。

ProcessMessagesメインの GUI スレッド メッセージ キューを維持するために、長時間実行するタスクを呼び出す必要があることは明らかです。明らかに、あなたはすでにそれを行っているに違いありません。

于 2013-07-07T21:01:27.723 に答える
1

DisableTaskWindowsEnableTaskWindows関数を使用することができ ます。

親フォームにsimple を使用する場合ParentForm.Enabled := Falseでも、他のすべてのフォームにアクセスできます (メイン フォームが と異なる場合) ParentForm。明らかにまだ危険です。

ここに短いサンプルがあります:

interface

uses
  Vcl.Forms, Winapi.Windows, ...;

type
  TPleaseWait = class(TObject)
  private
    fWindowList: TTaskWindowList;
    fActiveWindow: HWND;
    fDialog: TPleaseWaitForm;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

constructor TPleaseWait.Create;
begin
  // Disable all displayed windows
  fWindowList := DisableTaskWindows(0);

  // Save the last active window
  fActiveWindow := GetActiveWindow;

  fDialog := TPleaseWaitForm.Create(nil);
  fDialog.Show;
end;

destructor TPleaseWait.Destroy;
const
  INVALID_HANDLE = 0;
begin
  fDialog.Close;
  fDialog.Free;

  // All windows are enabled now
  EnableTaskWindows(fWindowList);

  // That helps by enabling the last one form
  if (fActiveWindow <> INVALID_HANDLE) and IsWindow(fActiveWindow) then
    SetActiveWindow(fActiveWindow);
  inherited;
end;

end.
于 2015-11-04T15:17:53.803 に答える