アプリケーションの特定のフォームは、モデルのグラフィカル ビューを表示します。ユーザーは、他の多くのものの中で、モデルの変換を開始できますが、これにはかなりの時間がかかります。この変換は、ユーザーの操作なしで進行する場合もあれば、頻繁なユーザー入力が必要な場合もあります。それが続く間、ユーザー入力が必要でない限り、UI を無効にする必要があります (進行状況ダイアログを表示するだけです)。
可能なアプローチ:
- 問題を無視して、変換コードをプロシージャに入れて呼び出すだけです。変換に時間がかかるがユーザー入力を必要としない場合、アプリがハングしているように見えるため、悪いです。
- コードにコールバックを散りばめます: これは目障りです。これらの呼び出しを変換コードに多数配置する必要があり、予測不能であり、適切な場所を見つけたことを確認できませんでした。
- コードに Application.ProcessMessages を追加します。コールバックと同じ問題です。さらに、ProcessMessages に関するすべての問題が発生します。
- スレッドを使用する: これにより、2. と 3. の「目障りで予測不可能な」部分から解放されます。ただし、ユーザー入力に必要な「マーシャリング」のために、多くの作業が必要です。Synchronize を呼び出し、必要なパラメーターを入力します。テーラーメイドのレコードなど。デバッグするのも悪夢であり、エラーが発生しやすくなります。
//編集: 現在の解決策はスレッドです。ただし、ユーザー入力のため、a ** は面倒です。また、多くのルーチンに多くの入力コードが存在する可能性があります。これは、スレッドが正しい解決策ではないと感じさせます。
恥ずかしい思いをして、私が作成した GUI と作業コードの不浄な組み合わせの概要を投稿します。
type
// Helper type to get the parameters into the Synchronize'd routine:
PGetSomeUserInputInfo = ^TGetSomeUserInputInfo;
TGetSomeUserInputInfo = record
FMyModelForm: TMyModelForm;
FModel: TMyModel;
// lots of in- and output parameters
FResult: Boolean;
end;
{ TMyThread }
function TMyThread.GetSomeUserInput(AMyModelForm: TMyModelForm;
AModel: TMyModel; (* the same parameters as in TGetSomeUserInputInfo *)): Boolean;
var
GSUII: TGetSomeUserInputInfo;
begin
GSUII.FMyModelForm := AMyModelForm;
GSUII.FModel := AModel;
// Set the input parameters in GSUII
FpCallbackParams := @GSUII; // FpCallbackParams is a Pointer field in TMyThread
Synchronize(DelegateGetSomeUserInput);
// Read the output parameters from GSUII
Result := GSUII.FResult;
end;
procedure TMyThread.DelegateGetSomeUserInput;
begin
with PGetSomeUserInputInfo(FpCallbackParams)^ do
FResult := FMyModelForm.DoGetSomeUserInput(FModel, (* the params go here *));
end;
{ TMyModelForm }
function TMyModelForm.DoGetSomeUserInput(Sender: TMyModel; (* and here *)): Boolean;
begin
// Show the dialog
end;
function TMyModelForm.GetSomeUserInput(Sender: TMyModel; (* the params again *)): Boolean;
begin
// The input can be necessary in different situations - some within a thread, some not.
if Assigned(FMyThread) then
Result := FMyThread.GetSomeUserInput(Self, Sender, (* the params *))
else
Result := DoGetSomeUserInput(Sender, (* the params *));
end;
何かコメントはありますか?