开发精彩实例:窗体自动隐藏
下面图老师小编要向大家介绍下开发精彩实例:窗体自动隐藏,看起来复杂实则是简单的,掌握好技巧就OK,喜欢就赶紧收藏起来吧!
本代码的流程如下:
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传来的指针
*/
voidOnMoving(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
{
//靠边界由鼠标测试
更多内容请看Wlan组网----家庭专题专题,或 POINT pt;
GetCursorPos(&pt);
if (alignType == ALIGN_TOP)
{
if (pt.y NEAR_SIZE) //由于我们移动窗体时,鼠标在标题栏内,当鼠标位置超过有效距离后,我们可以考虑用户要向下拖动鼠标。我们便解除上部停靠。
{
!-- frame contents -- !-- /frame contents -- 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;
}
更多内容请看Wlan组网----家庭专题专题,或 else
{
pRect->left += (ScreenX - pRect->right);
pRect->right = ScreenX;
if (pRect->top NEAR_SIZE) //考虑右上角。
{
pRect->bottom -= pRect->top;
pRect->top = 0;
}
}
}
}
}
!-- frame contents -- !-- /frame contents -- /*
在窗体初始化是设定窗体状态,假如可以停靠,便停靠在边缘
我本想寻求其他方法来解决初始化,而不是为它专一寻求一个函数,可是,窗体初始化时不
发送WM_MOVING消息,我不得不重复类似任务.
*/
voidNearSide(HWND hWnd)
{
int change = 0;
RECTrect;
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;
}
}
//调整上
更多内容请看Wlan组网----家庭专题专题,或 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)
{
!-- frame contents -- !-- /frame contents --MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
}
}
/*
窗体的显示隐藏由该函数完成,参数hide决定显示还是隐藏.
*/
voidHideSide(HWND hWnd, BOOL hide)
{
RECTrc;
int moves = 20; //动画滚动窗体的步数,假如你觉得不够平滑,可以增大该值.
int xStep, yStep;
int xEnd, yEnd;
int width;
int height;
register inti;
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:
{
//向左移藏
更多内容请看Wlan组网----家庭专题专题,或yStep = 0;
yEnd = rc.top;
if (hide)
{
xStep = -rc.right / moves;
xEnd = -width + NEAR_SIDE;
}
else
{
xStep = -rc.left / moves;
xEnd = 0;
}
break;
}
!-- frame contents -- !-- /frame contents -- 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);
}
}
//下面就是通过窗体回调函数将这些函数组织起来.
更多内容请看Wlan组网----家庭专题专题,或 //这里仅列出使用的消息
case WM_TIMER: //定时器消息
{
POINT pt;
RECTrc;
GetCursorPos(&pt);
GetWindowRect(hWnd, &rc);
if (!PtInRect(&rc, pt)) //若鼠标不在窗体内,隐藏窗体.
{
!-- frame contents -- !-- /frame contents --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: //受到窗体移动消息时,判定窗体是否显示,
{
RECTrc;
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:
{
//保存窗体位置
}
这些代码是从程序中摘录出来的, 笔者已尽量检查它们的完整性, 但人总有犯错的时候, 假如发现这些代码有问题, 或有更好的建议, 请联系笔者:ggg82@sina.com
更多内容请看Wlan组网----家庭专题专题,或