Как установить пиксель при щелчке мышью в C ++, используя WinApi (GDI) в окне GUI? - PullRequest
4 голосов
/ 26 сентября 2011

Я пытаюсь установить пиксель щелчком мыши, но при нажатии ничего не происходит.Вот часть моего кода.

Во-первых, я контролирую изменение размера окна в WM_SIZE.Затем в первый раз, когда я хочу установить пиксель мышью, я получаю ширину и высоту окна, затем копирую содержимое окна в память HDC и HBITMAP (в окне Store) (размер HBITMAP равен (width, height)).На самом деле я копирую в память только чистое окно.

И чем в любом случае я устанавливаю пиксель в память постоянного тока.В следующей обработке сообщений 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 будет хорошим местом для начала.

Я поместил этот код

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

перед EndPaint.Ничего такого.Чем я перемещаю его после EndPaint.Ничего.

  1. В обработчике WM_PAINT вам нужно использовать DC, предоставляемый BeginPaint, и вызывать EndPaint, когда вы закончите с ним.

Я делаю это в RestoreWindow ().

Я пока не знаю, в чем проблема ...

UPD3:

Должно произойти InvalidateRect ()в обработчике WM_? BUTTONDOWN после SetPixel (не в RestoreWindow ()) - это то, что сообщает Windows, что вы хотите получить WM_PAINT в первую очередь.

Ok.Я сделал это до того, как ты написал это сообщение.Все еще не работает.

UPD4:

Большое спасибо, Реми!Спасибо всем остальным.Теперь все в порядке !!

Ответы [ 2 ]

6 голосов
/ 26 сентября 2011

Две вещи.

  1. Когда вы изменяете DC памяти, вы также захотите сделать недействительной ту часть окна, на которую влияет, чтобы Windows сгенерировала для него сообщение WM_PAINT. InvalidateRect будет хорошим местом для начала.

  2. В обработчике WM_PAINT вам нужно использовать DC, предоставляемый BeginPaint, и вызывать EndPaint, когда вы закончите с ним.

4 голосов
/ 27 сентября 2011

Когда вы вызываете RestoreWindow() для рисования растрового изображения на экране, вы стираете переменную memoryDC, с которой вы рисовали пиксели.Растровое изображение по-прежнему выбрано в исходном HDC, которое вы сейчас потеряли, и растровое изображение не может быть выбрано одновременно в нескольких HDC (документация MSDN для SelectObject() говорит об этом слишком много).Таким образом, вы вообще не рисуете растровое изображение на экране.

Нет необходимости вызывать 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;
}
...
...