Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set pixel on mouse click in C++ using WinApi (GDI) in GUI window?

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!!

like image 470
Abzac Avatar asked Dec 28 '22 13:12

Abzac


1 Answers

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.

like image 101
Mark Ransom Avatar answered Dec 31 '22 14:12

Mark Ransom