我正在寫一個緊急情況警報程序,根據所收到的警報消息,我的程序必須能夠停止屏幕保護程序或者節能模式並顯示顯示報警消息,當然也可以 在屏幕保護程序之上顯示報警消息。我嘗試了用 SetWindowPos(&wndTopMost...),結果不靈,在 Windows 2000 的屏保中也沒有成功。我的程序要在 Windows 2000 裡運行,請問如何在特定的事件發生時終止屏幕保護?
Jungkun
早期在 Windows 3.1 和 Windows 98 時代,你只需獲取活動窗口,並且簡簡單單地發送一條 WM_CLOSE 消息即可:
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:
// width int cx = GetSystemMetrics(SM_CXSCREEN);
// 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 包含如下的硬代碼(寫死的)行:
// in CStatusBar::CreateEx
if (pParentWnd->GetStyle() & WS_THICKFRAME)
dwStyle |= SBARS_SIZEGRIP;
dwStyle |= dwCtrlStyle;
return CWnd::Create(... dwStyle ...);
這意味著如果你的主框架有 WS_THICKFRAME 風格(就是普通的框架窗口),MFC 會堅持為狀態欄設置 SBARS_SIZEGRIP 風格。怎麼辦?
一個合適的方法是派生一個新的類,CMyStatusBar,重寫自己的 Create 函數,並且不使用 SBAR_SIZEGRIP 風格。但是不用那麼復雜,用下面簡簡單單的幾行代碼也達到了相同的目的:
// 關閉 WS_THICKFRAME
ModifyStyle(WS_THICKFRAME,0);
m_wndStatusBar.Create(this); // 執行完這一行之後再打開 WS_THICKFRAME
ModifyStyle(0,WS_THICKFRAME);
這樣使 MFC 以為框架沒有厚邊框,所以它關閉了SBARS_SIZEGRIP,從而狀態欄的手柄被隱藏。這個方法雖然很業余,但效果不錯。
那如果你又需要這個大小拖拉把手呢?在這種情況下,我認為最簡單的方法是實現一個有兩個子狀態欄的組合狀態欄,任意一個都在你的按鈕或是隨便什麼其它控件的左邊或是右邊。然後,在左邊的那個子狀態欄沒有拖拉把手,而右邊的那個子狀態欄只剩下拖拉把手。老實說,如果你把狀態欄作為其 它什麼新窗口的子窗口,而不是主框架的子窗口,我懷疑它是否能正常工作;你可能必須自己重新跟蹤消息循環並改寫父窗口。如果,你真得在家這麼做了,請讓我知道。
還有一個細節是必須要做的,否則事情就不完美,如果用戶隱藏了狀態欄,會導致什麼?沒錯!正如你預料,按鈕還是會在。為了讓按鈕隨狀態欄一同隱藏,你必須在 ID_VIEW_STATUS_BAR 的處理函數中增加一些代碼,Figure 3 顯示了 具體處理細節。
如果你真的想去跟蹤一個組合狀態欄,你必須先把狀態欄,按鈕和其它一些控件作為一個新的窗口類的子窗口,並在處理OnSize 消息時,將他們放在正確的位置上。而對於主框架來講,重 新計算窗口位置是 MFC 的一項特權。如果你的按鈕或是其它的什麼控件比狀態欄窗口小的話,你必須寫一點代碼在你的組合狀態欄中,使得子窗口中間的空白被重畫。你可以在處理WM_ERASEBKGND 做這項工作,或者在注冊你的窗口類時,簡單的把背景刷子設置成合適的系統顏色(例如:COLOR_3DFACE)。最後,你還得重載 OnCmdMsg 消息函數,使得消息能夠發往父窗口。
使用 [email protected] 發送你的問題和評論給 Paul
作者簡介
Paul DiLascia 是一個自由作家,顧問和 Web/UI 方面資深的設計師。他是 Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992)一書的作者。你可以在 http://www.dilascia.com 網站和 Paul 聯系上。