博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PeekMessage完美解决MFC主界面无响应
阅读量:4298 次
发布时间:2019-05-27

本文共 3199 字,大约阅读时间需要 10 分钟。

  • 本文固定链接: 
  • 文章来自yanxin8.com

一般主界面无响应的解决方案是,对于计算量过大的方法,另开工作者线程,如下:

     支持两种线程:用户界面线程和工作者线程。

(1)用户界面线程通常用于处理用户输入,响应由用户产生的事件和消息。用户界面线程通常有窗口,有自己的消息循环。CWinApp是一个用户界面线程对象的例子,因为它是从CWinThread派生出来的,而且要处理用户产生的事件和消息。

(2)工作者线程:通常用于处理无需用户输入的任务,如计算。工作者线程没有窗口,因此不需要处理消息。

 

    必须注意的是,可能会出现多个线程同时访问同一个对象的情况。例如,一个线程正在修改一个对象,而另一个线程要读取这个对象,这时就会出现问题。所以,必须采取线程同步的方法来避免此类问题的发生。这也是多线程程序之所以复杂的一个重要原因。

    工作者线程通常用于后台的需耗费较长时间的工作,例如:计算、后台打印等。创建一个线程专门处理此类工作,用户就可以进行其他工作而无需等待。

    一个线程,不管是工作者线程还是用户界面线程,都是调用AfxBeginThread创建并初始化。只是AfxBeginThread被重载成两个版本,一个用于工作者线程,一个用于用户界面线程。

    创建工作线程的函数原型是:CWinThread * AfxBeginThread(AFX_THREADPROC pfnThreadProc,LPVOIDpParam ,int nPriority = THREAD_PRIORITY_NORMAL,UINT nStacksize=0,DWORDdwCreateFlags =0,LPSECURITY_ATTRIBUTES lpSecurityAttris = NULL);

     pfnThreadProc是线程函数指针,工作线程对应一个线程函数

    创建用户界面线程原型:CWinThread * AfxBeginThread(CRuntimClass * pThreadClass, intnPriority = THREAD_PRIORITY_NORMAL,UINT nStacksize=0,DWORD dwCreateFlags =0,LPSECURITY_ATTRIBUTESlpSecurityAttris = NULL);

pThreadClass是CWinTHread的派生类创建的

    但是另开工作者线程,需要pfnThreadProc为全局方法,或类静态方法,这样就限定了使用范围,但是我们可以采用PeekMEssage方法嵌入在主线程中,解决此种UI无响应的状态,如下:

    GetMessage不将控制传回给程序,直到从程序的消息队列中取得消息,但是PeekMessage总是立刻传回,而不论一个消息是否出现。当消息队列中有一个消息时,PeekMessage的传回值为TRUE(非0),并且将按通常方式处理消息。当队列中没有消息时,PeekMessage传回FALSE(0)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
BOOL PeekMessage(
LPMSG IpMsg, // 检索到的消息
HWND  hWnd,  // 窗口指向
UINT  wMSGfilterMin,// 消息范围的下界限参数
UINT  wMsgFilterMax,// 上界限参数
UINT  wRemoveMsg     // 消息在被检索之后要如何处理
);
lpMsg:接收消息信息的MSG结构指针。
hWnd:其消息被检查的窗口句柄。
wMsgFilterMin:指定被检查的消息范围里的第一个消息。
wMsgFilterMax:指定被检查的消息范围里的最后一个消息。
wRemoveMsg:确定消息如何被处理。此参数可取下列值之一:
PM_NOREMOVE:PeekMessage处理后,消息不从队列里除掉。
PM_REMOVE:PeekMessage处理后,消息从队列里除掉。
可将PM_NOYIELD随意组合到PM_NOREMOVE或PM_REMOVE。此标志使系统不释放等待调用程序空闲的线程。
缺省地,处理所有类型的消息。若只处理某些消息,指定一个或多个下列值:
PM_QS_INPUT:Windows NT5.0和Windows 98:处理鼠标和键盘消息。
PM_QS_PAINT:Windows NT 5.0和Windows 98:处理画图消息。
PM_QS_POSTMESSAGE:Windows NT 5.0和Windows 98:处理所有被寄送的消息,包括计时器和热键。
PM_QS_SENDMESSAGE:Windows NT 5.0和Windows 98:处理所有发送消息。
返回值:如果消息可得到,返回非零值;如果没有消息可得到,返回值是零

    PeekMessage在检索应用程序的消息队列时,如果其中有消息就将其放入lpMsg(如下所示的函数原型的声明中)所指的结构中,同时PeekMessage函数不会等到有消息放入队列时才返回。同样,如果hWnd为NULL,则PeekMessage检索对象为进程的消息队列;如果hWnd = -1,那么函数只检索消息队列中hWnd参数为NULL的PostThreadMessage函数投递的消息;如果wMsgFilterMin和wMsgFilterMax都是0,则PeekMessage就检索所有有效消息;对一个消息在完成检索之后,可以显式地删除之(WM_PAINT例外,因为WM_PAINT需要合并处理,只有在合并处理之后才会被删除),也可以显式地保留之。

    和函数GetMessage不一样的是,GetMessage:从系统获取消息,将消息从系统中移除,属于阻塞函数。当系统无消息时,GetMessage会等待下一条消息。而函数PeekMesssge是已查看的方式从系统中获取消息,可以不将消息从系统中移除,是非阻塞函数;当系统无消息时,返回FALSE,继续执行后续代码。

     PeekMesssge只得到那些与参数hWnd标识的窗口相联系的消息或被lsChild确定为其子窗口相联系的消息,并且该消息要在由参数wMsgFiterMin和wMsgFiherMax确定的范围内。如果hWnd为NULL,则PeekMessage接收属于当前调用线程的窗口的消息(PeekMessage不接收属于其他线程的窗口的消息)。如果hWnd为-1,PeekMessage只返回hWnd值为NULL的消息,该消息由函数PostThreadMessage寄送。如果wMsgFilterMin和wMsgFilterMax都为零,PeekMessage返回所有可得的消息(即,无范围过滤)。

1
2
3
4
5
6
while (GetMessage (&msg, NULL, 0, 0))       
{       
    TranslateMessage (&msg) ;       
    DispatchMessage (&msg) ;       
}      
return msg.wParam ;

  在MFC主进程中,如果计算量太大,会造成界面无响应,我们可以在循环中加入如下指令,方可解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while (TRUE)       
{        
    if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))        
    {        
            if (msg.message == WM_QUIT)        
                   break ;        
            TranslateMessage (&msg) ;        
            DispatchMessage (&msg) ;        
    }        
    else        
    {        
            // 完成某些工作的其它行程序        
    }       
}       
return msg.wParam ;

转载地址:http://xlnws.baihongyu.com/

你可能感兴趣的文章
MySQL innert join、left join、right join等理解
查看>>
vivado模块封装ip/edf
查看>>
sdc时序约束
查看>>
Xilinx Jtag Access/svf文件/BSCANE2
查看>>
NoC片上网络
查看>>
开源SoC整理
查看>>
【2020-3-21】Mac安装Homebrew慢,解决办法
查看>>
influxdb 命令行输出时间为 yyyy-MM-dd HH:mm:ss(年月日时分秒)的方法
查看>>
已知子网掩码,确定ip地址范围
查看>>
判断时间或者数字是否连续
查看>>
docker-daemon.json各配置详解
查看>>
Mac 下docker路径 /var/lib/docker不存在问题
查看>>
Docker(一)使用阿里云容器镜像服务
查看>>
Docker(二) 基础命令
查看>>
Docker(三) 构建镜像
查看>>
Spring 全家桶注解一览
查看>>
JDK1.8-Stream API使用
查看>>
cant connect to local MySQL server through socket /tmp/mysql.sock (2)
查看>>
vue中的状态管理 vuex store
查看>>
Maven之阿里云镜像仓库配置
查看>>