首页 > 解决方案 > 我应该如何绘制彩色矩形

问题描述

当我用左键绘制矩形时,它们应该是随机着色的。它们必须填充颜色,不仅是我尝试使用钢笔和画笔的边框,但它不起作用。我认为这是因为我用来绘制它们的方法。但我不知道该怎么做。这是我的代码:

POINT LeftButtonDown;
POINT ptCurrent;
POINT ptClicked;
vector<CRect> vRect;
bool isRubberBand = false;
bool IsClicked(CRect r, int x, int y);

void select(HWND hWnd, CRect r);
void deselect(HWND hWnd, CRect r);
void DrawRubberBand(HWND hWnd);
void MoveFromTo(HDC hdc, CRect &rectSelected, POINTS anchor, POINTS now);

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CRect add;
static CRect rectSelected;
TCHAR s[100] = L"";
HDC             hdc;
static POINTS   anchor;

switch (message)
{
case WM_COMMAND:
{
    int wmId = LOWORD(wParam);
    // Parse the menu selections:
    switch (wmId)
    {
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}
break;

case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    // TODO: Add any drawing code that uses hdc here...
    for (auto& rc : vRect)
    {
        Rectangle(hdc,
            rc.left,
            rc.top,
            rc.right,
            rc.bottom
        );
    }
    EndPaint(hWnd, &ps);
}
break;

case WM_LBUTTONDOWN:
{
    LeftButtonDown.x = LOWORD(lParam); //Start point
    LeftButtonDown.y = HIWORD(lParam);

    isRubberBand = true;

    ptCurrent.x = LOWORD(lParam); //current point
    ptCurrent.y = HIWORD(lParam);

    DrawRubberBand(hWnd); //draw the rect
}
break;

case WM_LBUTTONUP: // adding to a vector
{
    if (!isRubberBand)
    {
        return 0;
    }
    isRubberBand = false;

    //InvalidateRect(hWnd, NULL, TRUE);
    add.SetRect(LeftButtonDown.x, LeftButtonDown.y, ptCurrent.x, ptCurrent.y); //setting the coords of the rect
    vRect.push_back(add); //add the rect
    UpdateWindow(hWnd);
}
break;

case WM_MOUSEMOVE:

    if (wParam & MK_LBUTTON) //drawing the rectangle
    {
        hdc = GetDC(hWnd);
        if (!isRubberBand)
        {
            break;
        }
        DrawRubberBand(hWnd);

        ptCurrent.x = LOWORD(lParam);
        ptCurrent.y = HIWORD(lParam);

        DrawRubberBand(hWnd);

    }
    if (wParam & MK_RBUTTON) //dragging the rectangle
    {
        hdc = GetDC(hWnd);
        POINTS now = MAKEPOINTS(lParam);
        if (PtInRect(&rectSelected, POINT{ now.x,now.y }))
        {
            SetROP2(hdc, R2_NOTXORPEN);
            MoveFromTo(hdc, rectSelected, anchor, now);
            InvalidateRect(hWnd, NULL, TRUE);
            anchor = MAKEPOINTS(lParam);
        }

        ReleaseDC(hWnd, hdc);
    }
    break;

case WM_RBUTTONDOWN:
{
    bool isFind = false;
    int x{ LOWORD(lParam) }, y{ HIWORD(lParam) };
    for (auto& rc : vRect)
    {
        if (!isFind && IsClicked(rc, x, y))
        {
            select(hWnd, rc);
            rectSelected = rc;
            anchor = MAKEPOINTS(lParam);
            isFind = TRUE;
        }
        else {
            deselect(hWnd, rc);
        }
    }
    //select-deselect
}
break;
case WM_RBUTTONUP:
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    break;
default:
    return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}


bool IsClicked(CRect r, int x, int y)
{
    POINT pt{ x, y };
return (bool)PtInRect(&r, pt);
}
void select(HWND hWnd, CRect r) {
HDC hdc = GetDC(hWnd);
HPEN selectPen = CreatePen(PS_DOT, 0, RGB(255, 0, 0));
SelectObject(hdc, selectPen);
Rectangle(hdc, r.left, r.top, r.right, r.bottom);
DeleteObject(selectPen);
}
void deselect(HWND hWnd, CRect r) {
HDC hdc = GetDC(hWnd);
Rectangle(hdc, r.left, r.top, r.right, r.bottom);
}

void DrawRubberBand(HWND hWnd) {
HDC hdc = GetDC(hWnd);

SetROP2(hdc, R2_NOT);
SelectObject(hdc, GetStockObject(NULL_BRUSH));
Rectangle(hdc,
    LeftButtonDown.x,
    LeftButtonDown.y,
    ptCurrent.x,
    ptCurrent.y
);
ReleaseDC(hWnd, hdc);
}
void MoveFromTo(HDC hdc, CRect &rectSelected, POINTS anchor, POINTS now)
{
Rectangle(hdc, rectSelected.left, rectSelected.top, rectSelected.right, rectSelected.bottom);
for (auto it = vRect.begin();it != vRect.end();it++)
{
    if (*it == rectSelected)
    {
        vRect.erase(it);
        break;
    }
}
rectSelected.left = rectSelected.left + now.x - anchor.x; //x
rectSelected.top = rectSelected.top + now.y - anchor.y;    //y
rectSelected.right = rectSelected.right + now.x - anchor.x; //x
rectSelected.bottom = rectSelected.bottom + now.y - anchor.y; //y
Rectangle(hdc, rectSelected.left, rectSelected.top, rectSelected.right, rectSelected.bottom);
vRect.push_back(rectSelected);
}

标签: winapidraw

解决方案


现在你主要错过了两件事:

  1. 在您绘制矩形的地方,您没有创建和选择画笔,因此使用默认画笔填充您的矩形。
  2. 在您处理 WM_LBUTTONUP 的地方,在将矩形添加到要绘制的矩形矢量后,您不会使矩形无效。所以它不会被绘制(直到你做了一些迫使它重新绘制的事情,比如最小化和恢复它)。

这几乎就是你所缺少的。

因此,在您的 WM_LBUTTONUP 处理程序结束时,您可以将您对UpdateWindow, 的调用(此处不需要)替换为对 的调用,如下所示InvalidateRectInvalidateRect(hWnd, add, true);请注意,这只会使我们刚刚绘制的矩形无效(您的其他代码为无效矩形传递 NULL,因此它使所有内容都无效)。只有使真正无效的部分无效才能提高效率(在某种程度上)。

在您的 WM_PAINT 处理程序中,您需要这样的代码:

case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    // For the moment, I'm just hard-coding a fairly bright red fill:
    HBRUSH brush = CreateSolidBrush(RGB(192, 0, 0));
    HBRUSH original = (HBRUSH)SelectObject(hdc, brush);

    // TODO: Add any drawing code that uses hdc here...
    for (auto& rc : vRect)
    {
        Rectangle(hdc,
            rc.left,
            rc.top,
            rc.right,
            rc.bottom
        );
    }
    // restore original brush before releasing the DC:
    SelectObject(hdc, original);
    EndPaint(hWnd, &ps);

    // And destroy the brush:
    DeleteObject(brush);
}
break;

推荐阅读