V
V
Vlad_beg2019-03-24 16:48:06
C++ / C#
Vlad_beg, 2019-03-24 16:48:06

How to correctly draw a line in WINAPI?

When clicking, a line should be drawn from the point where the mouse was pressed and end at the point where the mouse was released. In my case, nothing happens, I just can not understand what is missing.

LONG WINAPI WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{

    HDC hdc;
    BOOL fDraw = FALSE;
    POINT ptPrevious = { 0 };
    HPEN Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));


    switch (Message) {
        case WM_LBUTTONDOWN: {
            fDraw = TRUE;
            ptPrevious.x = LOWORD(lParam);
            ptPrevious.y = HIWORD(lParam);
            break;
        }

        case WM_LBUTTONUP: {
            if (fDraw)
            {
                hdc = GetDC(hWnd);
                MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
                LineTo(hdc, LOWORD(lParam), HIWORD(lParam));
                ReleaseDC(hWnd, hdc);
            }
            fDraw = FALSE;
            break;
        }


        case WM_PAINT: {
            if (fDraw)
            {
                hdc = GetDC(hWnd);
                MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
                LineTo(hdc, ptPrevious.x = LOWORD(lParam),
                    ptPrevious.y = HIWORD(lParam));
                ReleaseDC(hWnd, hdc);
            }
            break;
        }


        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hWnd, Message, wParam, lParam);
    }
    return 0;
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
SerJook, 2019-03-24
@Vlad_beg

A few comments on your code:
Pen, ptPrevious, fDraw variables are not saved between function calls, make them static or global. In the current version, your code creates a HUGE number of GDI objects.

static HPEN Pen =  CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
static BOOL fDraw = FALSE;
static POINT ptPrevious = { 0, 0 };

You cannot use GetDC() when processing WM_PAINT. In case you haven't noticed, this is CPU intensive.
It would be correct to use BeginPaint() and EndPaint();
case WM_PAINT: {
        PAINTSTRUCT ps;
        hdc = BeginPaint(hWnd, &ps);
        // TODO: рисовать здесь
        EndPaint(hWnd, &ps);
        break;
    }

To prevent the drawing from being erased when the window is updated, you need to draw in the Back Buffer (I don’t know how it is in Russian). To do this, you need to create a BITMAP using CreateCompatibleBitmap, an HDC using CreateCompatibleDC, load a BITMAP into the created HDC using SelectObject, and draw on the HDC. Then call BitBlt and copy the backbuffer to the window's real HDC (inside the WM_PAINT handler).
Another option (without a back buffer): store your line coordinates in an array, and output them all in the WM_PAINT handler.
If you don't want the drawing to be erased, just remove the WM_PAINT handler.
Another small quibble: instead of LOWORD(lParam) when getting coordinates, you need to use GET_X_LPARAM and GET_Y_LPARAM.
ptPrevious.x = GET_X_LPARAM(lParam);
ptPrevious.y = GET_Y_LPARAM(lParam);

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question