如何在 C++ 中设置鼠标点击像素在 GUI 窗口中使用 WinApi (GDI)?
我试图通过鼠标单击来设置像素,但单击时没有任何反应。这是我的代码的一部分。
首先,我在 WM_SIZE 中控制窗口大小的变化。 比,第一次当我想通过鼠标设置像素时,我获取窗口的宽度和高度,然后将窗口的内容复制到内存 HDC 和 HBITMAP (在存储窗口中)(HBITMAP 大小等于(宽度,高度))。事实上,我复制到内存只是清除窗口。
无论如何,我将像素设置为内存 DC。在下一个 WM_PAINT 消息处理中,我将内存 DC 绘制到屏幕上。
.....
case WM_SIZE:
{
CheckWidthHeight();
break;
}
case WM_MBUTTONDOWN:
{
if (firstTimeDraw)
{
CheckWidthHeight();
StoreWindow();
firstTimeDraw = false;
}
SetPixel(memoryDC, LOWORD(lParam), HIWORD(lParam), RGB(0,0,0));
break;
}
case WM_PAINT:
{
RestoreWindow();
break;
}
.....
我的函数和变量在哪里:
HDC memoryDC;
HBITMAP memoryBitmap;
int width = 0, height = 0;
bool firstTimeDraw = true;
void CheckWidthHeight()
{
RECT clientRect;
GetClientRect(hwnd, &clientRect);
width = clientRect.right - clientRect.left;
height = clientRect.bottom - clientRect.top;
}
//Copy real window content to memory window
void StoreWindow()
{
HDC hDC = GetDC(hwnd);
memoryDC = CreateCompatibleDC(hDC);
memoryBitmap = CreateCompatibleBitmap(hDC, width, height);
SelectObject(memoryDC, memoryBitmap);
BitBlt(memoryDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hDC);
}
//Copy memory windows content to real window at the screen
void RestoreWindow()
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd, &ps);
memoryDC = CreateCompatibleDC(hDC);
SelectObject(memoryDC, memoryBitmap);
BitBlt(hDC, 0, 0, width, height, memoryDC, 0, 0, SRCCOPY);
EndPaint(hwnd, &ps);
}
我做错了什么?
更新:
黑暗中的一枪:您正在处理中间按钮的点击。您是否有机会点击鼠标左键或右键? :)
好的。现在我使用 WM_LBUTTONUP 或 WM_LBUTTONDOWN。再也没有发生任何事情。
更新2:
- 当您更改内存 DC 时,您还需要使受影响的窗口部分无效,以便 Windows 为其生成 WM_PAINT 消息。 InvalidateRect 将是一个很好的起点。
我将此代码放在
RECT rect;
GetClientRect(hwnd, &rect);
InvalidateRect(hwnd, &rect, true);
EndPaint 之前。没有什么。比我在 EndPaint 之后移动它。没有什么。
- 在 WM_PAINT 处理程序中,您需要使用 BeginPaint 提供的 DC,并在完成后调用 EndPaint。
我在 RestoreWindow() 中执行此操作。
我还不知道问题是什么...
UPD3:
InvalidateRect() 需要在 SetPixel 之后的 WM_?BUTTONDOWN 处理程序中发生(而不是在 RestoreWindow() 中) - 它告诉窗口您想要首先获得 WM_PAINT。
好的。在你写这封邮件之前我已经完成了。还是不行啊
UPD4:
非常感谢你,雷米!感谢其余所有人。现在好了!!
I'm trying to set pixel by mouse click, but nothing happens when I click. Here is part of my code.
First, I control window size changing in WM_SIZE.
Than, at first time when I want to set pixel by mouse I get window's width and height, then copy window's content to memory HDC and HBITMAP (in Store Window) (HBITMAP size equal to (width,height)). In fact, I copy to memory only clear window.
And than in any case I set pixel to memory DC. In next WM_PAINT message handling I'm drawing memory DC to screen.
.....
case WM_SIZE:
{
CheckWidthHeight();
break;
}
case WM_MBUTTONDOWN:
{
if (firstTimeDraw)
{
CheckWidthHeight();
StoreWindow();
firstTimeDraw = false;
}
SetPixel(memoryDC, LOWORD(lParam), HIWORD(lParam), RGB(0,0,0));
break;
}
case WM_PAINT:
{
RestoreWindow();
break;
}
.....
where my functions and variables is:
HDC memoryDC;
HBITMAP memoryBitmap;
int width = 0, height = 0;
bool firstTimeDraw = true;
void CheckWidthHeight()
{
RECT clientRect;
GetClientRect(hwnd, &clientRect);
width = clientRect.right - clientRect.left;
height = clientRect.bottom - clientRect.top;
}
//Copy real window content to memory window
void StoreWindow()
{
HDC hDC = GetDC(hwnd);
memoryDC = CreateCompatibleDC(hDC);
memoryBitmap = CreateCompatibleBitmap(hDC, width, height);
SelectObject(memoryDC, memoryBitmap);
BitBlt(memoryDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hDC);
}
//Copy memory windows content to real window at the screen
void RestoreWindow()
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd, &ps);
memoryDC = CreateCompatibleDC(hDC);
SelectObject(memoryDC, memoryBitmap);
BitBlt(hDC, 0, 0, width, height, memoryDC, 0, 0, SRCCOPY);
EndPaint(hwnd, &ps);
}
What I'm doing wrong?
UPD:
A shot in the dark: You're handling the middle button click. Are you by any chance clicking on the left or right mouse buttons? :)
Ok. Now I use WM_LBUTTONUP or WM_LBUTTONDOWN. Nothing happens again.
UPD2:
- When you change the memory DC, you'll also want to invalidate the part of the window that is affected so that Windows will generate a WM_PAINT message for it. InvalidateRect would be a good place to start.
I placed this code
RECT rect;
GetClientRect(hwnd, &rect);
InvalidateRect(hwnd, &rect, true);
before EndPaint. Nothing. Than I move it after EndPaint. Nothing.
- In the WM_PAINT handler, you need to use a DC provided by BeginPaint and call EndPaint when you're done with it.
I do it in RestoreWindow().
I don't know yet what's the problem...
UPD3:
InvalidateRect() needs to happen in the WM_?BUTTONDOWN handler after the SetPixel (not in RestoreWindow())- it's what tells windows that you want to get a WM_PAINT in the first place.
Ok. I've done it before you wrote this message. Still don't work.
UPD4:
Thank you a lot, Remy! Thank you to all the rest. Now all right!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有两件事。
当您更改内存 DC 时,您还需要使受影响的窗口部分无效,以便 Windows 为其生成 WM_PAINT 消息。 InvalidateRect 将是一个很好的起点。
在 WM_PAINT 处理程序中,您需要使用 BeginPaint 提供的 DC,并在完成后调用 EndPaint。
Two things.
When you change the memory DC, you'll also want to invalidate the part of the window that is affected so that Windows will generate a WM_PAINT message for it. InvalidateRect would be a good place to start.
In the WM_PAINT handler, you need to use a DC provided by BeginPaint and call EndPaint when you're done with it.
当您调用
RestoreWindow()
在屏幕上绘制位图时,您将清除用于绘制像素的memoryDC
变量。位图仍然被选入您现在丢失的原始 HDC,并且位图不能同时选入多个 HDC(HDC
的 MSDN 文档) >SelectObject() 就是这么说的)。因此,您实际上根本没有在屏幕上绘制位图。无需在
RestoreWindow()
内部调用CreateCompatibleDC()
或SelectObject()
,因为您已经拥有位图和内存HDC
在StoreWindow()
内部设置,因此他们按原样使用它们。试试这个:
When you call
RestoreWindow()
to draw the bitmap onscreen, you are wiping out yourmemoryDC
variable that you used to draw the pixels with. The bitmap is still selected into the originalHDC
that you have now lost, and a bitmap cannot be selected into multipleHDC
s at the same time (the MSDN documentation forSelectObject()
says as much). So you are not actually drawing the bitmap onscreen at all.There is no need to call
CreateCompatibleDC()
orSelectObject()
inside ofRestoreWindow()
because you already have the bitmap and memoryHDC
set up inside ofStoreWindow()
, so they use them as-is instead.Try this: