完成窗體自動(dòng)隱藏
發(fā)表時(shí)間:2024-06-08 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]最近寫個(gè)小程序,想讓窗體自動(dòng)隱藏,到csdn搜索,發(fā)現(xiàn)不少網(wǎng)友問這個(gè)問題,可是具體實(shí)現(xiàn)的例子不多,我經(jīng)過琢磨,實(shí)現(xiàn)可記錄停靠位置,可左上右三方?坎㈦[藏。現(xiàn)將實(shí)現(xiàn)的例子拿出來供大家參考。 實(shí)現(xiàn)窗體自動(dòng)隱藏方法有多種,可以使用定時(shí)器,不斷監(jiān)視鼠標(biāo),當(dāng)鼠標(biāo)移動(dòng)到窗體邊緣時(shí),顯示窗體,當(dāng)鼠標(biāo)離開后隱藏窗...
最近寫個(gè)小程序,想讓窗體自動(dòng)隱藏,到csdn搜索,發(fā)現(xiàn)不少網(wǎng)友問這個(gè)問題,可是具體實(shí)現(xiàn)的例子不多,我經(jīng)過琢磨,實(shí)現(xiàn)可記錄?课恢,可左上右三方?坎㈦[藏。現(xiàn)將實(shí)現(xiàn)的例子拿出來供大家參考。
實(shí)現(xiàn)窗體自動(dòng)隱藏方法有多種,可以使用定時(shí)器,不斷監(jiān)視鼠標(biāo),當(dāng)鼠標(biāo)移動(dòng)到窗體邊緣時(shí),顯示窗體,當(dāng)鼠標(biāo)離開后隱藏窗體。也可以在鼠標(biāo)收到WM_NCMOUSEMOVE或 WM_MOUSEMOVE(無邊框窗體)時(shí)激活窗體,然后在窗體消息WM_ACTIVE中設(shè)置顯示或隱藏,這種方法在窗體未失去焦點(diǎn)時(shí)不會(huì)隱藏。我在原本的設(shè)計(jì)中便使用這種方法,只是在設(shè)計(jì)時(shí)發(fā)現(xiàn)非主窗體不太合適,激活窗體時(shí)會(huì)出現(xiàn)兩個(gè)鍵盤焦點(diǎn),而且我所需要的焦點(diǎn)是虛假的,可能我的設(shè)計(jì)不當(dāng),那位朋友若能完美實(shí)現(xiàn),不妨交流一下。
本代碼的流程如下:
1. 初始化窗體時(shí)設(shè)置窗體位置,并設(shè)置依靠狀態(tài)窗體狀態(tài)。
2. 當(dāng)接收到WM_MOUSEMOVE消息時(shí),檢查窗體是否顯示,若否,顯示,并打開定時(shí)器。
3. 在WM_MOVING中檢測(cè)窗體位置,并自動(dòng)靠攏邊界。
4. 在定時(shí)器中檢測(cè)鼠標(biāo),當(dāng)鼠標(biāo)離開窗體后,關(guān)閉定時(shí)器,隱藏窗體。
當(dāng)然,在隱藏窗體時(shí)首先判斷位置,若?吭谶吘墸瑒t隱藏,否則,不隱藏。
現(xiàn)在我們一步步看代碼。
int alignType; //全局變量,用于記錄窗體?繝顟B(tài)
enum
{
ALIGN_NONE, //不?
ALIGN_TOP, //?可线
ALIGN_LEFT, //停靠左邊
ALIGN_RIGHT //?坑疫
};
#define NEAR_SIZE 20 //定義自動(dòng)?坑行Ь嚯x
#define NEAR_SIDE 2 //窗體隱藏后在屏幕上保留的像素,以使鼠標(biāo)可以觸及
/*
下面代碼處理窗體消息WM_MOVING,pRect是由參數(shù)lParam傳來的指針
*/
void OnMoving(HWND hWnd, LPRECT pRect)
{
//未靠邊界由pRect測(cè)試
if (alignType == ALIGN_NONE)
{
if (pRect->top < NEAR_SIZE) //在上邊有效距離內(nèi),自動(dòng)靠攏。
{
alignType = ALIGN_TOP;
pRect->bottom -= pRect->top;
pRect->top = 0;
}
if (pRect->left < NEAR_SIZE) //在左邊有效距離內(nèi)
{
alignType = ALIGN_LEFT;
pRect->right -= pRect->left;
pRect->left = 0;
}
else if (pRect->right + NEAR_SIZE > ScreenX) //在右邊有效距離內(nèi),ScreenX為屏幕寬度,可由GetSystemMetrics(SM_CYSCREEN)得到。
{
alignType = ALIGN_RIGHT;
pRect->left += (ScreenX - pRect->right);
pRect->right = ScreenX;
}
}
else
{
//靠邊界由鼠標(biāo)測(cè)試
POINT pt;
GetCursorPos(&pt);
if (alignType == ALIGN_TOP)
{
if (pt.y > NEAR_SIZE) //由于我們移動(dòng)窗體時(shí),鼠標(biāo)在標(biāo)題欄內(nèi),當(dāng)鼠標(biāo)位置超過有效距離后,我們可以考慮用戶要向下拖動(dòng)鼠標(biāo)。我們便解除上部?。
{
alignType = ALIGN_NONE;
pRect->bottom += NEAR_SIZE;
pRect->top = NEAR_SIZE;
}
else
{
pRect->bottom -= pRect->top;
pRect->top = 0;
if (pRect->left < NEAR_SIZE) //在上部停靠時(shí),我們也考慮左右邊角。
{
pRect->right -= pRect->left;
pRect->left = 0;
}
else if (pRect->right + NEAR_SIZE > ScreenX)
{
pRect->left += (ScreenX - pRect->right);
pRect->right = ScreenX;
}
}
}
if (alignType == ALIGN_LEFT)
{
if (pt.x - pRect->right > 0) //鼠標(biāo)可以在整個(gè)標(biāo)題條來回移動(dòng),所以我們不能簡(jiǎn)單用左邊界和鼠標(biāo)的距離來解除?浚@里我們?cè)谑髽?biāo)離開右邊界時(shí)解除?俊
{
alignType = ALIGN_NONE;
pRect->right += NEAR_SIZE;
pRect->left = NEAR_SIZE;
}
else
{
pRect->right -= pRect->left;
pRect->left = 0;
if (pRect->top < NEAR_SIZE) //考慮左上角。
{
pRect->bottom -= pRect->top;
pRect->top = 0;
}
}
}
else if (alignType == ALIGN_RIGHT)
{
if (pt.x < pRect->left) //當(dāng)鼠標(biāo)離開左邊界時(shí),解除?俊
{
alignType = ALIGN_NONE;
pRect->left -= NEAR_SIZE;
pRect->right -= NEAR_SIZE;
}
else
{
pRect->left += (ScreenX - pRect->right);
pRect->right = ScreenX;
if (pRect->top < NEAR_SIZE) //考慮右上角。
{
pRect->bottom -= pRect->top;
pRect->top = 0;
}
}
}
}
}
/*
在窗體初始化是設(shè)定窗體狀態(tài),如果可以?,便?吭谶吘
我本想尋求其他方法來解決初始化,而不是為它專一尋求一個(gè)函數(shù),可是,窗體初始化時(shí)不發(fā)送WM_MOVING消息,我不得不重復(fù)類似任務(wù).
*/
void NearSide(HWND hWnd)
{
int change = 0;
RECT rect;
GetWindowRect(hWnd, &rect);
alignType = ALIGN_NONE;
if (rect.left < NEAR_SIZE)
{
alignType = ALIGN_LEFT;
if ((rect.left != 0) && rect.right != NEAR_SIDE)
{
rect.right -= rect.left;
rect.left = 0;
change = 1;
}
}
else if (rect.right > ScreenX - NEAR_SIZE)
{
alignType = ALIGN_RIGHT;
if (rect.right != ScreenX && rect.left != ScreenX - NEAR_SIDE)
{
rect.left += (ScreenX - rect.right);
rect.right = ScreenX;
change = 1;
}
}
//調(diào)整上
else if (rect.top < NEAR_SIZE)
{
alignType = ALIGN_TOP;
if (rect.top != 0 && rect.bottom != NEAR_SIDE)
{
rect.bottom -= rect.top;
rect.top = 0;
change = 1;
}
}
if (change)
{
MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
}
}
/*
窗體的顯示隱藏由該函數(shù)完成,參數(shù)hide決定顯示還是隱藏.
*/
void HideSide(HWND hWnd, BOOL hide)
{
RECT rc;
int moves = 20; //動(dòng)畫滾動(dòng)窗體的步數(shù),如果你覺得不夠平滑,可以增大該值.
int xStep, yStep;
int xEnd, yEnd;
int width;
int height;
register int i;
GetWindowRect(hWnd, &rc);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
//下邊判斷窗體該如何移動(dòng),由停靠方式?jīng)Q定
switch (alignType)
{
case ALIGN_TOP:
{
//向上移藏
xStep = 0;
xEnd = rc.left;
if (hide)
{
yStep = -rc.bottom / moves;
yEnd = -height + NEAR_SIDE;
}
else
{
yStep = -rc.top / moves;
yEnd = 0;
}
break;
}
case ALIGN_LEFT:
{
//向左移藏
yStep = 0;
yEnd = rc.top;
if (hide)
{
xStep = -rc.right / moves;
xEnd = -width + NEAR_SIDE;
}
else
{
xStep = -rc.left / moves;
xEnd = 0;
}
break;
}
case ALIGN_RIGHT:
{
//向右移藏
yStep = 0;
yEnd = rc.top;
if (hide)
{
xStep = (ScreenX - rc.left) / moves;
xEnd = ScreenX - NEAR_SIDE;
}
else
{
xStep = (ScreenX - rc.right) / moves;
xEnd = ScreenX - width;
}
break;
}
default:
return;
}
//動(dòng)畫滾動(dòng)窗體.
for (i = 0; i < moves; i++)
{
rc.left += xStep;
rc.top += yStep;
SetWindowPos(hWnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE SWP_NOSENDCHANGING);
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE RDW_UPDATENOW);
Sleep(5);
}
SetWindowPos(hWnd, NULL, xEnd, yEnd, 0, 0, SWP_NOSIZE);
if (!hide) //如果窗體已被顯示,設(shè)置定時(shí)器.監(jiān)視鼠標(biāo).
{
SetTimer(hWnd, WM_TIMER, 500, NULL);
}
}
//下面就是通過窗體回調(diào)函數(shù)將這些函數(shù)組織起來.
//這里僅列出使用的消息
case WM_TIMER: //定時(shí)器消息
{
POINT pt;
RECT rc;
GetCursorPos(&pt);
GetWindowRect(hWnd, &rc);
if (!PtInRect(&rc, pt)) //若鼠標(biāo)不在窗體內(nèi),隱藏窗體.
{
KillTimer(hWnd, WM_TIMER);
HideSide(hWnd, TRUE);
}
break;
}
case WM_CREATE:
case WM_INITDIALOG: //初始化消息
{
SetWindowPos(...) //程序保存窗體上次靠位置,在這里恢復(fù).
NearSide(hWnd);
break;
}
//這兩個(gè)消息是在窗體移動(dòng)開始時(shí)和結(jié)束時(shí)產(chǎn)生的,我們?cè)诖绑w開始移動(dòng)時(shí)關(guān)閉定時(shí)器,移動(dòng)結(jié)束后再打開,這樣避免窗體移動(dòng)時(shí)隱藏,金山快譯的浮動(dòng)條就有這種情況出現(xiàn).
case WM_ENTERSIZEMOVE:
{
KillTimer(hWnd, WM_TIMER);
break;
}
case WM_EXITSIZEMOVE:
{
SetTimer(hWnd, WM_TIMER, 500, NULL);
break;
}
case WM_MOUSEMOVE: //受到窗體移動(dòng)消息時(shí),判斷窗體是否顯示,
{
RECT rc;
GetWindowRect(hWnd, &rc);
if (rc.left < 0 rc.top < 0 rc.right > ScreenX) //未顯示
HideSide(hWnd, FALSE);
break;
}
case WM_MOVING: //處理窗體移動(dòng)時(shí)消息,實(shí)現(xiàn)自動(dòng)?
{
OnMoving(hWnd, (LPRECT) lParam);
break;
}
case WM_MOVE:
{
//保存窗體位置
}
這些代碼是從我的程序中摘錄出來的, 我已盡量檢查它們的完整性, 但人總有犯錯(cuò)的時(shí)候, 如果你發(fā)現(xiàn)這些代碼有問題, 或有更好的建議, 請(qǐng)聯(lián)系我, 我的E-Mail:ggg82@sina.com