在Thread中使用EnterCriticalSection更新VCL标签

发布于 2024-08-25 04:51:59 字数 519 浏览 5 评论 0原文

我是线程新手。我正在使用一个第三方库,该库使用线程,有时会调用我提供的过程。

当线程调用我的过程时,如何更新 TLabel.Caption?

如果我在其他地方调用了InitializeCriticalSection,是否像

  EnterCriticalSection(CritSect);
  GlobalVariable := 'New TLabel.Caption';
  LeaveCriticalSection(CritSect);

然后在我的主线程中一样简单:

  EnterCriticalSection(CritSect);
    Label1.Caption:= GlobalVariable;
  LeaveCriticalSection(CritSect);

但是,如何获取要调用的主线程代码?线程可以使用SendMessage吗?或者是否有一些更好/更简单的方法(.OnIdle 可以检查线程设置的标志?)

谢谢。

I'm new to threads. I'm using a 3rd party library that uses threads which at times call a procedure I've provided.

How do I update update a TLabel.Caption from my procedure when its called by the thread?

If I've called InitializeCriticalSection elsewhere, is it as simple as

  EnterCriticalSection(CritSect);
  GlobalVariable := 'New TLabel.Caption';
  LeaveCriticalSection(CritSect);

And then in my main thread:

  EnterCriticalSection(CritSect);
    Label1.Caption:= GlobalVariable;
  LeaveCriticalSection(CritSect);

But, how do I get the main thread code to be called? The thread can use SendMessage? Or is there some better/easier way (.OnIdle could check a flag set by the thread?)

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

过潦 2024-09-01 04:51:59

关键部分用于序列化对一段代码的访问。对于更新图形用户界面,您应该注意只有主线程才应该更新 GUI 元素。

因此,如果您的线程需要更新 GUI 元素,它应该将其委托给主线程。为此,您可以使用不同的技术:

最简单的一种是在线程代码中使用 Synchronize 方法。当调用 Synchronize 时,您的线程将暂停,您提供给 Synchronize 的代码将在主线程的上下文中执行,然后您的线程恢复。

如果您不希望每次调用该代码段时线程都停止,那么您可以使用 Queue 方法。 Queue 将您的请求发送到目标线程(这里是主线程)的消息队列,因此您的线程不会停止,但 UI 可能不会立即更新,具体取决于主线程消息队列的拥挤程度。

实现此目的的另一种方法是使用 SendMessage 或 PostMessage API 函数将自定义 Windows 消息发送到主线程。在这种情况下,您必须定义一条自定义消息,并在需要更改 UI 元素时将其发送到主线程。您的主线程应该为该类型的消息提供一个消息处理程序,并处理收到的消息。结果与使用 Queue 方法类似。

Critical Sections are used to serialize accessing to a piece of code. For updating graphical user interface, you should take note that only the main thread should update GUI elements.

So if your thread needs to update a GUI element, it should delegate this to the main thread. To do so, you can use different techniques:

The simplest one is using Synchronize method in your thread code. When Synchronize is called, your thread is paused, the code you provided to Synchronize will be executed in the context of the main thread, and then your thread resumes.

If you don't like your thread get stopped every time that piece of code is called, then you can use Queue method. Queue sends your request to the message queue of the destination thread (here main thread), so your thread will not stop, but the UI might not get updated immediately, depending on how crowded main thread's message queue is.

Another way to achieve this is to send custom Windows messages to the main thread using SendMessage or PostMessage API functions. In that case, you have to define a custom message, and send it to the main thread whenever you need to change a UI element. Your main thread should provide a message handler for that type of message, and handle the received messages. The consequence is something similar to using Queue method.

九公里浅绿 2024-09-01 04:51:59

要使您的代码在主线程中被调用,请查看 TThread.Synchronize。它接受一个方法指针(或者,在 D2009+ 中,一个匿名方法)并负责幕后的所有消息传递,以确保您的代码将在主线程中运行。

To make your code gets called in the main thread, take a look at TThread.Synchronize. It accepts a method pointer (or, in D2009+, an anonymous method) and takes care of all the messaging behind the scenes to make sure your code will run in the main thread.

歌枕肩 2024-09-01 04:51:59

您必须确保以安全的方式更新标签。此外,VCL 在应用程序主线程中运行,从其他线程干扰它可能会产生奇怪的结果。即使使用临界区。

所以我的建议是:只使用PostMessage。当调用回调过程时,只需从该过程调用 PostMessage 到主窗体窗口句柄。这将确保标签标题是在主线程的上下文中设置的。

代码示例:

type
  TForm1 = class(TForm)
  private
    procedure OnWMUpdateLabel(var Msg: TMessage); message WM_UPDATE_LABEL;
    procedure MyCallbackProcedure(const Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.OnWMUpdateLabel(var Msg: TMessage);
begin
  Label1.Caption := SomeVariable;
end;

procedure TForm1.MyCallbackProcedure(const Sender: TObject);
begin
  SomeVariable := 'New Label';
  PostMessage(Handle, WM_UPDATE_LABEL, 0, 0);
end;

但是如果您以这种方式传递字符串,则必须小心。您必须同步对此类变量的访问。或者您可以使用 GlobalAddAtom (有点不推荐使用)或类似的东西。

编辑:

正如梅森已经说过的,您还可以使用同步,它更容易使用。对于你的问题应该完全没问题。

编辑2:

有关如何使用GlobalAddAtom的参考(是的,我之前拼写错误):

http ://www.delphi3000.com/articles/article_574.asp?SK=

You must ensure that the label is updated in a safe manner. Furthermore VCL runs in the application main thread and messing with it from other threads can have weird results. Even if using critical sections.

So my advice is: just use PostMessage. When your callback procedure is called, just call PostMessage from that procedure to the main form window handle. This will ensure that the label caption is set in the context of the main thread.

Code sample:

type
  TForm1 = class(TForm)
  private
    procedure OnWMUpdateLabel(var Msg: TMessage); message WM_UPDATE_LABEL;
    procedure MyCallbackProcedure(const Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.OnWMUpdateLabel(var Msg: TMessage);
begin
  Label1.Caption := SomeVariable;
end;

procedure TForm1.MyCallbackProcedure(const Sender: TObject);
begin
  SomeVariable := 'New Label';
  PostMessage(Handle, WM_UPDATE_LABEL, 0, 0);
end;

But you have to be careful if you pass strings around this way. You have to synchronize the access to such variable. Or you can use GlobalAddAtom (which is a little deprecated), or something similar.

EDIT:

As Mason already said you can also use Synchronize which is easier to use. For your problem it should be perfectly OK.

EDIT 2:

For the reference how to use GlobalAddAtom (yes I misspelled it earlier):

http://www.delphi3000.com/articles/article_574.asp?SK=

蘑菇王子 2024-09-01 04:51:59

我这样做的方法是让主应用程序线程在表单上使用 TTimer 来检查线程特定值的状态,以查看状态是否已更改,如果是,则更新标签(或其他组件)。 TThread 后代使用带有 Getter 函数的属性来保护对临界区的访问。这样,工作线程就不会被主线程阻碍(Synchronize 会这样做),并且用户在使用 UI 时不会遇到任何延迟。

The way I do this is to have the main application thread use a TTimer on the form to check the status of a thread specific value to see if the status has changed, and if so, update the label (or other components). The TThread descendent uses a property with Getter function to protect access with the critical section. This way the work thread is never held back by the main thread (which Synchronize will do), and the user does not experience any delay in the use of the UI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文