我应该如何绘制彩色矩形
How am i supposed to draw colored rectangles
当我用左键绘制矩形时,它们应该是随机着色的。它们不仅要用边框填充颜色
我曾尝试使用钢笔和刷子,但没有用。我认为这是因为我用来绘制它们的方法。但我不知道该怎么做。
这是我的代码:
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);
}
现在您主要缺少两件事:
- 在绘制矩形的位置,您并未创建和选择画笔,因此默认画笔用于填充矩形。
- 在您处理 WM_LBUTTONUP 的地方,在将矩形添加到要绘制的矩形矢量后,您并没有使该矩形无效。所以它不会被绘制(直到你做了一些强制它重新绘制的事情,比如最小化和恢复它)。
这就是您错过的全部内容。
因此,在 WM_LBUTTONUP 处理程序的末尾,您可以将对 UpdateWindow
的调用(此处不需要)替换为对 InvalidateRect
的调用,例如这个:InvalidateRect(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;
当我用左键绘制矩形时,它们应该是随机着色的。它们不仅要用边框填充颜色 我曾尝试使用钢笔和刷子,但没有用。我认为这是因为我用来绘制它们的方法。但我不知道该怎么做。 这是我的代码:
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);
}
现在您主要缺少两件事:
- 在绘制矩形的位置,您并未创建和选择画笔,因此默认画笔用于填充矩形。
- 在您处理 WM_LBUTTONUP 的地方,在将矩形添加到要绘制的矩形矢量后,您并没有使该矩形无效。所以它不会被绘制(直到你做了一些强制它重新绘制的事情,比如最小化和恢复它)。
这就是您错过的全部内容。
因此,在 WM_LBUTTONUP 处理程序的末尾,您可以将对 UpdateWindow
的调用(此处不需要)替换为对 InvalidateRect
的调用,例如这个:InvalidateRect(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;