User interface Application.DoEvents是否向单独的线程发送消息?
我一直试图从总体上理解事件循环(进展不太顺利),并且我读到windows消息传递循环是单线程的。如果是,Application.DoEvents如何工作?事件循环不是一次处理一条消息,并在处理每条消息/事件时阻塞吗?消息事件循环是否需要存在于与处理Application.DoEvents消息的线程不同的线程上?如果有单独的线程,我们称之为“主”线程的是哪一个?我确信我遗漏了一些非常简单的东西,我只是不知道它是什么。我花了一天的大部分时间来解决这个问题(如果我说的任何事情都是错误的,请评论并让我知道,这样我就可以纠正它)。实际上,我必须构建一个旧的Win32应用程序,并自己创建消息循环(我是一个非常顽固的SOB)。因此,有一个名为WinMain的函数启动消息循环,如下所示:User interface Application.DoEvents是否向单独的线程发送消息?,user-interface,windows-messages,event-loop,User Interface,Windows Messages,Event Loop,我一直试图从总体上理解事件循环(进展不太顺利),并且我读到windows消息传递循环是单线程的。如果是,Application.DoEvents如何工作?事件循环不是一次处理一条消息,并在处理每条消息/事件时阻塞吗?消息事件循环是否需要存在于与处理Application.DoEvents消息的线程不同的线程上?如果有单独的线程,我们称之为“主”线程的是哪一个?我确信我遗漏了一些非常简单的东西,我只是不知道它是什么。我花了一天的大部分时间来解决这个问题(如果我说的任何事情都是错误的,请评论并让我知
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void DoEvents()
{
MSG msg;
HACCEL hAccelTable;
hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDC_TESTWIN32));
// Main message loop:
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0)
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
GetMessage()的问题是它会一直阻塞,直到消息队列中有消息可用为止。如果运行带窗口的应用程序,只是坐在那里查看窗口(不要导致任何将消息发布到队列的操作),则主线程(创建窗口的线程)将在GetMessage()上暂停。现在,当消息确实被发布时,我们进入while循环(即如果消息未退出,则为0)。DispatchMessage()是这里有趣的函数。此函数最终将导致控件和EventHandler的执行引发(在.NET中)事件。让我困惑的是,如果调用堆栈是GetMessage()/DispatchMessage()/…/EventHandler,Application.DoEvents()如何处理消息?其实很简单。Win32中的DoEvents将如下所示:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void DoEvents()
{
MSG msg;
HACCEL hAccelTable;
hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDC_TESTWIN32));
// Main message loop:
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0)
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
因此DoEvents()实际上在初始消息循环的DispatchMessage()内启动另一个循环来处理事件关键的区别在于,我们没有使用GetMessage()来阻止队列中出现消息,而是使用PeekMessage(),它返回0,并在队列中不再有消息时存在循环。
那么,如果我们单击一个按钮两次,然后在该按钮的EventHandler中调用DoEvents()会怎么样?初始事件循环将处理第一次单击并触发事件。在执行EventHandler时,在DoEvents()调用时,将再次触发事件,并再次输入EventHandler(有点像递归调用)。太可怕了
所以最后,所有的事情都发生在一个线程中,DoEvents()实际上会阻塞,直到所有消息都被处理完毕,然后返回。现在我要去睡几天