4

アプリケーションの特定のフォームは、モデルのグラフィカル ビューを表示します。ユーザーは、他の多くのものの中で、モデルの変換を開始できますが、これにはかなりの時間がかかります。この変換は、ユーザーの操作なしで進行する場合もあれば、頻繁なユーザー入力が必要な場合もあります。それが続く間、ユーザー入力が必要でない限り、UI を無効にする必要があります (進行状況ダイアログを表示するだけです)。

可能なアプローチ:

  1. 問題を無視して、変換コードをプロシージャに入れて呼び出すだけです。変換に時間がかかるがユーザー入力を必要としない場合、アプリがハングしているように見えるため、悪いです。
  2. コードにコールバックを散りばめます: これは目障りです。これらの呼び出しを変換コードに多数配置する必要があり、予測不能であり、適切な場所を見つけたことを確認できませんでした。
  3. コードに Application.ProcessMessages を追加します。コールバックと同じ問題です。さらに、ProcessMessages に関するすべての問題が発生します。
  4. スレッドを使用する: これにより、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;

何かコメントはありますか?

4

10 に答える 10

7

長期にわたる変換にユーザーの操作が必要である限り、得られた回答に本当に満足することはできないと思います。ここで少し話を戻しましょう。詳細情報の要求で変換を中断する必要があるのはなぜですか? これらは本当に、変革を始める前には予想できなかった質問ですか? 確かに、ユーザーも中断についてあまり満足していませんよね? 彼らはただ変換を開始してからコーヒーを飲みに行くことはできません。問題が発生した場合に備えて、進行状況バーを座って見る必要があります。うーん。

おそらく、変換が遭遇する問題は、最後まで「保存」できるものです。変換はすぐに答えを知る必要がありますか?それとも、他のすべてを終了してから、後で「修正」を行うだけでよいでしょうか?

于 2009-01-12T19:46:40.003 に答える
4

間違いなくスレッドオプションを選択してください(編集した後でも、複雑だと言っています)。 duffymoが提案する解決策は、私の意見では、非常に貧弱なUIデザインです(外観については明示的にではありませんが、ユーザーがアプリケーションとどのようにインターフェイスするかについてです)。これを行うプログラムは、タスクにかかる時間や完了する時期などがわからないため、煩わしいものです。このアプローチを改善する唯一の方法は、結果に生成日時をスタンプすることですが、次に、ユーザーがいつプロセスを開始したかを覚えておく必要があります。

時間と労力を費やして、アプリケーションをエンドユーザーにとって有用で有益でイライラの少ないものにします。

于 2009-01-12T18:51:50.863 に答える
2

TThreadは完璧で使いやすいです。

遅い関数を開発してデバッグします。

準備ができたら、呼び出しをtthreadexecuteメソッドに入れます。onThreadTerminateイベントを使用して、関数の終わりを見つけます。

ユーザーフィードバックにはsyncronizeを使用してください!

于 2009-01-12T18:52:53.840 に答える
1

メッセージをキューに送信して非同期的に処理し、リスナーに処理を実行させます。コントローラは、「処理のリクエストを受け取りました。結果については後でもう一度確認してください」というACKメッセージをユーザーに送信します。ユーザーにメールボックスまたはリンクを提供して、状況を確認し、進捗状況を確認します。

于 2009-01-12T18:47:25.753 に答える
1

私は確かにスレッドで行きます。スレッドがユーザーとどのように相互作用するかを理解することはしばしば困難ですが、私にとってうまく機能した解決策は、スレッドをユーザーと相互作用させず、ユーザー側のGUIをスレッドと相互作用させることです。これにより、同期を使用してGUIを更新する問題が解決され、ユーザーのアクティビティの応答性が向上します。

したがって、これを行うために、クリティカルセクションを使用するGet / Setルーチンによってアクセスされるスレッド内のさまざまな変数を使用して、ステータス情報を含めます。手始めに、GUIがスレッドを停止するように要求するように設定するための「キャンセル済み」プロパティがあります。次に、スレッドが待機中、ビジー、または完了のいずれであるかを示す「ステータス」プロパティ。何が起こっているか、または完了率を示す「人間が読める」ステータスになっている可能性があります。

このすべての情報を読むには、フォームのタイマーを使用して更新するだけです。私も「statusChanged」プロパティを持っている傾向があります。これは、他のアイテムの1つを更新する必要がある場合に設定され、読み取りが多すぎないようにします。

これは、プログレスバーのあるリストボックスに最大8つのスレッドのステータスを表示するアプリなど、さまざまなアプリでうまく機能しました。

于 2009-01-13T09:24:46.903 に答える
1

スレッドを使用することに決めた場合は、Delphi での実装方法がいくぶん複雑だと思いますが、ここ Stack Overflow で知られているPrimož Gabrijelčič またはGabrによるOmniThreadLibraryをお勧めします。

私が知っているスレッドライブラリを使用するのは最も簡単です。Gabrは素晴らしいものを書いています。

于 2009-01-13T21:45:43.070 に答える