怎样让基于对话框的程序不闪烁

sdc_sh 2003-08-20 09:35:24
我有一个基于对话框的程序,我想让他一运行时就最小化到系统栏,因此我就用非模态对话框,即自己创建,然后在InitInstace中让他一开始就隐藏,但每次运行的时候都能看见对话框一闪,然后才是在系统栏,有那位知道让他不闪动。
...全文
322 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
sdc_sh 2003-08-20
  • 打赏
  • 举报
回复
to free_card(痛并快乐着) :
刚才没来得及测试,现在一看,新的问题又出来了,第一次启动时窗口是不闪了,但当我想要让他显示的时候(ShowWindow(SW_SHOW)),只能显示标题栏和菜单栏,底下的都不显示,非的在任务栏点几下才能完全显示,不知道什么原因(想知道原因),后来我是通过只让OnShowWindow 只运行一次解决了。不知free card 能否给我解释一下,谢谢了
awant2k 2003-08-20
  • 打赏
  • 举报
回复
在OnClose 和析构函数中调用 下面代码(m_nid为你的NOTIFYICONDATA m_nid)
{
m_nid.hIcon = NULL;
Shell_NotifyIcon (NIM_DELETE, &m_nid);
}
sdc_sh 2003-08-20
  • 打赏
  • 举报
回复
首先谢谢 free_card,按他的方法处理了一下OnShowWindow(BOOL bShow, UINT nStatus),现在窗口时不闪了,其实我在InitInstance中做了修改,在头文件中声明了一个指针 CDialUpdateDlg* m_pDlg;, 然后在实现文件中修改InitInstance如下:


//////////////////////////////////////////////////////////////////////////
// CDialUpdateDlg dlg;
// m_pMainWnd = &dlg;
//
// int nResponse = dlg.DoModal();
// if (nResponse == IDOK)
// {
// // TODO: Place code here to handle when the dialog is
// // dismissed with OK
// }
// else if (nResponse == IDCANCEL)
// {
// // TODO: Place code here to handle when the dialog is
// // dismissed with Cancel
// }
//
// // Since the dialog has been closed, return FALSE so that we exit the
// // application, rather than start the application's message pump.
// return FALSE;

m_pDlg = new CDialUpdateDlg;
m_pMainWnd =m_pDlg;
m_pDlg->Create(IDD_DIALUPDATE_DIALOG);
m_pDlg->ShowWindow(SW_HIDE);
//其他处理,如放在系统托盘区等
//...
return TRUE;


free_card 2003-08-20
  • 打赏
  • 举报
回复
有很多应用程序要求一起动就隐藏起来,这些程序多作为后台程序运行,希望不影响其他窗口,往往只在托盘区显示一个图标。这些程序通常都是对话框程序,而对话框在初始化的过程上与SDI、MDI的初始化是不同的,对话框只需要DoModule或者是CreateDialog等等对话框函数调用一次便可,SDI、MDI则要好几步才行。这样看来,对话框在使用方法上面是隐藏了不少细节的,其中就没有SDI、MDI所要求的ShowWindow(nCmdShow)这一步。因此对话框要想一运行就隐藏,并不是很直接的。有一些方法可以做到这一点,下面我们就来看看几种方案。



1.定时器
最直观,又是最无奈的一个方法就是使用定时器。既然我们在对话框开始显示之前不能用ShowWindow(SW_HIDE)将其隐藏,那就给一个时间让它显示,完了我们在隐藏它。

方法:

1.在OnInitDialog()函数里设置定时器:(WINDOWS API里面响应消息WM_INITDIALOG)

SetTimer(1, 1, NULL);

2.添加处理WM_TIMER的消息处理函数OnTimer,添加代码:

if(nIDEvent == 1)

{

DeleteTimer(1);

ShowWindow(SW_HIDE);

}

这种方法的缺点是显而易见的,使用定时器,使得程序的稳定性似乎打一个折扣;窗口是要先显示出来的,那么效果就是窗口闪了一下消失。



2.改变对话框显示状况
在对话框初始化时改变其显示属性可以让它隐藏起来。方法是调用SetWindowPlacement函数:



BOOL CDialogExDlg::OnInitDialog()

{

CDialog::OnInitDialog();

//DO something



WINDOWPLACEMENT wp;

wp.length=sizeof(WINDOWPLACEMENT);

wp.flags=WPF_RESTORETOMAXIMIZED;

wp.showCmd=SW_HIDE;

SetWindowPlacement(&wp);

return TRUE;

}

 

在需要显示时(通常是响应热键或者托盘图标的鼠标消息):



WINDOWPLACEMENT wp;

wp.length=sizeof(WINDOWPLACEMENT);

wp.flags=WPF_RESTORETOMAXIMIZED;

wp.showCmd=SW_SHOW;

SetWindowPlacement(&wp);



这样的效果很不理想:窗口显示在屏幕的左上角,并且是只有标题栏,要正常显示,还需加上如下代码:

定义一个成员变量CRect rect;

在OnInitDialog()里面:

GetWindowRect(&rect);

在需要显示的地方:

SetWindowPos(&wndNoTopMost, wndRc.left, wndRc.top, wndRc.right, wndRc.bottom, SWP_SHOWWINDOW);

CenterWindow();

即使这样,效果还是很差。

这种方法还有一个弊端是当程序开始运行并且隐藏起来后,原来激活的窗口变成了非激活状态了,而当对话框显示出来后,对话框自身也是非激活状态的。



3.不绘制窗口
当对话框显示时将要响应消息WM_PAINT绘制客户区,相应消息WM_NCPAINT绘制窗口边框。我们在窗口第一次自绘自身时隐藏窗口,可以收到比较良好的效果。由于窗口是先画窗口边框,所以我们仅需处理WM_NCPAINT即可。代码如下:

添加WM_NCPAINT处理函数。

void CMyDialog::OnNcPaint()

{

static int i = 2;

if(i > 0)

{

i --;

ShowWindow(SW_HIDE);

}

else

CDialog::OnNcPaint();

}

这里有个问题:为什么要定义静态变量i而且设其值为2呢?

我们只要窗口隐藏第一次,所以定义这个变量可以判断是否时首次显示窗口。当程序开始运行时,系统发送(SendMessage)WM_NCPAINT消息,此时程序的窗口边框应该被显示,但是此时我们没有作任何显示的操作,而是将窗口隐藏,ShowWindow(SW_HIDE)将把窗口的WS_VISIBLE属性去掉,继续执行,程序将检查WS_VISIBLE属性,如果没有则显示窗口,所以又发送了一个WM_NCPAINT消息。所以我们要处理两次WM_NCPAINT消息。

在需要窗口显示时,调用ShowWindow(SW_SHOW)即可。

程序执行的结果是,原来处于激活状态的窗口可能会闪动两下,然后仍然处于激活状态。这种处理方式比上面的方式要优越得多。



4.将对话框作为子窗口
这种方法是采用SDI框架,主窗口始终隐藏,对话框作为主窗口的成员变量,在CMainFrame::OnCreate()里面加入下代码:

if(!dlg.Create(IDD_MYDIALOG, this))

{

return –1;

}

dlg.ShowWindow(SW_HIDE);

在要显示对话框的地方用dlg.ShowWindow(SW_SHOW);即可。注意,主窗口一定要隐藏,否则对话框可能会闪现一下。
free_card 2003-08-20
  • 打赏
  • 举报
回复
要使一个基于 CDialog 的应用程序一开始便被隐藏的方法有好多种。大多数方法在相关文章(http://www.csdn.net/develop/article/11/11634.shtm)中已经提及。本人之所以要写这篇文章,主要是通过分析MFC 调用模式对话框的方法向大家展示一种简单,合理,完满的解决方案。

  首先,用MFC 生成的一个基于对话框的应用程序框架,然后修改对话框资源的Visible属性使之成为不可见(在属性页的MoreStyle中),接着按下F5 来运行这个程序,我们会发现,它并不象我们期望的那样一开始就被隐藏。而是被显示了出来。那么为什么会这样呢?特别是精通SDK的朋友们,会对此百思不得其解。

  其实,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(); // 声明为虚函数


希望MS能在以后的版本中考虑这个问题。
dennis80 2003-08-20
  • 打赏
  • 举报
回复
学习
wuxfBrave 2003-08-20
  • 打赏
  • 举报
回复
把对话框的WM_VISIBLE属性去掉就可以了啊,先显示再隐藏当然会闪了
sdc_sh 2003-08-20
  • 打赏
  • 举报
回复
这位兄弟可能还不知道我要做的是什么,或是因为我没说明白的原因,我是做一个控制程序,设置好以后就一直运行,做一些类似计划任务之类的工作。因此我觉得这样做可能是个比较好的选择。

还有我想问一下,有那位朋友知道: 别的在系统栏的程序退出时图标很快就消失了,我的为什么这么慢,要是把鼠标光标放在那里一下,倒是很快就会消失,不知是什么原因,有什么方法改进一下,先谢了
kinogre 2003-08-20
  • 打赏
  • 举报
回复
都搞的这么复杂,在OnInitDialog里加一句ShowWindow(SW_HIDE),然后调用基类初始化函数.
此文件分为2部分 part1 = http://download.csdn.net/source/2362571 含本书全部源码(1-16章) 共399个实例:第1章 窗体与界面设计  1.1 菜单应用实例  cc实例001 在系统菜单中添加菜单项  cc实例002 带图标的程序菜单   cc实例003 根据表中数据动态生成菜单  cc实例004 浮动的菜单  1.2 弹出菜单应用实例  cc实例005 在控件上单击右键弹出菜单  cc实例006 个性化的弹出菜单  cc实例007 任务栏托盘弹出菜单  1.3 工具栏应用实例  cc实例008 带背景的工具栏  cc实例 009 带图标的工具栏  cc实例010 带下拉菜单的工具栏  cc实例011 可调整按钮位置的工具栏  cc实例012 浮动工具栏  cc实例 013 根据表中数据动态生成工具栏  cc实例014 具有提示功能的工具栏  1.4 状态栏应用实例  cc实例015 带进度条的状态栏  cc 实例016 动画效果的状态栏  cc实例017 滚动字幕的状态栏  1.5 导航界面应用实例  cc实例018 Outlook导航界面  cc实例019 树状导航界面  cc实例020 按钮导航界面  cc实例021 类QQ导航菜单  1.6 界面窗体应用实例  cc实例022 背景为渐变色的程序界面  cc实例023 椭圆形的程序界面  cc实例024 自绘窗体界面  cc实例025 类似WindowscXP的程序界面  cc 实例026 窗体融合技术  cc实例027 限制对话框最大时的窗口大小  1.7 多媒体宣传光盘应用实例  cc实例028 多媒体宣传光盘主界面  cc实例029 自动运行的多媒体宣传光盘  1.8 多媒体触摸屏程序应用实例  cc实例030 采购中心多媒体触摸屏程序  cc实例031 为触摸屏程序添加虚拟键盘  1.9 窗体位置应用实例  cc实例032 不可移动的窗体  cc实例033 始终在最上面的窗体  cc实例034 动画显示窗体  cc实例035 以时钟显示界面窗体  1.10 窗体标题栏应用实例  cc实例036 闪烁的窗体标题栏  cc实例037 拖动没有标题栏的窗体  cc实例038 禁用标题栏上的最大化.c最小化或关闭按钮  1.11 窗体形状及应用  cc实例039 半透明窗体  cc实例 040 创建字型窗体  cc实例041 百叶窗窗体  cc实例042 类似Office助手 第2章 控件应用  2.1 按钮控件典型实例  cc 实例043 AVI动画按钮  cc实例044 GIF动画按钮  cc实例045 图文按钮  cc实例046 不规则按钮  2.2 EditBox 控件典型实例  cc实例047 为EditBox设置新的系统菜单  cc实例048 为EditBox控件添加列表选择框  cc实例049 多彩边框的编辑框  cc实例050 改变编辑框文本颜色  2.3 ListBox控件典型实例  cc实例051 利用ListBox控件实现标签式数据选择  cc实例052 在ListBox控件间实现数据交换  cc实例053 列表项的提示条  2.4 ComboBox控件典型实例  cc实例 054 将数据表中的字段添加到ComboBox控件  cc实例055 带查询功能的ComboBox控件  cc实例056 自动调整组合框的宽度  cc实例057 颜色组合框  cc实例058 多列显示的组合框  2.5 ListControl控件典型实例  cc实例059 将数据库中的数据表添加到ListControl控件  cc实例060 利用ListControl控件浏览数据  cc实例061 利用ListControl控件制作导航界面  cc实例062 在列表视图中拖动视图项  cc实例063 利用列标题对列表视图进行数据排序  cc实例064 具有文本录入功能的 ListControl控件  2.6 TreeControl控件典型实例  cc实例065 多级数据库树状结构数据显示  cc实例066 可动态修改节点的树状结构  cc实例067 带复选功能的树状结构  cc实例068 显示磁盘目录  cc实例069 树型提示框  2.7  RichEdit控件典型实例  cc实例070 利用RichEdit显示Word文档  cc实例071 利用RichEdit控件实现文字定位与标识  cc实例072 利用RichEdit控件显示图文数据  2.8 图形类控件典型实例  cc实例073 图文数据录入  cc实例074 带有滚动条的图形控件  2.9 滚动条控件典型实例  cc实例075 自定义滚动条控件  2.10 控件

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧