拖动窗口的两种效果,我们可以通过系统来设置。设置的步骤为:我的电脑 -> 右击“属性” -> 高级系统属性 -> 性能下的“设置” -> 调整为最佳外观(窗口跟着鼠标实时移动)/调整为最佳性能(窗口移动使用虚框代替,鼠标释放后真正移动窗口)。我们不知道如何选,就选择“让Windows选择计算机的最佳设置”。在优化电脑时,通常会将界面的特效优化掉,看到的就没有窗口的淡入淡出的效果,也让系统美感降低了不少。
我们要实现的效果如下:
【拖动矩形时矩形本身实时跟着移动】
【拖动矩形时使用虚框代替矩形可能落脚的位置】
我们首先在鼠标右击时创建了一个矩形,所以右击客户区这个矩形就出现了。使用的是白色画笔画边框和浅灰色画刷填充矩形内部。使用白色画刷是因为后面要实现虚框的效果。为了让每次拖动后,不让上次移动过程中留下痕迹,所以移动之后马上促使客户区重绘。重绘并且让客户区擦除背景。那么擦除后,就代表什么也没有了。那我们要得到移动的效果,就要再WM_PAINT消息里在移动后的位置画出矩形。这样就可以看到移动后的效果。
鼠标左键单击按下时,获取鼠标的坐标,然后判断这个坐标是否在所画的矩形内部,如果在则允许拖动矩形。这样可以防止鼠标没有在矩形内就可以拖动矩形的问题。PtInRect函数给定一个点和一个矩形,如果点在矩形内部,就返回真,否则返回假。
在鼠标左键弹起的消息WM_LBUTTONUP里,计算移动的水平和垂直方向的长度,然后计算出新的矩形的位置。同时将当前矩形的位置存入上一次位置里作为下次移动使用。CopyRect函数就是将一个矩形的值复制给另一个矩形。这样让客户区重绘,一是可以将上一次的矩形擦掉,同时也将本次的矩形画出来,就是最终的矩形了。
我们要清楚,WM_PAINT始终是显示最终的矩形,在左键弹起确定最终位置后并不绘制矩形,反正也要擦除背景,所以就在WM_PAINT一起处理了。
鼠标移动消息也是不停的计算新位置的过程,然后就是移动过程中显示移动效果。不管是哪种效果,都需要将前一次移动的效果擦除,这样不会有难看的痕迹。然后就是显示实时移动的效果,代码如下:
//实时移动矩形
SelectObject(hdc,GetStockObject(NULL_PEN));
SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
Rectangle(hdc,rectMove.left,rectMove.top,rectMove.right,rectMove.bottom);
CopyRect(&rectLast,&rectMove);
这样就结束了,就实现了实时移动矩形的效果。而如果你要实现带有虚框的移动,则不要使用这段代码了。因为之前已经将矩形都擦除了,自然原始的矩形也看不见了。因为移动的时候会和原始矩形重合,擦除了移动时的矩形也就将原始矩形擦没了。既然如此,就先擦除移动的矩形,然后再画出原始矩形。这样原始矩形就保留下来了。紧接着就是画带黑色边框无填充的矩形了。这个就是虚框了。在不停的移动中,这个虚框的位置就在不停地改变,就实现了虚框移动的效果。代码如下://使用虚框代替矩形实时移动效果
//画初始的矩形
SelectObject(hdc,GetStockObject(NULL_PEN));
SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
Rectangle(hdc,rectOld.left,rectOld.top,rectOld.right,rectOld.bottom);
//画本次移动的矩形轨迹
SelectObject(hdc,GetStockObject(BLACK_PEN));
SelectObject(hdc,GetStockObject(NULL_BRUSH));
Rectangle(hdc,rectMove.left,rectMove.top,rectMove.right,rectMove.bottom);
CopyRect(&rectLast,&rectMove);
注意,实时移动矩形和使用虚框移动矩形的代码二选一,不要同时生效哦。下面是所有完整代码:
#include "windows.h"
#include "Windowsx.h"
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
static POINT ptOld,ptNew;
static RECT rectOld,rectMove,rectNew,rectLast;
static bool bIsMove=false;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
SelectObject(hdc,GetStockObject(WHITE_PEN));
SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
Rectangle(hdc,rectOld.left,rectOld.top,rectOld.right,rectOld.bottom);
EndPaint(hwnd,&ps);
return 0;
case WM_RBUTTONDOWN:
//绘制第一个矩形
hdc = GetDC(hwnd);
SetRect(&rectOld,10,10,110,70);//保存上次矩形的位置
SelectObject(hdc,GetStockObject(WHITE_PEN));
SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
Rectangle(hdc,rectOld.left,rectOld.top,rectOld.right,rectOld.bottom);
ReleaseDC(hwnd,hdc);
return 0;
case WM_LBUTTONDOWN:
//确定鼠标起始位置
ptOld.x = GET_X_LPARAM(lParam);
ptOld.y = GET_Y_LPARAM(lParam);
if (PtInRect(&rectOld,ptOld))
{
bIsMove=true;
}
else
{
bIsMove=false;
}
return 0;
case WM_LBUTTONUP:
//确定鼠标释放位置
if (bIsMove)
{
hdc = GetDC(hwnd);
bIsMove=false;
ptNew.x = GET_X_LPARAM(lParam);
ptNew.y = GET_Y_LPARAM(lParam);
rectNew.left = rectOld.left+ (ptNew.x -ptOld.x);
rectNew.top = rectOld.top+ (ptNew.y -ptOld.y);
rectNew.right = rectNew.left+100;
rectNew.bottom = rectNew.top+60;
CopyRect(&rectOld,&rectNew);
InvalidateRect(hwnd,NULL,TRUE);
ReleaseDC(hwnd,hdc);
}
return 0;
case WM_MOUSEMOVE:
if(bIsMove)
{
//鼠标移动画边框
POINT ptMove;
ptMove.x = GET_X_LPARAM(lParam);
ptMove.y = GET_Y_LPARAM(lParam);
rectMove.left=rectOld.left+(ptMove.x-ptOld.x);
rectMove.top=rectOld.top+(ptMove.y-ptOld.y);
rectMove.right = rectMove.left+100;
rectMove.bottom = rectMove.top +60;
hdc = GetDC(hwnd);
//-擦掉上一次的拖动的矩形轨迹
SelectObject(hdc,GetStockObject(WHITE_PEN));
SelectObject(hdc,GetStockObject(WHITE_BRUSH));
Rectangle(hdc,rectLast.left,rectLast.top,rectLast.right,rectLast.bottom);
////实时移动矩形
//SelectObject(hdc,GetStockObject(NULL_PEN));
//SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
//Rectangle(hdc,rectMove.left,rectMove.top,rectMove.right,rectMove.bottom);
//CopyRect(&rectLast,&rectMove);
//使用虚框代替矩形实时移动效果
//画初始的矩形
SelectObject(hdc,GetStockObject(NULL_PEN));
SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
Rectangle(hdc,rectOld.left,rectOld.top,rectOld.right,rectOld.bottom);
//画本次移动的矩形轨迹
SelectObject(hdc,GetStockObject(BLACK_PEN));
SelectObject(hdc,GetStockObject(NULL_BRUSH));
Rectangle(hdc,rectMove.left,rectMove.top,rectMove.right,rectMove.bottom);
CopyRect(&rectLast,&rectMove);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
TCHAR ClassName[] = _T("MyClass");
TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
WNDCLASS wndClass;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = WinProc;
wndClass.lpszClassName = ClassName;
wndClass.lpszMenuName=NULL;
wndClass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndClass)) return 0;
HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,440,440,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}