zoukankan      html  css  js  c++  java
  • 学习游戏基础编程2:Win32分割窗口

    一直很不解分割窗口是什么原理。百度了老长时间发现这方面的资料甚少,但好歹也知道了个大概,今天就做个总结,免得到时候忘记。

    当初很傻很天真的时候,真的以为简单只是把一个窗口像玻璃那样劈成2半,各做各的,其实是父窗口下有数个子窗口,父窗口被这些子窗口所遮挡,看起来就像是窗口分成好几个区域。因此第一步我们要创建好几个窗口,并调整好它们的位置。

    HWND hwndMain;//主窗口
    HWND hwndEdit;//编辑区域窗口
    HWND hwndPreview;//预览图区域窗口
    HWND hwndTitleimg;//显示图片块儿窗口

    在WinMain()里hwndMain=CreateWindow();

    在WindowProc()里的WM_CREATE里,分别hwndEdit/hwndPreview/hwndTitleimg=CreateWindow();在WM_SIZE里,MoveWindow()到预定的位置。

    之后你就会看到左侧的hwndEdit窗口,右侧上方的hwndPreview窗口,下方的hwndTitleimg窗口。

    第二步,鼠标按在子窗口空隙形成的分割线(条)的时候拖动,子窗口能任意调整彼此之间的大小。怎么做呢?简单的一种做法就是,在鼠标拖动的时候画出一条矩形阴影来模拟,等鼠标释放时重新调整大小,也就是WM_SIZE里根据鼠标的位置设置3个子窗口的大小。复杂点的做法,就是分割条也当作一个子窗口CreateWindow()出来,不过有点麻烦,暂且不提。

    下面给出完整代码:

    //全局变量

    static TCHAR szAppName[]=TEXT("Win32分割窗口");

    char szClassName[ ] = TEXT("WindowsApp");

    HINSTANCE hInst;

    HWND hwndMain;
    HWND hwndEdit;
    HWND hwndPreview;
    HWND hwndTitleimg;
    static int CLIENT_W = 800;//主窗口客户区宽
    static int CLIENT_H = 600;//主窗口客户区高
    static RECT cliRect = {0,0,CLIENT_W,CLIENT_H};//主窗口客户区矩形位置
    static int spX=550;//水平分割条初始位置
    static int spY=150;//垂直分隔条初始位置
    static int spBar=5;//分隔条的厚度
    static RECT rectSpVer={spX,0,spX+spBar,CLIENT_H};//垂直分隔条矩形位置
    static RECT rectSpHor={spX+spBar,spY,CLIENT_W,spY+spBar};//水平分隔条矩形位置
    bool fDragVer=false;bool fMoveVer=false;//垂直分隔条是否按下/拖动
    bool fDragHor=false;bool fMoveHor=false;//水平分隔条是否按下/拖动
    POINT pold;//注意 保存旧的鼠标POINT位置 这是一个要点 并没有WM_PAINT重画,所以我们要消除之前绘制的阴影,利用PATINVERT方式重新绘制一次

    //全局函数

    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);//窗口过程函数
    void InitHwndChild(HWND hwnd);//初始化三个子窗口所用 在WM_CREATE处被调用
    void SizeWindowContents(int nWidth, int nHeight);//调整三个子窗口size所用 在WM_SIZE处调用 参数为客户区宽高
    void Sp_LBDown(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);//分隔条区域鼠标按下 WM_LBUTTONDOWN处调用
    void Sp_LBUp(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);//分隔条区域鼠标释放 WM_LBUTTONUP处调用
    void Sp_MouseMove(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);//分隔条区域鼠标移动 WM_MOUSEMOVE处调用
    void DrawSpBar(LPRECT lpRect);//绘制模拟分隔条的阴影 参数为要绘制的分隔条矩形位置
    LPRECT GetVerSpBar();//根据鼠标位置求得新的垂直分割矩形 用于绘制分割条时
    LPRECT GetHorSpBar();//根据鼠标位置求得新的水平分割矩形 用于绘制分隔条时

     void SetWndCenter(HWND hwnd);//根据客户区大小设置主窗口大小并居中

    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow)
    {
        HWND hwnd;               /* This is the handle for our window */

        MSG msg;
        WNDCLASSEX wndClass;
        wndClass.cbSize=sizeof(WNDCLASSEX);
        wndClass.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
        wndClass.lpfnWndProc=WindowProcedure;
        wndClass.cbClsExtra=0;
        wndClass.cbWndExtra=0;
        wndClass.hInstance=hInstance;
     wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
     wndClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
        wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
     wndClass.hbrBackground=(HBRUSH)COLOR_BACKGROUND;
     wndClass.lpszMenuName=NULL;
        wndClass.lpszClassName=szAppName;
        if(!RegisterClassEx(&wndClass))
        {
            MessageBox(NULL,TEXT("error"),szAppName,MB_ICONERROR|MB_OK);
            return 0;
        }
        hInst=hInstance;
        hwndMain=CreateWindowEx(0,szAppName,TEXT("The hello program"),WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
     SetWndCenter(hwndMain);//设置窗口客户区大小并居中
        ShowWindow(hwndMain,iCmdShow);
        UpdateWindow(hwndMain);
     while(GetMessage(&msg,NULL,0,0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return 0;
    }

    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        HDC hdc;
        PAINTSTRUCT ps;
        switch (message)                  /* handle the messages */
        {
        case WM_CREATE:
            InitHwndChild(hwnd);//init three HWND child
            break;
        case WM_SIZE:
            SizeWindowContents(LOWORD(lParam), HIWORD(lParam));//set three child window positions
            break;
        case WM_LBUTTONDOWN:
            Sp_LBDown(hwnd,message,wParam,lParam);
            break;
        case WM_LBUTTONUP:
            Sp_LBUp(hwnd,message,wParam,lParam);
            break;
        case WM_MOUSEMOVE:
            Sp_MouseMove(hwnd,message,wParam,lParam);
            break;
        case WM_PAINT:
            hdc=BeginPaint(hwnd,&ps);
            EndPaint(hwnd,&ps);
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
        }

        return 0;
    }
    void InitHwndChild(HWND hwnd)
    {
        hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
       "STATIC", "hwndEdit",
       WS_VISIBLE|WS_CHILD,
       0,0,0,0,hwnd, 0, hInst, 0);
        //SetWindowLongPtr(hwndEdit,GWLP_WNDPROC,(LONG)hwndEditProc);
        hwndPreview = CreateWindowEx(WS_EX_CLIENTEDGE,
       "STATIC", "hwndPreview",
       WS_VISIBLE|WS_CHILD,
       0,0,0,0,hwnd, 0, hInst, 0);
        hwndTitleimg = CreateWindowEx(WS_EX_CLIENTEDGE,
       "STATIC", "hwndTitleimg",
       WS_VISIBLE|WS_CHILD,
       0,0,0,0,hwnd, 0, hInst, 0);
    }
    void SizeWindowContents(int nWidth, int nHeight)
    {
        MoveWindow(hwndEdit, 0, 0, spX, nHeight, true);
        MoveWindow(hwndPreview, spX+spBar, 0, nWidth-spX-spBar, spY, true);
        MoveWindow(hwndTitleimg, spX+spBar, spY+spBar, nWidth-spX-spBar, nWidth-spY-spBar, true);
    }
    void Sp_LBDown(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        SetCapture(hwndMain);
        POINT p;
        p.x=LOWORD(lParam);p.y=HIWORD(lParam);
        if((fDragVer=PtInRect(GetVerSpBar(),p))) {DrawSpBar(GetVerSpBar());pold.x=spX;pold.y=spY;return;}
        if((fDragHor=PtInRect(GetHorSpBar(),p))) {DrawSpBar(GetHorSpBar());pold.x=spX;pold.y=spY;return;}
        //if(fDragVer||fDragVer) MessageBox(hwnd,"asd","asd",MB_OK);
    }
    void Sp_LBUp(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        POINT p;p.x=LOWORD(lParam);p.y=HIWORD(lParam);
        RECT rect;GetClientRect(hwnd,&rect);
        if(fDragVer)
        {
            DrawSpBar(GetVerSpBar());fDragVer=fMoveVer=false;
            SizeWindowContents(rect.right, rect.bottom);ReleaseCapture();return;
        }
        if(fDragHor)
        {
            DrawSpBar(GetHorSpBar());fDragHor=fMoveHor=false;
            SizeWindowContents(rect.right, rect.bottom);ReleaseCapture();return;
        }
    }
    void Sp_MouseMove(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        POINT p;
        p.x=LOWORD(lParam);p.y=HIWORD(lParam);
        if(wParam & MK_LBUTTON)//only handle mouse LeftButton drag and moved
        {
            if(fDragVer)
            {
                fMoveVer=true;
                spX=pold.x;DrawSpBar(GetVerSpBar());
                spX=p.x;DrawSpBar(GetVerSpBar());
                pold=p;return;
            }
            if(fDragHor)
            {
                fMoveHor=true;
                spY=pold.y;DrawSpBar(GetHorSpBar());
                spY=p.y;DrawSpBar(GetHorSpBar());
                pold=p;return;
            }
        }
    }
    void DrawSpBar(LPRECT lpRect)
    {
        //InvalidateRect(hwndMain,NULL,false);
        HDC hdc;
        hdc = GetDC(hwndMain);
     static WORD _dotPatternBmp[8] =
     {
      0x00aa, 0x0055, 0x00aa, 0x0055,
      0x00aa, 0x0055, 0x00aa, 0x0055
     };

     HBITMAP hbm;
     HBRUSH  hbr, hbrushOld;

     hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
     hbr = CreatePatternBrush(hbm);

     SetBrushOrgEx(hdc, lpRect->left, lpRect->top, 0);
     hbrushOld = (HBRUSH)SelectObject(hdc, hbr);

     PatBlt(hdc, lpRect->left, lpRect->top, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top, PATINVERT);
        
     SelectObject(hdc, hbrushOld);

     DeleteObject(hbr);
     DeleteObject(hbm);
     ReleaseDC(hwndMain,hdc);
       
    }
    LPRECT GetVerSpBar()
    {
        rectSpVer.left=spX;
        rectSpVer.top=0;
        rectSpVer.right=spX+spBar;
        rectSpVer.bottom=CLIENT_H;
        return &rectSpVer;
    }
    LPRECT GetHorSpBar()
    {
        rectSpHor.left=spX+spBar;
        rectSpHor.top=spY;
        rectSpHor.right=CLIENT_W;
        rectSpHor.bottom=spY+spBar;
        return &rectSpHor;
    }

    void SetWndCenter(HWND hwnd)
    {
        AdjustWindowRect(&cliRect,WS_OVERLAPPEDWINDOW,false);
        int WIN_W = cliRect.right - cliRect.left;
        int WIN_H = cliRect.bottom - cliRect.top;
        cliRect.left = (GetSystemMetrics(SM_CXSCREEN)-WIN_W)/2;
        cliRect.top = (GetSystemMetrics(SM_CYSCREEN)-WIN_H)/2;
        cliRect.right = cliRect.left + WIN_W;
        cliRect.bottom = cliRect.top + WIN_H;
        SetWindowPos(hwnd,HWND_TOPMOST,cliRect.left,cliRect.top,WIN_W,WIN_H, SWP_SHOWWINDOW);
    }

    代码注释不是很全,而且还有很多要补充的地方,如:拖动分割条的限制,离窗口一定距离就不再拖动等

    如有问题请留言,欢迎交流。

  • 相关阅读:
    第十五讲 实例模式
    第十四讲 实例模式
    将博客搬至CSDN
    CSU 1616: Heaps(区间DP)
    hdu 1281棋盘游戏(二分匹配)
    hdu 1042 N!(大数的阶乘)
    hdu 3371 Connect the Cities (最小生成树Prim)
    hdu 4502吉哥系列故事——临时工计划 (简单DP)
    hdu1230火星A+B (大数题)
    hdu1301 Jungle Roads (Prim)
  • 原文地址:https://www.cnblogs.com/gameNote/p/3528704.html
Copyright © 2011-2022 走看看