当前位置:C++技术网 > 精选软件 > OffsetRect为什么移不动矩形,OffsetRect移动矩形深入分析

OffsetRect为什么移不动矩形,OffsetRect移动矩形深入分析

更新时间:2015-12-28 15:28:33浏览次数:1+次

    本来以为OffsetRect函数使用很简单的,然而却因此花费了不少时间。因为它并没有按照我的想法移动矩形。然后就上网查一下这个函数的使用,然而都是恶心的MSDN解释的简单翻译。你说我要这种资料干嘛。看似互联网资料很多,然而,大部分都是垃圾资料。很多人都是在网上制造垃圾资料而已。真是可悲。我希望C++技术网可以做好这份工作,建立真正的专业的程序员学习平台,分享真正的学习经验资料。

    先来看看移动矩形的效果图:

左击客户区时向右移动矩形,右击向下移动矩形

【左击客户区时向右移动矩形,右击向下移动矩形】


    在文章《使用InvertRect快速实现指定矩形范围的颜色反色翻转》中,我们可以看到只需要调用InvertRect函数就可以对矩形执行翻转操作了。所以,我也以为移动矩形应该真的会移动吧。事实上,被误导了!
    我们在《win32模拟窗口拖动效果而实现的拖动矩形》展现了拖动矩形的两种实现方法,而且还带有拖动的特效的哦。这里是想利用这个现成的函数来移动矩形。而MSDN中只做了简单的描述,并没有给出更多细节的描述。如果你是新手,绝对不知道如何移动。因为缺乏说明,你根本没法使用这个函数。因此也无法让矩形真正动起来。
    通过写代码测试发现,OffsetRect函数移动矩形并不会真的将你给定的矩形移动。他并不像InvertRect函数一样直接操作矩形,而只是对矩形的位置值进行计算和存储而已。也就是说,执行完OffsetRect函数,你只是更新了给定矩形结构体RECT变量的值而已。而更新的方式就是在第二第三个参数中传入一个数值,用来决定移动的方向。第二个参数决定的是矩形左上角的x坐标的移动的值,第三个参数是矩形左上角的y坐标的移动的值。而这个值的正负就决定移动的方向。第二个参数为正,则表示左上角的点的x坐标在增大,这样就表示新矩形相对于老矩形向右偏移了一定的单位。如果为负数,则表示像左偏移了一定的单位,偏移的值则是第二个参数的绝对值。第三个参数就是决定向上(参数为正)或者向下(参数为负)移动。Offset就是偏移的意思。
    真正的移动,就是你要重新画矩形。OffsetRect并不会帮你完成这个事情。不要对此抱有幻想。所以,我在鼠标单击的时候,只是调用了OffsetRect函数来变化矩形的位置,然后在WM_PAINT消息中用矩形的位置画一下矩形即可。这样就达到了移动矩形的效果。实际上,OffsetRect函数我们也可以自己用简单的RECT结构体变量赋值搞定。不过既然用这个函数就是为了简化代码,所以既然使用,就要弄明白。万一哪一天要自己写不能用这个函数,你也可以很轻松的实现。
    下面是完整的代码:
#include "windows.h"
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    static RECT rect;
    static int x=10;//每次x轴上移动的单位
    static int y=10;//每次y轴上移动的单位
    switch (message)
    {
    case WM_CREATE:
        SetRect(&rect,0,0,100,100);//设置矩形的大小
        return 0;
     case WM_PAINT:
         hdc = BeginPaint(hwnd,&ps);
         SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
         Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom);
         EndPaint(hwnd,&ps);
         return 0;
     case WM_LBUTTONDOWN:
         {
             hdc=GetDC(hwnd);
             if(!OffsetRect(&rect,x,0))//只计算和更新矩形位置
             {
                 MessageBox(hwnd,_T("移动失败"),_T(""),0);
             }
             InvalidateRect(hwnd,NULL,TRUE);//让客户区绘制出移动后的矩形
             ReleaseDC(hwnd,hdc);
         }
         return 0;
     case WM_RBUTTONDOWN:
         {
             hdc=GetDC(hwnd);
             if(!OffsetRect(&rect,0,y))//只计算和更新矩形位置
             {
                 MessageBox(hwnd,_T("移动失败"),_T(""),0);
             }
             InvalidateRect(hwnd,NULL,TRUE);//让客户区绘制出移动后的矩形
             ReleaseDC(hwnd,hdc);
         }
         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_HAND);
    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,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}