当前位置:C++技术网 > 精选软件 > win32模拟窗口拖动效果而实现的拖动矩形

win32模拟窗口拖动效果而实现的拖动矩形

更新时间:2015-12-27 22:26:53浏览次数:1+次

    我们拖动窗口的过程中,会发现窗口并没有实时的跟着跑,而是看到一个虚框在移动,然后鼠标放了之后,窗口才会真正移动到目的地。还有一种效果就是,窗口跟着鼠标实时移动。我们使用win32拖动客户区的矩形来模仿这两种效果。
    拖动窗口的两种效果,我们可以通过系统来设置。设置的步骤为:我的电脑 -> 右击“属性” -> 高级系统属性 -> 性能下的“设置” -> 调整为最佳外观(窗口跟着鼠标实时移动)/调整为最佳性能(窗口移动使用虚框代替,鼠标释放后真正移动窗口)。我们不知道如何选,就选择“让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;
}