[c++]WinApi - Simple Program drawing lines












-1














I'm new and I'm trying to write a simple program drawing lines with the mouse.
I have a problem with drawing these lines, because it leaves traces behind.



Here is an image of my problem:



image



And here is a sample of my code:



LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:PostQuitMessage(0);break;

case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
last_x = LOWORD(lParam);
last_y = HIWORD(lParam);
isDown = true;
break;
case WM_MOUSEMOVE:
if (isDown)
{
Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
Box = (HPEN)SelectObject(hdc, Pen);
int x = LOWORD(lParam);
int y = HIWORD(lParam);
MoveToEx(hdc, last_x, last_y, NULL);
LineTo(hdc, x, y);
}
break;
case WM_LBUTTONUP:
isDown = false;
ReleaseDC;
break;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}


EDIT:
Now it's working well, but if You could explain me one another thing, how can i make that my old lines stayed on the Client area when i drawing new lines? Cause now i can draw only one line. Should i use Bitmap to save screen or something?



EDIT:EDIT:
Ok i used Vector to save coordinates of every line. Thank You guys for help!










share|improve this question
























  • "I have problem with drawing this line, cause it leaves traces." - have you considered clearing the screen between each draw?
    – Jesper Juhl
    Nov 12 '18 at 22:31










  • You have a logic issue. Please check this example. docs.microsoft.com/en-us/windows/desktop/gdi/…
    – Naidu
    Nov 12 '18 at 22:56










  • I'm pretty sure ReleaseDC is meant to take a parameter.
    – Jonathan Potter
    Nov 12 '18 at 23:02










  • @Naidu i was trying this example from microsoft, but also didn't work.
    – Kamilen
    Nov 13 '18 at 10:57


















-1














I'm new and I'm trying to write a simple program drawing lines with the mouse.
I have a problem with drawing these lines, because it leaves traces behind.



Here is an image of my problem:



image



And here is a sample of my code:



LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:PostQuitMessage(0);break;

case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
last_x = LOWORD(lParam);
last_y = HIWORD(lParam);
isDown = true;
break;
case WM_MOUSEMOVE:
if (isDown)
{
Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
Box = (HPEN)SelectObject(hdc, Pen);
int x = LOWORD(lParam);
int y = HIWORD(lParam);
MoveToEx(hdc, last_x, last_y, NULL);
LineTo(hdc, x, y);
}
break;
case WM_LBUTTONUP:
isDown = false;
ReleaseDC;
break;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}


EDIT:
Now it's working well, but if You could explain me one another thing, how can i make that my old lines stayed on the Client area when i drawing new lines? Cause now i can draw only one line. Should i use Bitmap to save screen or something?



EDIT:EDIT:
Ok i used Vector to save coordinates of every line. Thank You guys for help!










share|improve this question
























  • "I have problem with drawing this line, cause it leaves traces." - have you considered clearing the screen between each draw?
    – Jesper Juhl
    Nov 12 '18 at 22:31










  • You have a logic issue. Please check this example. docs.microsoft.com/en-us/windows/desktop/gdi/…
    – Naidu
    Nov 12 '18 at 22:56










  • I'm pretty sure ReleaseDC is meant to take a parameter.
    – Jonathan Potter
    Nov 12 '18 at 23:02










  • @Naidu i was trying this example from microsoft, but also didn't work.
    – Kamilen
    Nov 13 '18 at 10:57
















-1












-1








-1







I'm new and I'm trying to write a simple program drawing lines with the mouse.
I have a problem with drawing these lines, because it leaves traces behind.



Here is an image of my problem:



image



And here is a sample of my code:



LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:PostQuitMessage(0);break;

case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
last_x = LOWORD(lParam);
last_y = HIWORD(lParam);
isDown = true;
break;
case WM_MOUSEMOVE:
if (isDown)
{
Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
Box = (HPEN)SelectObject(hdc, Pen);
int x = LOWORD(lParam);
int y = HIWORD(lParam);
MoveToEx(hdc, last_x, last_y, NULL);
LineTo(hdc, x, y);
}
break;
case WM_LBUTTONUP:
isDown = false;
ReleaseDC;
break;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}


EDIT:
Now it's working well, but if You could explain me one another thing, how can i make that my old lines stayed on the Client area when i drawing new lines? Cause now i can draw only one line. Should i use Bitmap to save screen or something?



EDIT:EDIT:
Ok i used Vector to save coordinates of every line. Thank You guys for help!










share|improve this question















I'm new and I'm trying to write a simple program drawing lines with the mouse.
I have a problem with drawing these lines, because it leaves traces behind.



Here is an image of my problem:



image



And here is a sample of my code:



LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:PostQuitMessage(0);break;

case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
last_x = LOWORD(lParam);
last_y = HIWORD(lParam);
isDown = true;
break;
case WM_MOUSEMOVE:
if (isDown)
{
Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
Box = (HPEN)SelectObject(hdc, Pen);
int x = LOWORD(lParam);
int y = HIWORD(lParam);
MoveToEx(hdc, last_x, last_y, NULL);
LineTo(hdc, x, y);
}
break;
case WM_LBUTTONUP:
isDown = false;
ReleaseDC;
break;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}


EDIT:
Now it's working well, but if You could explain me one another thing, how can i make that my old lines stayed on the Client area when i drawing new lines? Cause now i can draw only one line. Should i use Bitmap to save screen or something?



EDIT:EDIT:
Ok i used Vector to save coordinates of every line. Thank You guys for help!







c++ winapi gdi






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 '18 at 12:40







Kamilen

















asked Nov 12 '18 at 22:22









KamilenKamilen

82




82












  • "I have problem with drawing this line, cause it leaves traces." - have you considered clearing the screen between each draw?
    – Jesper Juhl
    Nov 12 '18 at 22:31










  • You have a logic issue. Please check this example. docs.microsoft.com/en-us/windows/desktop/gdi/…
    – Naidu
    Nov 12 '18 at 22:56










  • I'm pretty sure ReleaseDC is meant to take a parameter.
    – Jonathan Potter
    Nov 12 '18 at 23:02










  • @Naidu i was trying this example from microsoft, but also didn't work.
    – Kamilen
    Nov 13 '18 at 10:57




















  • "I have problem with drawing this line, cause it leaves traces." - have you considered clearing the screen between each draw?
    – Jesper Juhl
    Nov 12 '18 at 22:31










  • You have a logic issue. Please check this example. docs.microsoft.com/en-us/windows/desktop/gdi/…
    – Naidu
    Nov 12 '18 at 22:56










  • I'm pretty sure ReleaseDC is meant to take a parameter.
    – Jonathan Potter
    Nov 12 '18 at 23:02










  • @Naidu i was trying this example from microsoft, but also didn't work.
    – Kamilen
    Nov 13 '18 at 10:57


















"I have problem with drawing this line, cause it leaves traces." - have you considered clearing the screen between each draw?
– Jesper Juhl
Nov 12 '18 at 22:31




"I have problem with drawing this line, cause it leaves traces." - have you considered clearing the screen between each draw?
– Jesper Juhl
Nov 12 '18 at 22:31












You have a logic issue. Please check this example. docs.microsoft.com/en-us/windows/desktop/gdi/…
– Naidu
Nov 12 '18 at 22:56




You have a logic issue. Please check this example. docs.microsoft.com/en-us/windows/desktop/gdi/…
– Naidu
Nov 12 '18 at 22:56












I'm pretty sure ReleaseDC is meant to take a parameter.
– Jonathan Potter
Nov 12 '18 at 23:02




I'm pretty sure ReleaseDC is meant to take a parameter.
– Jonathan Potter
Nov 12 '18 at 23:02












@Naidu i was trying this example from microsoft, but also didn't work.
– Kamilen
Nov 13 '18 at 10:57






@Naidu i was trying this example from microsoft, but also didn't work.
– Kamilen
Nov 13 '18 at 10:57














1 Answer
1






active

oldest

votes


















1














You are getting residual traces because you are not erasing your old drawings before drawing a new line, or at least updating last_x and last_y on each move so that a new line connects to the end of the previous line, like in Microsoft's example.



But, you really should not draw on the window directly in the mouse message handlers at all. As soon as the window needs a repaint for any reason, all of your drawing will be lost. The correct way to handle this is to perform all of your drawing in a WM_PAINT message handler instead. Use the mouse messages to keep track of line information as needed, and then do all of the actual drawing in WM_PAINT only.



For example:



LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
break;

case WM_DESTROY:
DeleteObject(Pen);
PostQuitMessage(0);
break;

case WM_LBUTTONDOWN:
x = last_x = LOWORD(lParam);
y = last_y = HIWORD(lParam);
isDown = true;
InvalidateRect(hwnd, NULL, TRUE);
break;

case WM_MOUSEMOVE:
if (isDown)
{
x = LOWORD(lParam);
y = HIWORD(lParam);
InvalidateRect(hwnd, NULL, TRUE);
}
break;

case WM_LBUTTONUP:
isDown = false;
InvalidateRect(hwnd, NULL, TRUE);
break;

/* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
case WM_ERASEBKGND:
{
HDC hdc = (HDC) wParam;
draw a background on the hdc as needed...
return 1;
}
*/

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

if (last_x != x) || (last_y != y)
{
HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
MoveToEx(hdc, last_x, last_y, NULL);
LineTo(hdc, x, y);
SelectObject(hdc, OldPen);
}

EndPaint(hwnd, &ps);
break;
}

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}


That will draw a single line that starts at the point where the mouse was first held down, and then follow the mouse as it moves around.



Or, if you want to draw multiple lines end-to-end that follow the mouse while it is held down, try this:



std::vector<POINT> points;

LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
points.clear();
break;

case WM_DESTROY:
DeleteObject(Pen);
PostQuitMessage(0);
break;

case WM_LBUTTONDOWN:
{
points.clear();
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
points.push_back(pt);
isDown = true;
InvalidateRect(hwnd, NULL, TRUE);
break;
}

case WM_MOUSEMOVE:
if (isDown)
{
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
points.push_back(pt);
InvalidateRect(hwnd, NULL, TRUE);
}
break;

case WM_LBUTTONUP:
isDown = false;
InvalidateRect(hwnd, NULL, TRUE);
break;

/* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
case WM_ERASEBKGND:
{
HDC hdc = (HDC) wParam;
draw a background on the hdc as needed...
return 1;
}
*/

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

if (points.size() > 1)
{
HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
MoveToEx(hdc, points[0].x, points[0].y, NULL);
for (size_t i = 1; i < points.size(); ++i) {
LineTo(hdc, points[i].x, points[i].y);
}
SelectObject(hdc, OldPen);
}

EndPaint(hwnd, &ps);
break;
}

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270959%2fcwinapi-simple-program-drawing-lines%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    You are getting residual traces because you are not erasing your old drawings before drawing a new line, or at least updating last_x and last_y on each move so that a new line connects to the end of the previous line, like in Microsoft's example.



    But, you really should not draw on the window directly in the mouse message handlers at all. As soon as the window needs a repaint for any reason, all of your drawing will be lost. The correct way to handle this is to perform all of your drawing in a WM_PAINT message handler instead. Use the mouse messages to keep track of line information as needed, and then do all of the actual drawing in WM_PAINT only.



    For example:



    LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    switch (uMsg)
    {
    case WM_CREATE:
    Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
    break;

    case WM_DESTROY:
    DeleteObject(Pen);
    PostQuitMessage(0);
    break;

    case WM_LBUTTONDOWN:
    x = last_x = LOWORD(lParam);
    y = last_y = HIWORD(lParam);
    isDown = true;
    InvalidateRect(hwnd, NULL, TRUE);
    break;

    case WM_MOUSEMOVE:
    if (isDown)
    {
    x = LOWORD(lParam);
    y = HIWORD(lParam);
    InvalidateRect(hwnd, NULL, TRUE);
    }
    break;

    case WM_LBUTTONUP:
    isDown = false;
    InvalidateRect(hwnd, NULL, TRUE);
    break;

    /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
    case WM_ERASEBKGND:
    {
    HDC hdc = (HDC) wParam;
    draw a background on the hdc as needed...
    return 1;
    }
    */

    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    if (last_x != x) || (last_y != y)
    {
    HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
    MoveToEx(hdc, last_x, last_y, NULL);
    LineTo(hdc, x, y);
    SelectObject(hdc, OldPen);
    }

    EndPaint(hwnd, &ps);
    break;
    }

    default:
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
    }


    That will draw a single line that starts at the point where the mouse was first held down, and then follow the mouse as it moves around.



    Or, if you want to draw multiple lines end-to-end that follow the mouse while it is held down, try this:



    std::vector<POINT> points;

    LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    switch (uMsg)
    {
    case WM_CREATE:
    Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
    points.clear();
    break;

    case WM_DESTROY:
    DeleteObject(Pen);
    PostQuitMessage(0);
    break;

    case WM_LBUTTONDOWN:
    {
    points.clear();
    POINT pt;
    pt.x = LOWORD(lParam);
    pt.y = HIWORD(lParam);
    points.push_back(pt);
    isDown = true;
    InvalidateRect(hwnd, NULL, TRUE);
    break;
    }

    case WM_MOUSEMOVE:
    if (isDown)
    {
    POINT pt;
    pt.x = LOWORD(lParam);
    pt.y = HIWORD(lParam);
    points.push_back(pt);
    InvalidateRect(hwnd, NULL, TRUE);
    }
    break;

    case WM_LBUTTONUP:
    isDown = false;
    InvalidateRect(hwnd, NULL, TRUE);
    break;

    /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
    case WM_ERASEBKGND:
    {
    HDC hdc = (HDC) wParam;
    draw a background on the hdc as needed...
    return 1;
    }
    */

    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    if (points.size() > 1)
    {
    HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
    MoveToEx(hdc, points[0].x, points[0].y, NULL);
    for (size_t i = 1; i < points.size(); ++i) {
    LineTo(hdc, points[i].x, points[i].y);
    }
    SelectObject(hdc, OldPen);
    }

    EndPaint(hwnd, &ps);
    break;
    }

    default:
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
    }





    share|improve this answer




























      1














      You are getting residual traces because you are not erasing your old drawings before drawing a new line, or at least updating last_x and last_y on each move so that a new line connects to the end of the previous line, like in Microsoft's example.



      But, you really should not draw on the window directly in the mouse message handlers at all. As soon as the window needs a repaint for any reason, all of your drawing will be lost. The correct way to handle this is to perform all of your drawing in a WM_PAINT message handler instead. Use the mouse messages to keep track of line information as needed, and then do all of the actual drawing in WM_PAINT only.



      For example:



      LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
      {
      switch (uMsg)
      {
      case WM_CREATE:
      Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
      break;

      case WM_DESTROY:
      DeleteObject(Pen);
      PostQuitMessage(0);
      break;

      case WM_LBUTTONDOWN:
      x = last_x = LOWORD(lParam);
      y = last_y = HIWORD(lParam);
      isDown = true;
      InvalidateRect(hwnd, NULL, TRUE);
      break;

      case WM_MOUSEMOVE:
      if (isDown)
      {
      x = LOWORD(lParam);
      y = HIWORD(lParam);
      InvalidateRect(hwnd, NULL, TRUE);
      }
      break;

      case WM_LBUTTONUP:
      isDown = false;
      InvalidateRect(hwnd, NULL, TRUE);
      break;

      /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
      case WM_ERASEBKGND:
      {
      HDC hdc = (HDC) wParam;
      draw a background on the hdc as needed...
      return 1;
      }
      */

      case WM_PAINT:
      {
      PAINTSTRUCT ps;
      HDC hdc = BeginPaint(hwnd, &ps);

      if (last_x != x) || (last_y != y)
      {
      HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
      MoveToEx(hdc, last_x, last_y, NULL);
      LineTo(hdc, x, y);
      SelectObject(hdc, OldPen);
      }

      EndPaint(hwnd, &ps);
      break;
      }

      default:
      return DefWindowProc(hwnd, uMsg, wParam, lParam);
      }
      return 0;
      }


      That will draw a single line that starts at the point where the mouse was first held down, and then follow the mouse as it moves around.



      Or, if you want to draw multiple lines end-to-end that follow the mouse while it is held down, try this:



      std::vector<POINT> points;

      LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
      {
      switch (uMsg)
      {
      case WM_CREATE:
      Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
      points.clear();
      break;

      case WM_DESTROY:
      DeleteObject(Pen);
      PostQuitMessage(0);
      break;

      case WM_LBUTTONDOWN:
      {
      points.clear();
      POINT pt;
      pt.x = LOWORD(lParam);
      pt.y = HIWORD(lParam);
      points.push_back(pt);
      isDown = true;
      InvalidateRect(hwnd, NULL, TRUE);
      break;
      }

      case WM_MOUSEMOVE:
      if (isDown)
      {
      POINT pt;
      pt.x = LOWORD(lParam);
      pt.y = HIWORD(lParam);
      points.push_back(pt);
      InvalidateRect(hwnd, NULL, TRUE);
      }
      break;

      case WM_LBUTTONUP:
      isDown = false;
      InvalidateRect(hwnd, NULL, TRUE);
      break;

      /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
      case WM_ERASEBKGND:
      {
      HDC hdc = (HDC) wParam;
      draw a background on the hdc as needed...
      return 1;
      }
      */

      case WM_PAINT:
      {
      PAINTSTRUCT ps;
      HDC hdc = BeginPaint(hwnd, &ps);

      if (points.size() > 1)
      {
      HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
      MoveToEx(hdc, points[0].x, points[0].y, NULL);
      for (size_t i = 1; i < points.size(); ++i) {
      LineTo(hdc, points[i].x, points[i].y);
      }
      SelectObject(hdc, OldPen);
      }

      EndPaint(hwnd, &ps);
      break;
      }

      default:
      return DefWindowProc(hwnd, uMsg, wParam, lParam);
      }
      return 0;
      }





      share|improve this answer


























        1












        1








        1






        You are getting residual traces because you are not erasing your old drawings before drawing a new line, or at least updating last_x and last_y on each move so that a new line connects to the end of the previous line, like in Microsoft's example.



        But, you really should not draw on the window directly in the mouse message handlers at all. As soon as the window needs a repaint for any reason, all of your drawing will be lost. The correct way to handle this is to perform all of your drawing in a WM_PAINT message handler instead. Use the mouse messages to keep track of line information as needed, and then do all of the actual drawing in WM_PAINT only.



        For example:



        LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
        switch (uMsg)
        {
        case WM_CREATE:
        Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
        break;

        case WM_DESTROY:
        DeleteObject(Pen);
        PostQuitMessage(0);
        break;

        case WM_LBUTTONDOWN:
        x = last_x = LOWORD(lParam);
        y = last_y = HIWORD(lParam);
        isDown = true;
        InvalidateRect(hwnd, NULL, TRUE);
        break;

        case WM_MOUSEMOVE:
        if (isDown)
        {
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        InvalidateRect(hwnd, NULL, TRUE);
        }
        break;

        case WM_LBUTTONUP:
        isDown = false;
        InvalidateRect(hwnd, NULL, TRUE);
        break;

        /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
        case WM_ERASEBKGND:
        {
        HDC hdc = (HDC) wParam;
        draw a background on the hdc as needed...
        return 1;
        }
        */

        case WM_PAINT:
        {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        if (last_x != x) || (last_y != y)
        {
        HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
        MoveToEx(hdc, last_x, last_y, NULL);
        LineTo(hdc, x, y);
        SelectObject(hdc, OldPen);
        }

        EndPaint(hwnd, &ps);
        break;
        }

        default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
        return 0;
        }


        That will draw a single line that starts at the point where the mouse was first held down, and then follow the mouse as it moves around.



        Or, if you want to draw multiple lines end-to-end that follow the mouse while it is held down, try this:



        std::vector<POINT> points;

        LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
        switch (uMsg)
        {
        case WM_CREATE:
        Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
        points.clear();
        break;

        case WM_DESTROY:
        DeleteObject(Pen);
        PostQuitMessage(0);
        break;

        case WM_LBUTTONDOWN:
        {
        points.clear();
        POINT pt;
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        points.push_back(pt);
        isDown = true;
        InvalidateRect(hwnd, NULL, TRUE);
        break;
        }

        case WM_MOUSEMOVE:
        if (isDown)
        {
        POINT pt;
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        points.push_back(pt);
        InvalidateRect(hwnd, NULL, TRUE);
        }
        break;

        case WM_LBUTTONUP:
        isDown = false;
        InvalidateRect(hwnd, NULL, TRUE);
        break;

        /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
        case WM_ERASEBKGND:
        {
        HDC hdc = (HDC) wParam;
        draw a background on the hdc as needed...
        return 1;
        }
        */

        case WM_PAINT:
        {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        if (points.size() > 1)
        {
        HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
        MoveToEx(hdc, points[0].x, points[0].y, NULL);
        for (size_t i = 1; i < points.size(); ++i) {
        LineTo(hdc, points[i].x, points[i].y);
        }
        SelectObject(hdc, OldPen);
        }

        EndPaint(hwnd, &ps);
        break;
        }

        default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
        return 0;
        }





        share|improve this answer














        You are getting residual traces because you are not erasing your old drawings before drawing a new line, or at least updating last_x and last_y on each move so that a new line connects to the end of the previous line, like in Microsoft's example.



        But, you really should not draw on the window directly in the mouse message handlers at all. As soon as the window needs a repaint for any reason, all of your drawing will be lost. The correct way to handle this is to perform all of your drawing in a WM_PAINT message handler instead. Use the mouse messages to keep track of line information as needed, and then do all of the actual drawing in WM_PAINT only.



        For example:



        LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
        switch (uMsg)
        {
        case WM_CREATE:
        Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
        break;

        case WM_DESTROY:
        DeleteObject(Pen);
        PostQuitMessage(0);
        break;

        case WM_LBUTTONDOWN:
        x = last_x = LOWORD(lParam);
        y = last_y = HIWORD(lParam);
        isDown = true;
        InvalidateRect(hwnd, NULL, TRUE);
        break;

        case WM_MOUSEMOVE:
        if (isDown)
        {
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        InvalidateRect(hwnd, NULL, TRUE);
        }
        break;

        case WM_LBUTTONUP:
        isDown = false;
        InvalidateRect(hwnd, NULL, TRUE);
        break;

        /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
        case WM_ERASEBKGND:
        {
        HDC hdc = (HDC) wParam;
        draw a background on the hdc as needed...
        return 1;
        }
        */

        case WM_PAINT:
        {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        if (last_x != x) || (last_y != y)
        {
        HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
        MoveToEx(hdc, last_x, last_y, NULL);
        LineTo(hdc, x, y);
        SelectObject(hdc, OldPen);
        }

        EndPaint(hwnd, &ps);
        break;
        }

        default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
        return 0;
        }


        That will draw a single line that starts at the point where the mouse was first held down, and then follow the mouse as it moves around.



        Or, if you want to draw multiple lines end-to-end that follow the mouse while it is held down, try this:



        std::vector<POINT> points;

        LRESULT APIENTRY WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
        switch (uMsg)
        {
        case WM_CREATE:
        Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
        points.clear();
        break;

        case WM_DESTROY:
        DeleteObject(Pen);
        PostQuitMessage(0);
        break;

        case WM_LBUTTONDOWN:
        {
        points.clear();
        POINT pt;
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        points.push_back(pt);
        isDown = true;
        InvalidateRect(hwnd, NULL, TRUE);
        break;
        }

        case WM_MOUSEMOVE:
        if (isDown)
        {
        POINT pt;
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        points.push_back(pt);
        InvalidateRect(hwnd, NULL, TRUE);
        }
        break;

        case WM_LBUTTONUP:
        isDown = false;
        InvalidateRect(hwnd, NULL, TRUE);
        break;

        /* if your WNDCLASS sets hbrBackground=NULL, uncomment this handler...
        case WM_ERASEBKGND:
        {
        HDC hdc = (HDC) wParam;
        draw a background on the hdc as needed...
        return 1;
        }
        */

        case WM_PAINT:
        {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        if (points.size() > 1)
        {
        HPEN OldPen = (HPEN) SelectObject(hdc, Pen);
        MoveToEx(hdc, points[0].x, points[0].y, NULL);
        for (size_t i = 1; i < points.size(); ++i) {
        LineTo(hdc, points[i].x, points[i].y);
        }
        SelectObject(hdc, OldPen);
        }

        EndPaint(hwnd, &ps);
        break;
        }

        default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
        return 0;
        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 13 '18 at 0:56

























        answered Nov 13 '18 at 0:40









        Remy LebeauRemy Lebeau

        332k18251443




        332k18251443






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270959%2fcwinapi-simple-program-drawing-lines%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Florida Star v. B. J. F.

            Danny Elfman

            Lugert, Oklahoma