技术标签: ui Library mfc microsoft windows 工作 command
June 1995,Microsoft System Journal
Paul DiLascia 是一个自由软件顾问,专长是训练和软件开发(C++ and Windows).他是Windows ++: Writing Reusable Code in C++ (Addison-Wesley, 1992)的作者. |
问:我的问题是OnIdle在通常的文档/视图程序中可以工作,但是看起来在基于对话框的程序中不行。我的CApp::InitInstance调用dlg.DoModal,调用一个函数:不调用OnIdle的CWnd::RunModalLoop。我想我应该在WM_ENTERIDLE中做一些后台处理,但是这个消息是发送到对话框的父窗口的。在我的这种情况下,父窗口不存在。请帮忙!
Jim Kallimani
如你所见,“模态”对话框在MFC4.0中实际上是非模态的。当你调用CDialog::DoModal的时候,MFC并不调用::DialogBox,像它以前所做的,而是调用CreateDialogIndirect (在三思之后)然后通过禁用父窗口并且进入自己的消息循环模拟模态行为。这是::DialogBox所做的本质工作。这样做的好处是MFC拥有对话框的消息循环,以前它被Windows API函数::DialogBox隐藏起来了。这样MFC通过通常MFC的消息泵CWinThread::PumpMessage取模态对话框消息,像其他窗口一样。特别的,你可以为模态对话框重载CWnd::PreTranslateMessage—例如实现加速键。MFC的早期版本允许你为模态对话框实现你自己的PreTranslateMessage,但是没有被系统调用,因为CDialog::DoModal直接执行::DialogBox,直到你的对话框消息处理函数调用EndDialog才返回。同样,使用::DialogBox, 使用通常的MFC方法进行消息处理是不可能的,因为程序控制消失在::DialogBox中,直到对话框结束才返回。
作为替代方案, Windows有它自己的机制, WM_ENTERIDLE, 在模态对话框中进行消息处理。当处理完一个或多个消息之后,Windows 发送 WM_ ENTERIDLE 到一个模态对话框或菜单的所有者,如果消息队列中没有等待的消息的话。只有模态对话框发送WM_ENTERIDLE,而非模态对话框不发送。因为MFC现在使用非模态对话框,甚至是在使用模态对话框的时候实际上也是使用非模态对话框,MFC不得不自己发送WM_ENTERIDLE以模仿模态对话框—-但是仅当对话框有父窗口的时候才这么干。Jim碰到麻烦,因为没有父窗口来接收WM_ENTERIDLE。你的头快昏了吗?
如果MFC通过标准消息泵取模态对话框消息,为什么不调用CWinApp::OnIdle作为自己消息处理的一部分?为题是CWnd::RunModalLoop 调用了CWinThread::PumpMessage但是OnIdle在CWinThread::Run中出现。当你的应用程序调用了InitInstance函数之后,MFC调用CWinThread::Run运行你的应用程序。CWinThread::Run的浓缩形式看起来像这样:
// (from THRDCORE.CPP)
int CWinThread::Run()
{
// 为了空闲状态处理
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
for (;;) {
while (bIdle && !::PeekMessage(...)) {
//当在bIdle状态时调用OnIdle
if (!OnIdle(lIdleCount++))
// 假设"非空闲" 状态
bIdle = FALSE;
}
// 获取/预处理/分派消息
// (调用 CWinThread::PumpMessage)
}
}
我砍掉了很多,以强调空闲处理如何工作。如果没有消息在等待,MFC重复调用CWinThread::OnIdle,传递给它每次增加的一个计数器参数。你可以使用这个参数区分不同种类的空闲处理的优先次序。你可能在空闲计数为1时作格式化,空闲计数为2时更新一个指示当天时间的时钟。当你的OnIdle返回FALSE时,MFC停止调用它并且等待,直到你的线程得到另一个消息,因此空闲循环从头开始。
模态对话框从不执行这个代码,因为CWnd::RunModalLoop直接在自己的消息循环中调用CWinThread::PumpMessage。它没有调用CWinThread::Run,因此从不调用CWinThread::OnIdle。 Redmond 的人员告诉我这是由设计上决定的。显然,在模态对话框中调用OnIdle是危险的,因为许多消息处理函数建立临时CWnd对象,它们被期望在对话框生存期中存在。默认空闲处理的一部分就是释放临时句柄映射。(译者注:临时CWnd对象依赖于临时句柄映射而存在。.)
(我不得不告诉你,依我所见,整个MFC用来连接HWND和CWnd的临时/永久句柄映射机制是整个架构中的灾难之一,甚至比它们的消息映射还要坏。临时映射机制的问题不断出现在程序中—特别是在多线程应用中,使得他们很难用MFC编写。)
这样看来,你如何在基于对话框的应用程序中进行消息处理,当对话框没有父窗口的时候?幸运的是,它易如反掌。MFC开发者提供一个钩子: WM_KICKIDLE。 RunModalLoop 不断发送这个MFC私有消息,当消息队列中没有消息的时候—就像CWinThread::Run调用OnIdle一样。 RunModalLoop甚至还为你提供一个计数器并且依次递增。实际上,WM_KICKIDLE是对话框的OnIdle替代品。 (历史信息:早期版本的MFC为属性表作这个模态/非模态切换和提供WM_KICKIDLE。显然它工作的如此之好,以至于他们决定使所有的模态对话框非模态化。)
要警告你的是:你可能在OnKickIdle函数中,想调用你的主应用程序的OnIdle函数
LRESULT CMyDlg::OnKickIdle(WPARAM, LPARAM lCount)
{
return AfxGetApp()->OnIdle(lCount);
}
MFC人员告诉我这是危险的;因为临时映射问题。在OnKickIdle中执行你的空闲处理会更安全一些。如果有必要,你可以组合共有的空闲处理成为一个辅助函数,在CApp::OnIdle 和 CMyDlg::OnKickIdle中调用。
当我在处理空闲处理的问题的时候,发现不是所有程序员都知道CDocTemplate和CDocument的OnIdle函数! 如果你要在文档或文档模板中执行空闲处理,只需重载这些函数。
|
Paul DiLascia |
From the June 1996 issue of Microsoft Systems Journal.
July 1997,Microsoft System Journal
......
下面我将指出如何使ON_COMMAND_UPDATE_UI处理函数在对话框中工作。在通常的MFC文档/视图应用中,MFC使用内部消息WM_IDLEUPDATECMDUI更新菜单项、工具栏按钮、状态栏格等用户界面对象。作为空闲处理的一部分,IDLEUPDATECMDUI广播到所有你的应用程序的窗口。工具栏、状态栏和对话栏的命令处理依次调用UpdateDialogControls广播另一个命令,CN_UPDATE_COMMAND_UI,到窗口上的所有控件。从你的程序员的角度来看,这些消息是不可见的。你只需实现ON_UPDATE_COMMAND_UI处理你的菜单项和按钮,然后,看? 它们被变魔法似的更新了。(需要更多信息的话,参见我的在1995年6月MSJ.上的文章 "Meandering Through the Maze of MFC Message and Command Routing" )
不幸的是,这个奇妙的UI更新机制不能用于对话框—至少不是自动的。 你必须自己修补一下。幸好它很简单。你只需处理WM_KICKIDLE,一个MFC私有消息;当对话框空闲时发送出来(类似应用程序的OnIdle处理)给.你自己调用UpdateDialogControls。.
LRESULT CTabDialog::OnKickIdle(WPARAM wp,
LPARAM lCount)
{
UpdateDialogControls(this, TRUE);
return 0;
}
CWnd::UpdateDialogControls发送魔术般的CN_ UPDATE_COMMAND_UI 消息给所有对话框控件,结果是现在ON_COMMAND_ UPDATE_UI处理突然在对话框中可以工作了。 |
程序设计作业week_11to sum up本周主要学习动态规划中的背包问题。主要以0-1背包为原型,拓展到完全背包,分组背包,多重背包等问题,并后者延伸问题使用滚动数组、二进制拆分进行优化。Problem A 蒜头君买房蒜头君从现在开始工作,年薪N 万。他希望在蒜厂附近买一套 60 平米的房子,现在价格是 200 万。假设房子价格以每年百分之 K 增长,并且蒜头君未来年薪不变,且不吃不...
我们在开发中会有些方法多次调用,为了方便使用都会写一批辅助类,我亦是如此,不过最近发现实际上Android已经有一些自带的辅助类,来看看吧:一.android.text.TextUtils类1. boolean isEmpty(CharSequence str):判断给定的字符序列是否为空。如果字符串为空或者它的长度为0返回true
IDEA初次运行web项目遇到的问题,Error:Abnormal build process termination:2019-12-23今天刚接手一个web项目,在初次运行的时候,遇到一个问题,记录一下:问题如下:Error:Abnormal build process termination:“C:\Program Files (x86)\Java\jdk1.8.0_191\bin...
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/79566313需求是每天的23点59分执行定时任务。1、安装yum install crontabs2、服务相关/sbin/service crond status #查看任务状态/sbin/service crond start #启动服务/sbin/...
一.initrd和initramfs区别1.initramfs是对initrd的升级;2.initrd将根文件系统包和Image分开,而initramfs将根文件系统与内核打包在一起;3.initrd文件系统占用的内存得不到释放,而initramfs可以释放内存;4.initrd是基于ramdisk实现,initramfs是基于ramfs实现;5.ramdisk是把一块内存(r...
基于vue实现的双向数据绑定数据劫持+订阅者-发布者模式;运用Object.defineProperty;每当一个watcher订阅者初次获取vue实例的data的某个属性时,将它添加为这个属性的订阅者,当data的这个属性改变时,会通知订阅者,调用它们各自的update方法;前话何为数据劫持?vue通过Object.defineProperty()来劫持各个属性的sette...
jQueryjQuery引入jQuery框架js对象和jq对象互相转换选择器基础选择器层级选择器过滤选择器内容选择器可见选择器属性选择器子元素选择器表单选择器创建和添加元素插入元素删除元素获取和修改元素的文本内容获取和修改元素的html内容获取和修改元素的css样式获取和修改元素的属性 attr = attribute(属性)jQuery什么jQuery:是一个js框架可以让程...
声明 本文参考了《机器学习实战》书中代码,结合该书讲解,并加之自己的理解和阐述机器学习实战系列博文机器学习实战--k近邻算法改进约会网站的配对效果 机器学习实战--决策树的构建、画图与实例:预测隐形眼镜类型 机器学习实战--朴素贝叶斯算法应用及实例:利用贝叶斯分类器过滤垃圾邮件 机器学习实战--Logistic回归与实例:从疝病症预测病马的死亡率Logist...
给一个点加D,的效果为以从该点发出的出边权值+D,所有进入该边的入边权值-D,现在要求使所有边权值为正,且最大的D。sum(a)表示节点a上D值之和得到不等式 对于 sum(a)-sum(b)+w(a,b)>=D 可以得到这个不等式,不等式怎么办?差分约束,最短路。注意要是图联通。所以加入0与每个点连权值为0最后二分枚举D,判断是否有负环,有则不符合要求。
Loader: 1. 本身是一个base类, 其注释里谈到了一些注意事项Loader的使用者应该遵循在任何时候对Loader的操作都在主线程(Activity的callback(onStart/XXX)发生的线程)进行, 而Loader的具体实现类,其耗时的操作可以也应该放在独立线程,传达结果这类操作应该在主线程完成Loader的构造函数传入一个context,但是其内部使用的mContext
如果你在启动Jenkins,然后配置Jenkins初始化报错:Problem accessing /jenkins/. Reason那么恭喜你找到了jenkins的一个彩蛋bug。解决办法:去掉访问地址的/jenkins 即可。例如: http://localhost:8080/jenkins -> http://localhost:8080喜欢的朋友点点关注哦~~...
关于loadrunner使用web_add_header添加HTTP信息头(比如Content-Type,token等)和使用1.web_add_header添加HTTP信息头(比如Content-Type,token等) 2.用web_custom_request()函数实现提交json数据 Method填入相应的请求方式,我这是POSTURL填入请求的地址B...