我有一个问题,C ++构建器VCL Button Click函数是在主UI线程还是临时新创建的线程中执行的?我写了一个测试代码,当用户关闭某个对话框时,按钮点击功能退出,我发现即使先前调用的对话框出现,也会再次输入按钮单击功能。
测试代码如下所示。我的问题是,由于DoPollingFunc()中的Application-> ProcessMessages(),可以再次单击Button并重新输入Click函数?
void SomeForm::DoPollingFunc( void )
{
while( 1 )
{
Application->ProcessMessages();
if( polling some flag )
{
break;
}
if( timeout condition )
{
break;
}
}
}
void __fastcall SomeForm::ButtonClick(TObject* Sender)
{
DoPollingFunc();
}
答案 0 :(得分:1)
我有一个问题,即C ++构建器VCL Button Click函数是在主UI线程中执行还是临时新创建的线程?
它运行在实际创建按钮的任何线程中,该按钮通常是主UI线程,除非您编写自己的多线程代码来执行不同的操作。
我编写了一个测试代码,当用户关闭某个对话框时,按钮单击功能退出,我发现即使先前调用的对话框出现,也会再次输入按钮单击功能。
按钮控件收到单击消息时会触发OnClick
事件。
如果对话框是模态的,它会在对话框可见时阻止表单接收用户输入,因此只有在对话框的内部消息循环正在接收和发送针对该特定内容的单击消息时才能触发OnClick
按钮。这意味着当对话框可见时,必须通过某些代码模拟按钮单击。
如果对话框不是模态的(例如TFindDialog
),则在对话框可见时它不会阻止表单接收用户输入,并且对话框在主消息循环中运行,因此用户仍然可以在对话框可见时直接与按钮交互。
答案 1 :(得分:0)
代码在主VCL线程中执行,除非你从OnClick开始,一些其他线程来处理响应(然后以某种方式同步)。
您对测试用例的处理方式尚不清楚。如果多次单击按钮,可以多次执行OnClick,但它们将是顺序的,而不是并行的。
答案 2 :(得分:0)
如果拨打Application->ProcessMessages();
的电话会选择按钮点击消息,则会调用SomeForm::ButtonClick
,然后调用DoPollingFunc
。所以你的调用堆栈看起来像(最近的第一个):
TApplication::ProcessMessages
SomeForm::DoPollingFunc
SomeForm::ButtonClick
TApplication::ProcessMessages
SomeForm::DoPollingFunc
...
为避免发生这种情况,您可能希望使用静态变量来检测重新输入。例如:
struct locker
{
bool &b;
locker(bool &b): b(b) {}
bool lock() { return b++; }
~locker() { b = false; }
};
void SomeForm::DoPollingFunc( void )
{
static bool reentry_flag = false;
locker reentry_lock(reentry_flag);
if ( reentry_lock.lock() )
return; // Already in this function at an earlier level
// ... main code here ...
}