原文轉自 http://blog.csdn.net/wwkaven/article/details/32710759
本文介紹如何實現類似QQ的自動隱藏功能,具體的講,就是當窗口停靠在屏幕邊緣並且鼠標離開窗口時,窗口自動隱藏,但是會留有一小截窗口不隱藏。當鼠標移回這一小截不隱藏的窗口時,窗口自動彈出。這里所謂的隱藏,並不是窗口直接不見了,而是窗口被移動至屏幕外,留下的一小截也就是未移出屏幕的部分。另一點,動態的隱藏,其實是多次調用MoveWindow函數向一個方向移動窗口至屏幕外的結果。下面是具體實現:
1、創建基於對話框的工程,編寫實現窗口自動隱藏的函數AutoHiddenWindow(int margin)。因為要留出的“一小截”不好確定,可能有不同的需求,所以添加一個margin參數,表示隱藏后露出的那一小截的寬度(單位為像素)。上文講了,要實現動態效果,就要多次調用MoveWindow函數,這里將每次移動的距離定為1個像素。那么要移動的次數也就是要移動的距離了。而要移動的距離即為窗口的高度(上下兩個方向)或寬度(左右兩個方向)減去留出的邊距margin。下面是具體的函數實現:
void AutoHiddenDlg::AutoHiddenWindow(int margin) { // 獲取屏幕寬度 int screenWidth = GetSystemMetrics(SM_CXSCREEN); // 獲取屏幕高度 int screenHeight = GetSystemMetrics(SM_CYSCREEN); CRect rect; GetWindowRect(&rect); // 向左收縮 while (rect.left <= 0 && rect.right >= margin) { // 獲取窗口范圍 GetWindowRect(&rect); // 移動窗口 MoveWindow(rect.left - 1, rect.top, rect.Width(), rect.Height(), FALSE); } // 向上收縮 while (rect.top <= 0 && rect.bottom >= margin) { // 獲取窗口范圍 GetWindowRect(&rect); // 移動窗口 MoveWindow(rect.left, rect.top - 1, rect.Width(), rect.Height(), FALSE); } // 向右收縮 while (rect.right >= screenWidth && rect.left <= screenWidth - margin) { // 獲取窗口范圍 GetWindowRect(&rect); // 移動窗口 MoveWindow(rect.left + 1, rect.top, rect.Width(), rect.Height(), FALSE); } // 向下收縮 while (rect.bottom >= screenHeight && rect.top <= screenHeight - margin) { // 獲取窗口范圍 GetWindowRect(&rect); // 移動窗口 MoveWindow(rect.left, rect.top + 1, rect.Width(), rect.Height(), FALSE); } }
上面在判斷隱藏的方向時是根據水平或垂直方向上的兩個坐標來確定的。rect變量保存了窗口的位置,具體的講是窗口左上角的坐標(rect.left,rect.top)以及窗口右下角的坐標(rect.right,rect.bottom),當rect.left, rect.top,rect.right, rect.bottom的值為0時,那么就可以確定窗口貼緊了屏幕的哪一邊。由上可知,窗口可能同時貼緊兩個邊,這時根據上述函數,會同時向兩個方向移動,最后留下的自繪剩下一個角。其實,這樣的效果也不錯。如果確實只想其向某一邊隱藏,加個判斷語句就行了。附上幾張圖:
窗口停靠在屏幕上側后隱藏

窗口停靠在屏幕右側后隱藏
窗口同時停靠在屏幕上側和右側后隱藏
2、自動彈出窗口的函數,總的來說,就是自動隱藏函數的反過程。需要注意一點,彈出后要保證窗口仍在隱藏前的位置,即緊靠屏幕的某一側。這樣,鼠標再次離開時,窗口仍能自動隱藏。下面是具體函數實現:
void AutoHiddenDlg::AutoShowWindow() { // 獲取屏幕寬度 int screenWidth = GetSystemMetrics(SM_CXSCREEN); // 獲取屏幕高度 int screenHeight = GetSystemMetrics(SM_CYSCREEN); CRect rect; GetWindowRect(&rect); // 向右彈出 while (rect.left < 0) { // 移動窗口 MoveWindow(rect.left + 1, rect.top, rect.Width(), rect.Height(), FALSE); // 獲取窗口范圍 GetWindowRect(&rect); } // 向下彈出 while (rect.top < 0) { // 移動窗口 MoveWindow(rect.left, rect.top + 1, rect.Width(), rect.Height(), FALSE); // 獲取窗口范圍 GetWindowRect(&rect); } // 向左彈出 while (rect.right > screenWidth) { // 移動窗口 MoveWindow(rect.left - 1, rect.top, rect.Width(), rect.Height(), FALSE); // 獲取窗口范圍 GetWindowRect(&rect); } // 向上彈出 while (rect.bottom > screenHeight) { // 移動窗口 MoveWindow(rect.left, rect.top - 1, rect.Width(), rect.Height(), FALSE); // 獲取窗口范圍 GetWindowRect(&rect); } }
3、另外,還需要一個判斷鼠標是否離開窗口的函數JudgeCursorOut:
bool AutoHiddenDlg::JudgeCursorOut() { // 獲取鼠標位置 POINT point; GetCursorPos(&point); // 獲取窗口范圍 CRect rect; GetWindowRect(&rect); // 判斷 if (point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom) { return false; // 鼠標還在窗口內 } else { return true; // 鼠標離開窗口 } }
4、添加消息WM_TIMER的響應函數OnTimer,在其中調用上述函數實現如題功能:
void AutoHiddenDlg::OnTimer(UINT_PTR nIDEvent) { if (AUTO_HIDDEN_WINDOW_DLG_TIMER1 == nIDEvent) { if (JudgeCursorOut()) { AutoHiddenWindow(10); // 如果鼠標離開窗口,窗口自動隱藏 } else { AutoShowWindow(); // 鼠標移入窗口,窗口自動顯示 } } CDialogEx::OnTimer(nIDEvent); }
5、最后,在窗口初始化函數中添加一個計時器就行了:
#define AUTO_HIDDEN_WINDOW_DLG_TIMER1 1 BOOL AutoHiddenDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 啟動計時器 SetTimer(AUTO_HIDDEN_WINDOW_DLG_TIMER1, 500, NULL); return TRUE; // return TRUE unless you set the focus to a control // 異常: OCX 屬性頁應返回 FALSE }
至此,功能實現,當然還有很多不足之處,但是這里主要介紹隱藏和顯示兩個函數。
另附上述示例源代碼:http://download.csdn.net/detail/wwkaven/7527013