FRAME (フォームではありません)とスレッドがあります。スレッドからフレームのコントロールを参照するにはどうすればよいですか?たとえば、スレッドのボタンを無効にしたい。しかし、ボタンへのポインタがなく、フレームにグローバル変数がありません。
ありがとう!
実際には、メソッドを呼び出したり、VCLコントロールのプロパティを変更したり、ユーザーに表示されるもの(アプリケーションのユーザーインターフェイス、つまり、フレーム内かどうかに関係なく、Delphiで通常VCLコントロールを使用すること)を直接変更しないでください。バックグラウンドスレッドから。
PostMessage
ただし、、、またはを使用して、イベントまたは通知をメインスレッドに送信できTThread.Synchronize
ますTThread.Queue
。
スレッドオブジェクトにフレームまたはコントロールへの参照を設定するよりも、フレームまたはその他のコントロールを含むフォームのハンドルをスレッドに渡して、ユーザーメッセージ(WM_USER + 10001)を使用する方がよい場合があります。 )このように。
TTHread.SynchronizeやQueueよりもPostMessageの方が好きです。なぜなら、それは本当にシンプルで、うまく機能するからです。Win32 APIに関連付けられているため、クロスプラットフォームに適した手法ではありません。
次のように同期を呼び出す必要があります。
TMyThread = class(TThread)
private
FFrame: TFrame;
...
public
constructor Create(AFrame: TFrame);
...
end;
constructor TMyThread.Create(AFrame: TFrame);
begin
FFrame := AFrame;
inherited Create;
end;
// do not call directly, only using Synchronize
procedure TMyThread.AMethodWithNoParameters;
begin
FFrame.Button1.Enabled := not FBusy;
end;
procedure TMyThread.DoWork; // called from Execute.
begin
FBusy := true;
Synchronize(AMethodWithNoParameters);
Sleep(100); //dummy;
FBusy := false;
Synchronize(AMethodWithNoParameters);
end;
正しく指摘されているように、バックグラウンド スレッドでビジュアル コンポーネントのメンバーを呼び出すことはできません。
スレッドコード内からボタンを無効にするには、ボタンへの参照、またはスレッドオブジェクトを割り当てることができるイベントへの参照が必要です-その後、次のように、キューまたは同期されたプロシージャ内でスレッドを起動できます:-
type
test=class(tthread)
ondisablebutton:tnotifyevent;
{...}
次に、tthread.synchronize でカプセル化したプロシージャーでイベントを呼び出すことができます。イベントが割り当てられているかどうかをテストすることを忘れずに....
procedure test.synchronisedprocedure;
begin
if assigned(ondisablebutton) then
ondisablebuttone(self);
end;
設計したスレッド オブジェクトを作成するときは、次のようなボタンを含むフォームのプロシージャに ondisablebutton を割り当てる必要があります。
procedure form1.threadwantstodisablebutton(sender:tobject);
begin
button1.enabled:=false;
end;
スレッドの作成には追加の行が必要です:-
mythread:=test.create;
test.ondisablebutton:=form1.threadwantstodisablebutton;
そのように、明らかに、スレッドを定義および作成している form1 (またはボタンを含むフォーム) にアクセスする必要があります。これは必ずしも良い設計ではありませんが、機能します。