开发者社区> 问答> 正文

《windows程序设计》“blokout1.c”的疑问

这个程序点击拖动鼠标可以画出一个矩形轮廓,我的问题有两个,都和一个函数有关。

1.在


case WM_MOUSEMOVE:
        if (fBlocking)
        {
            SetCursor(LoadCursor(NULL, IDC_CROSS));

            DrawBoxOutline(hwnd, ptBeg, ptEnd);

            ptEnd.x = GET_X_LPARAM(lParam);
            ptEnd.y = GET_Y_LPARAM(lParam);

            DrawBoxOutline(hwnd, ptBeg, ptEnd);
        }
        return 0;

中,为什么需要调用两次DrawBoxOutline(hwnd, ptBeg, ptEnd);为什么仅调用其中任何一个都会导致不同的绘画效果?(具体效果请自行实验)

1.在


case WM_CHAR:
        if (fBlocking & (wParam == '\x1B'))     // i.e., Escape
        {
            DrawBoxOutline(hwnd, ptBeg, ptEnd);

            SetCursor(LoadCursor(NULL, IDC_ARROW));
            DrawBoxOutline(hwnd, ptBeg, ptEnd);
            fBlocking = FALSE;
        }
        return 0;

中,为什么拖动鼠标的过程中按ESC之后矩形反而消失了?函数中不是调用了DrawBoxOutline(hwnd, ptBeg, ptEnd);这个函数吗?

完整程序如下:

/*-----------------------------------------
BLOKOUT1.C -- Mouse Button Demo Program
(c) Charles Petzold, 1998
-----------------------------------------*/

#include <windows.h>
#include <windowsx.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("BlokOut1");
    HWND         hwnd;
    MSG          msg;
    WNDCLASS     wndclass;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("Program requires Windows NT!"),
            szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName, TEXT("Mouse Button Demo"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, NULL);

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);

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

void DrawBoxOutline(HWND hwnd, POINT ptBeg, POINT ptEnd)
{
    HDC hdc;

    hdc = GetDC(hwnd);

    SetROP2(hdc, R2_NOT);
    SelectObject(hdc, GetStockObject(NULL_BRUSH));
    Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y);

    ReleaseDC(hwnd, hdc);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static BOOL  fBlocking, fValidBox;
    static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd;
    HDC          hdc;
    PAINTSTRUCT  ps;

    switch (message)
    {
    case WM_LBUTTONDOWN:
        ptBeg.x = ptEnd.x = GET_X_LPARAM(lParam);
        ptBeg.y = ptEnd.y = GET_Y_LPARAM(lParam);
        
        DrawBoxOutline(hwnd, ptBeg, ptEnd);
        SetCursor(LoadCursor(NULL, IDC_CROSS));

        fBlocking = TRUE;
        return 0;

    case WM_MOUSEMOVE:
        if (fBlocking)
        {
            SetCursor(LoadCursor(NULL, IDC_CROSS));

            DrawBoxOutline(hwnd, ptBeg, ptEnd);

            ptEnd.x = GET_X_LPARAM(lParam);
            ptEnd.y = GET_Y_LPARAM(lParam);

            DrawBoxOutline(hwnd, ptBeg, ptEnd);
        }
        return 0;

    case WM_LBUTTONUP:
        if (fBlocking)
        {
            ptBoxBeg = ptBeg;
            ptBoxEnd.x = GET_X_LPARAM(lParam);
            ptBoxEnd.y = GET_Y_LPARAM(lParam);

            SetCursor(LoadCursor(NULL, IDC_ARROW));

            fBlocking = FALSE;
            fValidBox = TRUE;

            InvalidateRect(hwnd, NULL, TRUE);
        }
        return 0;

    case WM_CHAR:
        if (fBlocking & (wParam == '\x1B'))     // i.e., Escape
        {
            DrawBoxOutline(hwnd, ptBeg, ptEnd);

            SetCursor(LoadCursor(NULL, IDC_ARROW));
            
            fBlocking = FALSE;
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

更新

我的问题是拖动鼠标过程中,调用一次与两次DrawBoxOutline()为什么会产生如下两幅图的差别。两张图都是鼠标从左上角拖动到右下角。
screenshot
screenshot
这张图拖动过程中会显示很多的矩形轨迹

展开
收起
杨冬芳 2016-05-30 19:53:43 2401 0
1 条回答
写回答
取消 提交回答
  • IT从业

    你的提问与你的完整代码不符: 提问中 WM_CHAR 的处理程序里 DrawBoxOutline 被调用了两次,个人认为后者正确。

    居然还看到有人玩 WIN32 编程,好怀念啊

    所有的奥秘都在 DrawBoxOutline 中,请看这句:

    SetROP2(hdc, R2_NOT);

    这句话说明对绘图区域执行的是 非 操作,即 调用一次就绘上去,调用两次则擦除。

    嗯可以回答了:

    1.在绘制新矩形前,要将旧矩形擦除,故调用两次

    2.对上一次的矩形区域调用 DrawBoxOutline,其效果是将其擦除

    2019-07-17 19:21:01
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
《云服务器运维之Windows篇》 立即下载
TAKING WINDOWS 10 KERNEL 立即下载
ECS运维指南之Windows系统诊断 立即下载