懸浮窗口應該具有的特性
為了實現讓用戶能方便打開軟件主窗口,又不對用戶界面造成明顯的視覺干擾,懸浮窗口應該有以下特點:
- 和主窗口是二選一的關系,主窗口顯示時自動隱藏,主窗口被全部遮擋時自動顯示
- 始終置前,不被其它窗口遮擋,全屏播放電影、截圖軟件截圖等情形時,取消置前。
- 支持全窗口拖動
- 半透明效果,鼠標移上時全為不透明
- 為了使隱藏和出現不顯得突兀,支持淡入淡出效果
- 點擊懸浮窗時,呼出主窗口,並隱藏懸浮窗口
上述特點的實現方案
整個實現方案依賴於主窗口內的一個定時器(200ms),定時檢查主窗口的顯示狀態以及懸浮窗口的頂置屬性。
和主窗口是二選一的關系,主窗口顯示時自動隱藏,主窗口被全部遮擋時自動顯示
與主窗口二選一的顯示,是通過定時檢查主窗口的顯示狀態,來設置是否顯示懸浮窗口。
如果主窗口未隱藏,並且沒有被其它窗口完全遮擋(可以是一個或者多個窗口的組合),懸浮窗口不顯示。
IsEntirelyCovered(HWND hWnd)(http://blog.csdn.net/harbinzju/article/details/6781646)函數可以判斷一個窗口,是否被完全遮擋住,可能是被一個或者多個窗口遮擋。
實現思路:向上找到Z-Order大於目標窗口的窗口,將這些窗口逐一拼接,每拼接一個窗口后,判斷一下目標窗口是不是被這個拼接后的區域覆蓋。
這里用到的CRgn來自WTL的atlgdi.h,MFC中也有相似的類,都是對API的一個封裝。
始終置前,不被其它窗口遮擋,全屏播放電影、截圖軟件截圖等情形時,取消置前。
這個功能的實現同樣依賴於主窗口的定時器,當定時器觸發時,發現主窗口未顯示,會調用懸浮窗的顯示窗口方法,這里會重新設置置前屬性。
在設置置屬性之前,要判斷是否有其它全屏的置前窗口遮擋了懸浮窗,如果有,不再去搶置前。這樣就可以避免與截圖和全屏播放電影沖突。
實現思路:向上找到Z-Order大於懸浮窗口的窗口,判斷這個窗口是否為全屏。
IsFullScreen(HWND hWnd)函數可以判斷窗口是否為全屏。
BOOL IsFullScreen(HWND hWnd)
{
if (hWnd == NULL)
{
return FALSE;
}
if (!::IsWindowVisible(hWnd))
{
return FALSE;
}
int nScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
CRect rcWnd;
GetWindowRect(hWnd, &rcWnd);
if (rcWnd.top == 0 && rcWnd.left == 0
&& rcWnd.Width() == nScreenWidth
&& rcWnd.Height() == nScreenHeight)
{
return TRUE;
}
return FALSE;
}
支持全窗口拖動
窗口響應WM_NCHITTEST消息,固定返回HTCAPTION。
半透明效果,鼠標移上時全為不透明
設置WS_EX_LAYERED屬性,使用UpdateLayeredWindow來繪制窗口。因為懸浮窗口一般比較簡單,沒有復雜的控件,甚至沒有控件,所以此方案比較簡單可行。
當鼠標移入和移出時,調用SetLayeredWindowAttributes來改變懸浮窗的透明度。
為了使隱藏和出現不顯得突兀,支持淡入淡出效果
實現思路:開始淡入\淡出時,啟動定時器(30ms),定期增加\減少窗口透明度,當增加至1(或者預設的最大透明度)\減小到0時,停止定時器。
http://blog.csdn.net/harbinzju/article/details/7022882
