在VC中如何是应用程序窗口自动隐藏!!! 当鼠标位置到窗口边缘某区域内,SHOWWINDOW(SW_HIDE) 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 最简单的是使用FindWindow,跟据窗口类类名或窗口标题名联系。不过也可使用其它通信手段,如命名事件,共享内存等。 enum { ALIGN_NONE, ALIGN_TOP, ALIGN_LEFT, ALIGN_RIGHT};void C***Dlg::hideWindow(BOOL hide){ CRect rc; GetWindowRect(rc); int moves = 20; int xStep, yStep; int xEnd, yEnd; int cxScreen; switch (alignType) { case ALIGN_TOP: xStep = 0; xEnd = rc.left; if (hide) { yStep = -rc.bottom / moves; yEnd = -rc.Height() + 2; } else { yStep = -rc.top / moves; yEnd = 0; } break; case ALIGN_LEFT: yStep = 0; yEnd = rc.top; if (hide) { xStep = -rc.right / moves; xEnd = -rc.Width() + 2; } else { xStep = -rc.left / moves; xEnd = 0; } break; case ALIGN_RIGHT: yStep = 0; yEnd = rc.top; cxScreen = GetSystemMetrics(SM_CXSCREEN); if (hide) { xStep = (cxScreen - rc.left) / moves; xEnd = cxScreen - 2; } else { xStep = (cxScreen - rc.right) / moves; xEnd = cxScreen - rc.Width(); } break; }/* for (int i = 0; i < moves; i++) { rc.left += xStep; rc.top += yStep; SetWindowPos(NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING); RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN); Sleep(20); }*/ SetWindowPos(NULL, xEnd, yEnd, 0, 0, SWP_NOSIZE); isHide = hide; if (!isHide) SetTimer(IDT_HOVER, 50, NULL);}UINT C***Dlg::OnNcHitTest(CPoint point) { UINT res = CDialog::OnNcHitTest(point); if (res == HTCLIENT) return HTCAPTION;// TRACE("OnNcHitTest point=%d %d. res=%d ,alignType=%d\n",point.x,point.y ,res,alignType); switch (alignType) { case ALIGN_TOP: if (res == HTLEFT || res == HTRIGHT || res == HTTOP || res == HTTOPLEFT || res == HTTOPRIGHT) // res = HTERROR; // else if (res == HTBOTTOMLEFT || res == HTBOTTOMRIGHT) res = HTBOTTOM; // if (isHide && res == HTBOTTOM) hideWindow(FALSE); break; case ALIGN_LEFT: if (res == HTTOP || res == HTBOTTOM || res == HTLEFT || res == HTTOPLEFT || res == HTBOTTOMLEFT) // res = HTERROR; // else if (res == HTTOPRIGHT || res == HTBOTTOMRIGHT) res = HTRIGHT; if (isHide && res == HTRIGHT) hideWindow(FALSE); break; case ALIGN_RIGHT: if (res == HTTOP || res == HTBOTTOM || res == HTRIGHT || res == HTTOPRIGHT || res == HTBOTTOMRIGHT) // res = HTERROR; // else if (res == HTTOPLEFT || res == HTBOTTOMLEFT) res = HTLEFT; if (isHide && res == HTLEFT) hideWindow(FALSE); break; } return res;}void C***Dlg::OnTimer(UINT nIDEvent) { if (nIDEvent == IDT_HOVER) { CPoint pt; GetCursorPos(&pt); CRect rc; GetWindowRect(rc); rc.InflateRect(10, 10); if (!rc.PtInRect(pt)) { KillTimer(nIDEvent); hideWindow(); } } ****}void C***Dlg::OnMoving(UINT fwSide, LPRECT pRect) { CRect rcOld, rcWorkArea; CPoint pt; GetWindowRect(rcOld); SystemParametersInfo(SPI_GETWORKAREA, 0, rcWorkArea, 0); GetCursorPos(&pt); int cxScreen = GetSystemMetrics(SM_CXSCREEN); if (alignType == ALIGN_NONE) { if (pt.y - rcWorkArea.top < 20) { alignType = ALIGN_TOP; pRect->top = 0; } else if (pt.x - rcWorkArea.left < 20) { alignType = ALIGN_LEFT; pRect->left = 0; winNormalSize = rcOld.Size(); } else if (rcWorkArea.right - pt.x < 20) { alignType = ALIGN_RIGHT; pRect->right = cxScreen; winNormalSize = rcOld.Size(); } if (alignType != ALIGN_NONE) SetTimer(IDT_HOVER, 50, NULL); } if (alignType == ALIGN_TOP) { if (pRect->top > 0) alignType = ALIGN_NONE; else { pRect->top = 0; pRect->bottom = rcOld.Height(); } } else if (alignType == ALIGN_LEFT) { if (pRect->left > 0) { pRect->right = pRect->left + winNormalSize.cx; pRect->bottom = pRect->top + winNormalSize.cy; alignType = ALIGN_NONE; } else { pRect->left = 0; pRect->right = rcOld.Width(); pRect->top = 0; pRect->bottom = rcWorkArea.bottom; } } else if (alignType == ALIGN_RIGHT) { if (pRect->right < cxScreen) { pRect->left = pRect->right - winNormalSize.cx; pRect->bottom = pRect->top + winNormalSize.cy; alignType = ALIGN_NONE; } else { pRect->right = cxScreen; pRect->left = pRect->right - rcOld.Width(); pRect->top = 0; pRect->bottom = rcWorkArea.bottom; } } if (alignType == ALIGN_NONE) KillTimer(IDT_HOVER); CDialog::OnMoving(fwSide, pRect); }最开始,alignType = ALIGN_NONE 本代码的流程如下:1. 初始化窗体时设置窗体位置,并设置依靠状态窗体状态。2. 当接收到WM_MOUSEMOVE消息时,检查窗体是否显示,若否,显示,并打开定时器。3. 在WM_MOVING中检测窗体位置,并自动靠拢边界。4. 在定时器中检测鼠标,当鼠标离开窗体后,关闭定时器,隐藏窗体。当然,在隐藏窗体时首先判断位置,若停靠在边缘,则隐藏,否则,不隐藏。现在我们一步步看代码。int alignType; //全局变量,用于记录窗体停靠状态enum{ALIGN_NONE, //不停靠ALIGN_TOP, //停靠上边ALIGN_LEFT, //停靠左边ALIGN_RIGHT //停靠右边};#define NEAR_SIZE 20 //定义自动停靠有效距离#define NEAR_SIDE 2 //窗体隐藏后在屏幕上保留的像素,以使鼠标可以触及/*下面代码处理窗体消息WM_MOVING,pRect是由参数lParam传来的指针*/void OnMoving(HWND hWnd, LPRECT pRect){//未靠边界由pRect测试if (alignType == ALIGN_NONE){ if (pRect->top < NEAR_SIZE) //在上边有效距离内,自动靠拢。 { alignType = ALIGN_TOP; pRect->bottom -= pRect->top; pRect->top = 0; } if (pRect->left < NEAR_SIZE) //在左边有效距离内 { alignType = ALIGN_LEFT; pRect->right -= pRect->left; pRect->left = 0; } else if (pRect->right + NEAR_SIZE > ScreenX) //在右边有效距离内,ScreenX为屏幕宽度,可由GetSystemMetrics(SM_CYSCREEN)得到。 { alignType = ALIGN_RIGHT; pRect->left += (ScreenX - pRect->right); pRect->right = ScreenX; }}else{ //靠边界由鼠标测试 POINT pt; GetCursorPos(&pt); if (alignType == ALIGN_TOP) { if (pt.y > NEAR_SIZE) //由于我们移动窗体时,鼠标在标题栏内,当鼠标位置超过有效距离后,我们可以考虑用户要向下拖动鼠标。我们便解除上部停靠。 { alignType = ALIGN_NONE; pRect->bottom += NEAR_SIZE; pRect->top = NEAR_SIZE; } else { pRect->bottom -= pRect->top; pRect->top = 0; if (pRect->left < NEAR_SIZE) //在上部停靠时,我们也考虑左右边角。 { 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) //鼠标可以在整个标题条来回移动,所以我们不能简单用左边界和鼠标的距离来解除停靠,这里我们在鼠标离开右边界时解除停靠。 { 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) //当鼠标离开左边界时,解除停靠。 { 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; } } }}}/*在窗体初始化是设定窗体状态,如果可以停靠,便停靠在边缘我本想寻求其他方法来解决初始化,而不是为它专一寻求一个函数,可是,窗体初始化时不发送WM_MOVING消息,我不得不重复类似任务.*/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; }}//调整上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);}}/*窗体的显示隐藏由该函数完成,参数hide决定显示还是隐藏.*/void HideSide(HWND hWnd, BOOL hide){RECT rc;int moves = 20; //动画滚动窗体的步数,如果你觉得不够平滑,可以增大该值.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;//下边判断窗体该如何移动,由停靠方式决定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;}//动画滚动窗体.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) //如果窗体已被显示,设置定时器.监视鼠标.{ SetTimer(hWnd, WM_TIMER, 500, NULL);}}//下面就是通过窗体回调函数将这些函数组织起来.//这里仅列出使用的消息case WM_TIMER: //定时器消息{POINT pt;RECT rc;GetCursorPos(&pt);GetWindowRect(hWnd, &rc);if (!PtInRect(&rc, pt)) //若鼠标不在窗体内,隐藏窗体.{ KillTimer(hWnd, WM_TIMER); HideSide(hWnd, TRUE);}break;}case WM_CREATE:case WM_INITDIALOG: //初始化消息{SetWindowPos(...) //程序保存窗体上次靠位置,在这里恢复. NearSide(hWnd);break;}//这两个消息是在窗体移动开始时和结束时产生的,我们在窗体开始移动时关闭定时器,移动结束后再打开,这样避免窗体移动时隐藏,金山快译的浮动条就有这种情况出现.case WM_ENTERSIZEMOVE:{KillTimer(hWnd, WM_TIMER);break;}case WM_EXITSIZEMOVE:{SetTimer(hWnd, WM_TIMER, 500, NULL);break;}case WM_MOUSEMOVE: //受到窗体移动消息时,判断窗体是否显示,{RECT rc;GetWindowRect(hWnd, &rc);if (rc.left < 0 || rc.top < 0 || rc.right > ScreenX) //未显示 HideSide(hWnd, FALSE);break;}case WM_MOVING: //处理窗体移动时消息,实现自动停靠{OnMoving(hWnd, (LPRECT) lParam);break;}case WM_MOVE:{//保存窗体位置} VS2010把别的项目文件添加到自己项目里怎么不能用? 如何修改系统菜单的文本显示? 轻量级的IM工具。很小,但是文件传输方面的功能比较强大,速度也很不错。大家去试试看:) 面试上机题 opengl中如何实现绕任意轴旋转? 我想在树型控件中添加列表的功能,我该怎么做? 我在这个cex13aview这个类里没办法用这个变量? 怎样取段地址和偏移地址? 呼叫高手!!!!! 问一个弱弱的问题vc 的link error 是vc的问题吗? WinPcap接收数据过滤规则设置的问题。 用AddNew()报了个 Debug Assertion Failed.大虾帮忙搞定一下!!!
ALIGN_NONE,
ALIGN_TOP,
ALIGN_LEFT,
ALIGN_RIGHT
};void C***Dlg::hideWindow(BOOL hide)
{
CRect rc;
GetWindowRect(rc);
int moves = 20;
int xStep, yStep;
int xEnd, yEnd;
int cxScreen; switch (alignType) {
case ALIGN_TOP:
xStep = 0;
xEnd = rc.left;
if (hide) {
yStep = -rc.bottom / moves;
yEnd = -rc.Height() + 2;
} else {
yStep = -rc.top / moves;
yEnd = 0;
}
break;
case ALIGN_LEFT:
yStep = 0;
yEnd = rc.top;
if (hide) {
xStep = -rc.right / moves;
xEnd = -rc.Width() + 2;
} else {
xStep = -rc.left / moves;
xEnd = 0;
}
break;
case ALIGN_RIGHT:
yStep = 0;
yEnd = rc.top;
cxScreen = GetSystemMetrics(SM_CXSCREEN);
if (hide) {
xStep = (cxScreen - rc.left) / moves;
xEnd = cxScreen - 2;
} else {
xStep = (cxScreen - rc.right) / moves;
xEnd = cxScreen - rc.Width();
}
break;
}/* for (int i = 0; i < moves; i++) {
rc.left += xStep;
rc.top += yStep;
SetWindowPos(NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN);
Sleep(20);
}*/
SetWindowPos(NULL, xEnd, yEnd, 0, 0, SWP_NOSIZE); isHide = hide;
if (!isHide)
SetTimer(IDT_HOVER, 50, NULL);
}UINT C***Dlg::OnNcHitTest(CPoint point)
{
UINT res = CDialog::OnNcHitTest(point);
if (res == HTCLIENT)
return HTCAPTION;// TRACE("OnNcHitTest point=%d %d. res=%d ,alignType=%d\n",point.x,point.y ,res,alignType);
switch (alignType) {
case ALIGN_TOP:
if (res == HTLEFT || res == HTRIGHT || res == HTTOP ||
res == HTTOPLEFT || res == HTTOPRIGHT)
// res = HTERROR;
// else if (res == HTBOTTOMLEFT || res == HTBOTTOMRIGHT)
res = HTBOTTOM;
// if (isHide && res == HTBOTTOM)
hideWindow(FALSE);
break;
case ALIGN_LEFT:
if (res == HTTOP || res == HTBOTTOM || res == HTLEFT ||
res == HTTOPLEFT || res == HTBOTTOMLEFT)
// res = HTERROR;
// else if (res == HTTOPRIGHT || res == HTBOTTOMRIGHT)
res = HTRIGHT;
if (isHide && res == HTRIGHT)
hideWindow(FALSE);
break;
case ALIGN_RIGHT:
if (res == HTTOP || res == HTBOTTOM || res == HTRIGHT ||
res == HTTOPRIGHT || res == HTBOTTOMRIGHT)
// res = HTERROR;
// else if (res == HTTOPLEFT || res == HTBOTTOMLEFT)
res = HTLEFT;
if (isHide && res == HTLEFT)
hideWindow(FALSE);
break;
}
return res;
}void C***Dlg::OnTimer(UINT nIDEvent)
{
if (nIDEvent == IDT_HOVER) {
CPoint pt;
GetCursorPos(&pt);
CRect rc;
GetWindowRect(rc);
rc.InflateRect(10, 10);
if (!rc.PtInRect(pt)) {
KillTimer(nIDEvent);
hideWindow();
}
}
****
}void C***Dlg::OnMoving(UINT fwSide, LPRECT pRect)
{
CRect rcOld, rcWorkArea;
CPoint pt;
GetWindowRect(rcOld);
SystemParametersInfo(SPI_GETWORKAREA, 0, rcWorkArea, 0);
GetCursorPos(&pt);
int cxScreen = GetSystemMetrics(SM_CXSCREEN); if (alignType == ALIGN_NONE) {
if (pt.y - rcWorkArea.top < 20) {
alignType = ALIGN_TOP;
pRect->top = 0;
}
else if (pt.x - rcWorkArea.left < 20) {
alignType = ALIGN_LEFT;
pRect->left = 0;
winNormalSize = rcOld.Size();
}
else if (rcWorkArea.right - pt.x < 20) {
alignType = ALIGN_RIGHT;
pRect->right = cxScreen;
winNormalSize = rcOld.Size();
}
if (alignType != ALIGN_NONE)
SetTimer(IDT_HOVER, 50, NULL);
} if (alignType == ALIGN_TOP) {
if (pRect->top > 0)
alignType = ALIGN_NONE;
else {
pRect->top = 0;
pRect->bottom = rcOld.Height();
}
}
else if (alignType == ALIGN_LEFT) {
if (pRect->left > 0) {
pRect->right = pRect->left + winNormalSize.cx;
pRect->bottom = pRect->top + winNormalSize.cy;
alignType = ALIGN_NONE;
} else {
pRect->left = 0;
pRect->right = rcOld.Width();
pRect->top = 0;
pRect->bottom = rcWorkArea.bottom;
}
}
else if (alignType == ALIGN_RIGHT) {
if (pRect->right < cxScreen) {
pRect->left = pRect->right - winNormalSize.cx;
pRect->bottom = pRect->top + winNormalSize.cy;
alignType = ALIGN_NONE;
} else {
pRect->right = cxScreen;
pRect->left = pRect->right - rcOld.Width();
pRect->top = 0;
pRect->bottom = rcWorkArea.bottom;
}
} if (alignType == ALIGN_NONE)
KillTimer(IDT_HOVER); CDialog::OnMoving(fwSide, pRect);
}最开始,alignType = ALIGN_NONE
1. 初始化窗体时设置窗体位置,并设置依靠状态窗体状态。
2. 当接收到WM_MOUSEMOVE消息时,检查窗体是否显示,若否,显示,并打开定时器。
3. 在WM_MOVING中检测窗体位置,并自动靠拢边界。
4. 在定时器中检测鼠标,当鼠标离开窗体后,关闭定时器,隐藏窗体。
当然,在隐藏窗体时首先判断位置,若停靠在边缘,则隐藏,否则,不隐藏。
现在我们一步步看代码。
int alignType; //全局变量,用于记录窗体停靠状态
enum
{
ALIGN_NONE, //不停靠
ALIGN_TOP, //停靠上边
ALIGN_LEFT, //停靠左边
ALIGN_RIGHT //停靠右边
};
#define NEAR_SIZE 20 //定义自动停靠有效距离
#define NEAR_SIDE 2 //窗体隐藏后在屏幕上保留的像素,以使鼠标可以触及
/*
下面代码处理窗体消息WM_MOVING,pRect是由参数lParam传来的指针
*/
void OnMoving(HWND hWnd, LPRECT pRect)
{
//未靠边界由pRect测试
if (alignType == ALIGN_NONE)
{
if (pRect->top < NEAR_SIZE) //在上边有效距离内,自动靠拢。
{
alignType = ALIGN_TOP;
pRect->bottom -= pRect->top;
pRect->top = 0;
}
if (pRect->left < NEAR_SIZE) //在左边有效距离内
{
alignType = ALIGN_LEFT;
pRect->right -= pRect->left;
pRect->left = 0;
}
else if (pRect->right + NEAR_SIZE > ScreenX) //在右边有效距离内,ScreenX为屏幕宽度,可由GetSystemMetrics(SM_CYSCREEN)得到。
{
alignType = ALIGN_RIGHT;
pRect->left += (ScreenX - pRect->right);
pRect->right = ScreenX;
}}
else
{
//靠边界由鼠标测试
POINT pt;
GetCursorPos(&pt);
if (alignType == ALIGN_TOP)
{
if (pt.y > NEAR_SIZE) //由于我们移动窗体时,鼠标在标题栏内,当鼠标位置超过有效距离后,我们可以考虑用户要向下拖动鼠标。我们便解除上部停靠。
{
alignType = ALIGN_NONE;
pRect->bottom += NEAR_SIZE;
pRect->top = NEAR_SIZE;
}
else
{
pRect->bottom -= pRect->top;
pRect->top = 0;
if (pRect->left < NEAR_SIZE) //在上部停靠时,我们也考虑左右边角。
{
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) //鼠标可以在整个标题条来回移动,所以我们不能简单用左边界和鼠标的距离来解除停靠,这里我们在鼠标离开右边界时解除停靠。
{
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) //当鼠标离开左边界时,解除停靠。
{
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;
}
}
}
}
}
/*
在窗体初始化是设定窗体状态,如果可以停靠,便停靠在边缘
我本想寻求其他方法来解决初始化,而不是为它专一寻求一个函数,可是,窗体初始化时不发送WM_MOVING消息,我不得不重复类似任务.
*/
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;
}
}
//调整上
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);
}}
/*
窗体的显示隐藏由该函数完成,参数hide决定显示还是隐藏.
*/
void HideSide(HWND hWnd, BOOL hide)
{
RECT rc;
int moves = 20; //动画滚动窗体的步数,如果你觉得不够平滑,可以增大该值.
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;//下边判断窗体该如何移动,由停靠方式决定
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;
}
//动画滚动窗体.
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) //如果窗体已被显示,设置定时器.监视鼠标.
{
SetTimer(hWnd, WM_TIMER, 500, NULL);
}
}
//下面就是通过窗体回调函数将这些函数组织起来.
//这里仅列出使用的消息
case WM_TIMER: //定时器消息
{
POINT pt;
RECT rc;
GetCursorPos(&pt);
GetWindowRect(hWnd, &rc);
if (!PtInRect(&rc, pt)) //若鼠标不在窗体内,隐藏窗体.
{
KillTimer(hWnd, WM_TIMER);
HideSide(hWnd, TRUE);
}
break;
}
case WM_CREATE:
case WM_INITDIALOG: //初始化消息
{
SetWindowPos(...) //程序保存窗体上次靠位置,在这里恢复.
NearSide(hWnd);
break;
}
//这两个消息是在窗体移动开始时和结束时产生的,我们在窗体开始移动时关闭定时器,移动结束后再打开,这样避免窗体移动时隐藏,金山快译的浮动条就有这种情况出现.
case WM_ENTERSIZEMOVE:
{
KillTimer(hWnd, WM_TIMER);
break;
}
case WM_EXITSIZEMOVE:
{
SetTimer(hWnd, WM_TIMER, 500, NULL);
break;
}
case WM_MOUSEMOVE: //受到窗体移动消息时,判断窗体是否显示,
{
RECT rc;
GetWindowRect(hWnd, &rc);
if (rc.left < 0 || rc.top < 0 || rc.right > ScreenX) //未显示
HideSide(hWnd, FALSE);
break;
}
case WM_MOVING: //处理窗体移动时消息,实现自动停靠
{
OnMoving(hWnd, (LPRECT) lParam);
break;
}
case WM_MOVE:
{
//保存窗体位置
}