如何在 C++ 中设置鼠标点击像素在 GUI 窗口中使用 WinApi (GDI)?

发布于 2024-12-06 17:28:07 字数 2542 浏览 2 评论 0原文

我试图通过鼠标单击来设置像素,但单击时没有任何反应。这是我的代码的一部分。

首先,我在 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:

  1. 当您更改内存 DC 时,您还需要使受影响的窗口部分无效,以便 Windows 为其生成 WM_PAINT 消息。 InvalidateRect 将是一个很好的起点。

我将此代码放在

RECT rect;
GetClientRect(hwnd, &rect);
InvalidateRect(hwnd, &rect, true);

EndPaint 之前。没有什么。比我在 EndPaint 之后移动它。没有什么。

  1. 在 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:

  1. 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.

  1. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

贩梦商人 2024-12-13 17:28:07

有两件事。

  1. 当您更改内存 DC 时,您还需要使受影响的窗口部分无效,以便 Windows 为其生成 WM_PAINT 消息。 InvalidateRect 将是一个很好的起点。

  2. 在 WM_PAINT 处理程序中,您需要使用 BeginPaint 提供的 DC,并在完成后调用 EndPaint。

Two things.

  1. 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.

  2. In the WM_PAINT handler, you need to use a DC provided by BeginPaint and call EndPaint when you're done with it.

红玫瑰 2024-12-13 17:28:07

当您调用 RestoreWindow() 在屏幕上绘制位图时,您将清除用于绘制像素的 memoryDC 变量。位图仍然被选入您现在丢失的原始 HDC,并且位图不能同时选入多个 HDC(HDC 的 MSDN 文档) >SelectObject() 就是这么说的)。因此,您实际上根本没有在屏幕上绘制位图。

无需在 RestoreWindow() 内部调用 CreateCompatibleDC()SelectObject(),因为您已经拥有位图和内存HDCStoreWindow() 内部设置,因此他们按原样使用它们。

试试这个:

HDC memoryDC = NULL;
HBITMAP memoryBitmap = NULL;
int width = 0, height = 0;

void CheckWidthHeight() 
{
    RECT clientRect;
    GetClientRect(hwnd, &clientRect);
    width = clientRect.right - clientRect.left;
    height = clientRect.bottom - clientRect.top;
}

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);
}

void RestoreWindow()
{
    PAINTSTRUCT ps;
    HDC hDC = BeginPaint(hwnd, &ps);
    if (memoryDC)
        BitBlt(hDC, 0, 0, width, height, memoryDC, 0, 0, SRCCOPY);
    EndPaint(hwnd, &ps);
} 

...
case WM_SIZE:
{
    CheckWidthHeight();
    break;
}

case WM_LBUTTONDOWN:
{
    if (!memoryDC)
        StoreWindow();

    if (memoryDC)
    {
        SetPixel(memoryDC, LOWORD(lParam), HIWORD(lParam), RGB(0,0,0));

        RECT rect;
        rect.left = LOWORD(lParam);
        rect.top = HIWORD(lParam);
        rect.right = rect.left + 1;
        rect.bottom = rect.top + 1;
        InvalidateRect(hwnd, &rect, TRUE);
    }

    break;
}

case WM_PAINT:
{
    RestoreWindow();
    break;
}
...

When you call RestoreWindow() to draw the bitmap onscreen, you are wiping out your memoryDC variable that you used to draw the pixels with. The bitmap is still selected into the original HDC that you have now lost, and a bitmap cannot be selected into multiple HDCs at the same time (the MSDN documentation for SelectObject() says as much). So you are not actually drawing the bitmap onscreen at all.

There is no need to call CreateCompatibleDC() or SelectObject() inside of RestoreWindow() because you already have the bitmap and memory HDC set up inside of StoreWindow(), so they use them as-is instead.

Try this:

HDC memoryDC = NULL;
HBITMAP memoryBitmap = NULL;
int width = 0, height = 0;

void CheckWidthHeight() 
{
    RECT clientRect;
    GetClientRect(hwnd, &clientRect);
    width = clientRect.right - clientRect.left;
    height = clientRect.bottom - clientRect.top;
}

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);
}

void RestoreWindow()
{
    PAINTSTRUCT ps;
    HDC hDC = BeginPaint(hwnd, &ps);
    if (memoryDC)
        BitBlt(hDC, 0, 0, width, height, memoryDC, 0, 0, SRCCOPY);
    EndPaint(hwnd, &ps);
} 

...
case WM_SIZE:
{
    CheckWidthHeight();
    break;
}

case WM_LBUTTONDOWN:
{
    if (!memoryDC)
        StoreWindow();

    if (memoryDC)
    {
        SetPixel(memoryDC, LOWORD(lParam), HIWORD(lParam), RGB(0,0,0));

        RECT rect;
        rect.left = LOWORD(lParam);
        rect.top = HIWORD(lParam);
        rect.right = rect.left + 1;
        rect.bottom = rect.top + 1;
        InvalidateRect(hwnd, &rect, TRUE);
    }

    break;
}

case WM_PAINT:
{
    RestoreWindow();
    break;
}
...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文