基于 CDialog 的应用程序一开始便被隐藏的方法 补充 CMainframe
来源:互联网 发布:淘宝店铺个性公告范文 编辑:程序博客网 时间:2024/05/20 14:28
其实,MFC框架为了显示对话框很多工作,它并不简简单单地调用 DialogBox 显示对话框,而是使用了相对复杂的方法。现在,我就来引导大家对此探个究竟。
在生成的应用程序框架中(名称为Test),你会看到CTestApp和CTestDlg 两个类,在 CTestApp 的 InitInstance 方法中有如下语句:
CTestDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal(); // 此处将创建并显示对话框
DoModal 是一个虚函数,MFC允许用户编写自己的调用对话框方式来替代原来的方式。但是,MS 实在令人失望。如果,你打开 DlgCore.Cpp (MFC Source 目录下)并复制 DoModal 的代码到你自己的类中,你会发现无法编译成功。原因在于MS在 DoModal 中使用了两个非输出函数 AfxHookWindowCreate 和 AfxUnhookWindowCreate。(这两个函数的作用超出了本文所讨论的范围,因此不作详细论述。)由于无法编译,所以 MS 要求用户的 DoModal 必须调用 CDialog 的 DoModal 来显示对话框。这样,控制隐藏就无法通过重载 DoModal 实现了。那么 MS 在 DoModal 中干了什么呢?下面就是一部分代码。
int CDialog::DoModal()
{
...... 读入资源,并作一些设置
if (CreateDlgIndirect(lpDialogTemplate,
CWnd::FromHandle(hWndParent), hInst)) //创建无模式对话框
{
if (m_nFlags & WF_CONTINUEMODAL)
{
// enter modal loop
DWORD dwFlags = MLF_SHOWONIDLE; //罪魁祸首就是他
if (GetStyle() & DS_NOIDLEMSG)
dwFlags |= MLF_NOIDLEMSG;
VERIFY(RunModalLoop(dwFlags) == m_nModalResult); //进入消息循环
}
.......
}
}
...... 释放资源等
}
原来,DoModal 并不使用 DialogBox 直接调出对话框,而是通过创建无模式对话框并维护消息循环的方式(RunModalLoop)来模拟模式对话框的效果。(看起来好像有点像DialogBox 的内部作业方式)MLF_SHOWONIDLE 是什么?看英文的意思是在Idle 的时候ShowWindow。那么是不是这样呢?好吧,为了探个究竟,让我们进入RunModalLoop。RunModalLoop在WinCore.CPP中定义。打开WinCore.CPP 并找到 RunModalLoop, 会看到以下的语句
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
条件 dwFlags & MLF_SHOWONIDLE 始终为TRUE。 而 !(GetStyle() & WS_VISIBLE)只有在WS_VISIBLE属性没有设置的时候才会为 TRUE。这样,当我们去掉Visible 属性后 bShowIdle 就为 TRUE 了。再往下,就会看到以下的调用
while (bIdle &&
!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
// show the dialog when the message queue goes idle
if (bShowIdle) // 找到了
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE; // 指示下一次Idle 时不用显示对话框了
}
While 里的条件是消息队列里再也没有任何消息了。此时,由于 bShowIdle 为 TRUE ,就会调用 ShowWindow 来显示对话框。由于 ShowWindow 只执行一次,所以如果能截获第一次WM_SHOWWINDOW消息, 就能控制了隐藏了。
是的。在 CTestDlg 处理 WM_SHOWWINDOW 并添上以下代码
void CTestDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
if( GetStyle() & WS_VISIBLE ) {
CDialog::OnShowWindow(bShow, nStatus);
} else {
long Style = ::GetWindowLong(*this, GWL_STYLE);
::SetWindowLong(*this, GWL_STYLE, Style | WS_VISIBLE);
CDialog::OnShowWindow(SW_HIDE, nStatus);
}
}
再运行一下,哈哈,对话框不见了,连闪都不闪一下。细心的读者也许会问为什么使用SetWindowLong,而不是 ModifyStyle, 其实是为了加快速度,因为 ModifyStyle 内部还要调用 GetWindowLong 和 SetWindowPos。到此为止,一个简单,完满的解决方法已经展现在大家面前了。
其实,本来 MS 可以做的更好,比如把 GetStyle() 声明为虚函数,使得我们能返回WS_VISIBLE 来控制 bShowIdle 成为 FALSE, 或者把
DWORD dwFlags = MLF_SHOWONIDLE;
改成
DWORD dwFlags = ShowOnIdle(); // 声明为虚函数
对于SDI 则需要改动两处
第一处:
CXXApp::InitInstance()
{
//m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->ShowWindow(SW_HIDE); //只修改这一处 程序会一闪而过
}
第二处:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
AfxGetApp()->m_nCmdShow=SW_HIDE;//添上这一句
}
- 基于 CDialog 的应用程序一开始便被隐藏的方法 补充 CMainframe
- 基于 CDialog 的应用程序一开始便被隐藏的方法[转]
- "基于 CDialog 的应用程序一开始便被隐藏的方法"再探
- VC中基于对话框的程序在一开始创建时候就隐藏主窗体的方法
- mfc 一开始隐藏窗体的方法以及原理解析
- CDialog的new方法
- .隐藏基于对话框的MFC应用程序窗口的方法
- 隐藏基于对话框的MFC应用程序窗口的方法
- onActivityResult方法在一开始就被调用的解决方法
- 隐藏基于对话框的MFC应用程序窗口的方法 (推荐这个方法,非常好用)
- CDialog上建立View的方法
- 动态改变基于CDialog的窗口的大小
- 动态改变基于CDialog的窗口的大小
- CDialog dlg; 和 CDialog *pDlg;的区别
- CMainFrame中获得CMyView对象的指针的方法
- 工作的一开始
- 更改CMainFrame窗口标题的几种可选方法
- MFC中去掉CMainFrame蓝色边框的一种方法
- SEO简介及优化
- 类加载机制
- 【转】计算几何中的精度问题
- WIN7 无法使用ping 命令
- 使用setStyleSheet来设置图形界面的外观
- 基于 CDialog 的应用程序一开始便被隐藏的方法 补充 CMainframe
- stagefright + omx小结
- 三种东西永远不要放到数据库里
- RepairImages\superboot-6410.bin
- 求几个数的组合数 容斥原理
- WCF
- BigDecimal类的的基本用法【附加:整除报错的解决方案】
- SQL语句大全(几乎所有常用的示例,包括省市号码源码)
- 在Eclipse中使用JUnit4进行单元测试(初级篇)