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

时间:2011-09-26 17:06:52

标签: c++ windows winapi user-interface 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);
}

我做错了什么?

UPD:

  

在黑暗中拍摄:你正在处理中间按钮点击。您是否有机会点击鼠标左键或右键? :)

确定。现在我使用WM_LBUTTONUP或WM_LBUTTONDOWN。什么都没发生。

UPD2:

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

我放置了这段代码

RECT rect;
GetClientRect(hwnd, &rect);
InvalidateRect(hwnd, &rect, true);
在EndPaint之前

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

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

我在RestoreWindow()中执行此操作。

我还不知道问题是什么......

UPD3:

  

InvalidateRect()需要在SetPixel之后的WM_?BUTTONDOWN处理程序中发生(不在RestoreWindow()中) - 这是告诉Windows你想要首先获得WM_PAINT的东西。

确定。我在你写这封邮件之前已经完成了。还是不行。

UPD4:

非常感谢,雷米!谢谢你们所有人。好吧!!

2 个答案:

答案 0 :(得分:6)

两件事。

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

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

答案 1 :(得分:4)

当您致电RestoreWindow()在屏幕上绘制位图时,您将消除用于绘制像素的memoryDC变量。您仍然会将位图选入您现在丢失的原始HDC,并且无法同时将位图选择到多个HDC中(SelectObject()的MSDN文档说明了这一点)。所以你实际上并没有在屏幕上绘制位图。

无需在CreateCompatibleDC()内拨打SelectObject()RestoreWindow(),因为您已经在HDC内设置了位图和内存StoreWindow(),所以他们原样使用它们。

试试这个:

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