增加状态栏按钮及其它......

我正在写一个紧急情况警报程序,根据所收到的警报消息,我的程序必须能够停止屏幕保护程序或者节能模式并显示显示报警消息,当然也可以 在屏幕保护程序之上显示报警消息。我尝试了用 SetWindowPos(&wndTopMost...),结果不灵,在 Windows 2000 的屏保中也没有成功。我的程序要在 Windows 2000 里运行,请问如何在特定的事件发生时终止屏幕保护?

Jungkun

早期在 Windows 3.1 和 Windows 98 时代,你只需获取活动窗口,并且简简单单地发送一条 WM_CLOSE 消息即可:

1. PostMessage(GetActiveWindow(),WM_CLOSE,0,0);

是不是看来很简单?但在Windows 2000下,这个方法不再有效。Windows 2000 中有单独的桌面概念,所以,屏保程序是运行在一个名叫 Screeen-Saver 的特殊桌面中。使用 GetActiveWindow 或是 GetForegroundWindow 是找不到屏保的窗口的,因为它们运行在其他的桌面下。所以,你必须打开 该桌面,枚举它的窗口,然后发送 WM_CLOSE 消息给它。
有关细节参见 Figure 1。

我用 C++ 如何侦测屏幕的分辨率是 640X480 还是 600X800 ?

Amir Dashti
Tehran

只需简单地调用 GetSystemMetrics:

1. // width int cx = GetSystemMetrics(SM_CXSCREEN); 
2. // height int cy = GetSystemMetrics(SM_CYSCREEN);

GetSyStemMetrics 是一个很容易使用的函数,它可以用来获得各种类型的全局尺寸,象一个图标的大小或是窗口标题栏的高度。在Windows 2000中 ,有些像 SM_CXVIRTUALSCREEN 和 SM_CYVIRTUALSCREEN 这样的新参数,可以用了获得多监视器系统屏幕虚拟尺寸。无论作为一个 Windows 新丁还是一个老鸟,都应该仔细察看 GetSystemMetrics 的文档,学习所有你能获得不同的系统参数尺寸。详见最新的 Platform SDK 中的 GetSystemMetrics。 这个函数是你经常要用的一个函数,每一版的 Windows 中都有新的变化。

这可能是一个比较简单的问题,我想知道如何在某个应用程序的状态栏添加按钮,就像 Windows 快速启动栏里的按钮那样?

Guru India

我怎样才能在应用程序的状态栏上增加一个按钮或是一个编辑控件(带有上下键的),就象你在 1997 年 MSJ C++ Q&A 专栏中做的 VIRGIL 那样?

Jef Pavlat

状态栏是基于 Windows 通用控件 msctls_statusbar32,这个通用控件并不提供任何方法来添加子窗口。这是不是意味着我们就没有办法解决上面提出的问题呢?当然不!在 Windows 中,在 某些控件或是窗口中添加子窗口并不是将它们作为这些控件的子窗口,而是作为这些控件的兄弟窗口。在现在这种情况下,你有两个选择:一是建立一个“超级状态栏“,它包含一个普通状态栏 以及其它控件子窗口(就像 Windows 结合列表框和编辑框而合成的组合框一样);第二、你也可以直接将按钮或是其它控件直接加在主框架上,就像是状态栏,工具栏 或视图的兄弟窗口一样。

至于决定使用那种方法取决于你的设计有多复杂以及你的规划。如果你想加很多的控件, 和/或在其它的窗口或应用程序中重用组合的状态栏/按钮/编辑控制的话,那么最好建立一个复合控件。如果仅仅是想 在某个窗口中添加单个按钮,那么最好是将它添加到主框架。无论你使用哪种方法,你都需要写一点代码来定位你的控件,使 之与其它相邻的控件在合适的位置上。

我写了一个小的示例程序,StatBarButn(见 Figure 2)。

Figure 2 状态栏按钮

所有的动作都发生在 CMainFrame 中,参见 Figure 3。CMainFrame 有一个数据成员来 代表按钮(参见 Figure 4)。这些代码被压缩状态栏, 用按钮填充被压缩出的空间。由于我们将按钮的 ID 设置成为 ID_APP_ABOUT,与 HELP 菜单中的 About (Help | About)菜单命令相同,所以在连接按钮到其命令处理函数时不用做任何事。自然,如果你想使用其它命令,你 就必须为它设置一个 ID 并使用它。

StatBarButn 使用默认的字体;如果你想在一个实际的程序中使用的话,你应当使用SystemParamtersInfo(SPI_GETNONCLIENTMETRICS) 获得当前 的消息或菜单字体。

Figure 5 去掉调整窗口大小的手柄

当我刚开始写这个 StatBarButn 程序时,我在做到 如 Figure 5 所示的那样时就结束了。注意到按钮左边调整窗口大小的手柄了吗!这是个问题。为了摆脱这个把手,你必须建立一个没有 SBARS_SIZEGRIP 风格的状态栏。 可是,在状态栏建立以后再把这个风格去掉是没有用的。因为 Windows 只会在建立状态栏时才会去认这个风格。MFC 提供 CStatusBar::Create 使你能够传送你自己的风格参数,但是 MFC 包含如下的硬代码(写死的)行:

1. // in CStatusBar::CreateEx
2. if (pParentWnd->GetStyle() & WS_THICKFRAME)
3.   dwStyle |= SBARS_SIZEGRIP;
4. dwStyle |= dwCtrlStyle;
5. return CWnd::Create(... dwStyle ...);

这意味着如果你的主框架有 WS_THICKFRAME 风格(就是普通的框架窗口),MFC 会坚持为状态栏设置 SBARS_SIZEGRIP 风格。怎么办?

一个合适的方法是派生一个新的类,CMyStatusBar,重写自己的 Create 函数,并且不使用 SBAR_SIZEGRIP 风格。但是不用那么复杂,用下面简简单单的几行代码也达到了相同的目的:

1. // 关闭 WS_THICKFRAME 
2. ModifyStyle(WS_THICKFRAME,0);
3. m_wndStatusBar.Create(this); // 执行完这一行之后再打开 WS_THICKFRAME 
4. ModifyStyle(0,WS_THICKFRAME);

这样使 MFC 以为框架没有厚边框,所以它关闭了SBARS_SIZEGRIP,从而状态栏的手柄被隐藏。这个方法虽然很业余,但效果不错。

那如果你又需要这个大小拖拉把手呢?在这种情况下,我认为最简单的方法是实现一个有两个子状态栏的组合状态栏,任意一个都在你的按钮或是随便什么其它控件的左边或是右边。然后,在左边的那个子状态栏没有拖拉把手,而右边的那个子状态栏只剩下拖拉把手。老实说,如果你把状态栏作为其 它什么新窗口的子窗口,而不是主框架的子窗口,我怀疑它是否能正常工作;你可能必须自己重新跟踪消息循环并改写父窗口。如果,你真得在家这么做了,请让我知道。

还有一个细节是必须要做的,否则事情就不完美,如果用户隐藏了状态栏,会导致什么?没错!正如你预料,按钮还是会在。为了让按钮随状态栏一同隐藏,你必须在 ID_VIEW_STATUS_BAR 的处理函数中增加一些代码,Figure 3 显示了 具体处理细节。

如果你真的想去跟踪一个组合状态栏,你必须先把状态栏,按钮和其它一些控件作为一个新的窗口类的子窗口,并在处理OnSize 消息时,将他们放在正确的位置上。而对于主框架来讲,重 新计算窗口位置是 MFC 的一项特权。如果你的按钮或是其它的什么控件比状态栏窗口小的话,你必须写一点代码在你的组合状态栏中,使得子窗口中间的空白被重画。你可以在处理WM_ERASEBKGND 做这项工作,或者在注册你的窗口类时,简单的把背景刷子设置成合适的系统颜色(例如:COLOR_3DFACE)。最后,你还得重载 OnCmdMsg 消息函数,使得消息能够发往父窗口。

你可能感兴趣的:(MFC/VC++)