等待点击,同时保持应用程序UI处于活动状态 [英] Wait for a click whilst keeping app UI active

查看:44
本文介绍了等待点击,同时保持应用程序UI处于活动状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中有一个功能,必须等待鼠标单击或退出键才能返回.该应用程序必须保持活动",直到获得结果为止,即功能区控件需要能够更新,并且我需要在每次鼠标移动等情况下做一些自己的GDI绘图.

我已经通过使用消息循环实现了这一点.简化代码:

I have a function in my app which has to wait for a mouse click or an escape keypress before it returns. The app has to ''stay alive'' until I get a result, ie the ribbon controls need to be able to update, and I need to do some of my own GDI drawing with each mouse movement etc.

I have achieved this by using a message loop. Simplified code:

bool cancel = false;
bool clicked = false;

BOOL waitForClick (CPoint &clickedPosition)
{
    while (theApp.PumpMessage())
    {
        theApp.OnIdle(0);
        if (bCancelled) // this is set elsewhere in the app code, when WM_KEYDOWN is received with an escape keypress
        {
            cancel = true;
            break;
        }

        if (bClicked) // this is set elsewhere in the app code, when ON_WM_LBUTTONDOWN is received
        {
            clicked = true;
            break;
        }
    }

    if (cancel)
    {
        return FALSE;
    }
    if (clicked)
    {
        clickedPosition = gPosition;
        return TRUE;
    }
    return FALSE;
}



这似乎可以正常工作,但是对此进行了研究,我已经阅读了很多有关我应该如何使用线程而不是消息循环的信息.

但是,即使我生成一个线程来等待单击,我仍然必须等待该线程完成并告诉我的函数它可以返回,对吗?

我还发现我无法停止代码中其他地方的循环.例如,假设用户决定通过单击另一个功能区按钮来运行其他命令.我需要取消当前正在运行的命令(这是上面的循环).我尝试使循环在每次循环时都检查全局布尔值是否为真,如果另一个命令开始,则将该布尔值设置为false,但是当然,直到另一个命令的代码完成后,循环才通过.

另一个问题是,在MDI环境中,如果我启动命令,切换文档,在该文档中启动命令,然后再切换回第一个文档,那么我现在在第二个文档中运行循环,从而占用所有消息.

因此,总而言之,我认为消息循环不是正确的答案.但在这种情况下,我也不知道线程如何执行此操作,主要是因为该函数只有在单击或转义后才能返回.


我猜想对此可能有一个优雅的解决方案,可能是使用线程,到目前为止,这已经使我逃脱了(没有双关语).有没有人能向我介绍正确的方向?



This seems to work OK but having researched this I have read a lot about how I should be using threads instead of message loops.

However, even if I spawn a thread to wait for a click, I still have to wait for that thread to finish and tell my function that it can return, right?

I also found that I can''t stop this loop from elsewhere in my code. For example, suppose the user decides to run a different command, by hitting another ribbon button. I need to cancel the command currently running (which is the loop above). I tried making the loop check a global bool is true every time through the loop, and set that bool to false if the other command starts, but of course the loop isn''t passed through until the code for that other command has finished.

Another problem is that in an MDI environment, if I start the command, switch documents, start the command in that document, and then switch back to the first document, I now have the loop running in the second document, hogging all the messages.

So in summary, I don''t think a message loop is the right answer. But I don''t get how threading could do it either, in this case, mainly because the function can not return until it has a click or an escape.


I would guess that there is an elegant solution to this, probably using threading, which so far has escaped me (no pun intended). Is anyone able to give me a nudge in the right direction please?

推荐答案

线程和消息泵?对我来说,这听起来像是工程上的事情.当然,您需要在处理线条图的对象内使用有限状态机.

消息可以正常处理.绘制状态结构,并在它们之间建立链接,以显示可以将您从一个转移到另一个的事件类型.只要您能够处理将在每个状态转换中发生的相关消息,您就不必担心消息泵或其中的线程.

我认为您试图在这里过度设计,并为此增加线程复杂性问题将使整个事情变得少很多麻烦.当然,我对您在这里想要实现的目标仅了解甚少.
Threads and message pumps? This sounds like over engineering to me. Surely you need a finite state machine within the object handling the line drawing.

Messages can be handled as normal. Draw out a structure of states with links between them showing the event types that can move you from one to the other. As long as you can handle the relevant messages that will occur for each state transition you dont need to worry about message pump or threading in this.

I think your trying to over engineer here and adding a threading complexity issue to this will just make the whole thing much less managle. Of course I only have a cursory knowledge of exactly what your trying to achieve here.


但是,即使我产生一个线程来等待单击,我仍然必须等待该线程完成并告诉我的函数可以返回,对吗?"


等待返回的函数也应该在等待单击/转义的那个单独的线程中.然后,当检测到单击/转义并且线程即将终止时,您将必须通知主线程.
例如,您可以通过将wParam中具有唯一ID的WM_COMMAND消息发送到消息循环(该消息循环从功能区解释命令)来实现此目的.

现在,如果您在功能区收到消息之前从功能区收到另一个命令,则可以设置bCancelled变量.
"However, even if I spawn a thread to wait for a click, I still have to wait for that thread to finish and tell my function that it can return, right?"


The function waiting to return should also be in that separate thread which is waiting for the click/escape. Then when the click/escape has been detected and the thread is about to terminate, you''ll have to inform the main thread.
You could do this for example by sending a WM_COMMAND message with a unique ID in wParam to the message loop which is interpreting commands from your ribbon.

Now if you receive another command from your ribbon before you got the message that the thread is finished, you can set your bCancelled variable.


OnCommandDrawLine()将创建一个线程并立即返回.因此,主线程仍然处于活动状态,并且能够设置bClicked和bCancelled消息,以及处理功能区中的所有命令消息.

在OnCommandDrawLine创建的线程中,您现在可以简单地添加一个循环以等待第一次单击,然后存储单击坐标.现在有了另一个这样的循环,等待第二次单击并在收到时画线.
由于主线程没有等待任何内容,因此让第二个线程在while循环中等待bClicked和bCancelled的更改非常好.

OnCommandDrawLine() will create a thread and return immediately. So the main thread is still active and able to set the bClicked and bCancelled messages, as well as process all your command messages from the ribbon.

In the thread created by OnCommandDrawLine, you can now simply add a loop to wait for the first click and then store the click coordinates. Now with another such loop, wait for the second click and draw the line when you receive it.
Since the main thread isn''t waiting on anything, it''s perfectly fine for the second thread to be waiting for a change in bClicked and bCancelled in a while loop.

// Wait for the first click and allow for a cancel command.
while(!bClicked)
        if(bCancelled)
            return FALSE;

// At this point, the first click has been received.
// Store the mouse coordinates somewhere, for example in
//  clickedPosition1.

// Make sure not to process the first click twice.
bClicked = 0;

// Wait for the second click.
while(!bClicked)
        if(bCancelled)
            return FALSE;

// At this point, two clicks have been received
//  and no cancel command has been given.
// Now you can draw a line using the stored coordinates.


这篇关于等待点击,同时保持应用程序UI处于活动状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆