title: How to avoid excessive screen flickering with GDI
body: <p>I'm sort of new to rendering graphics with GDI...</p>
  
  <p>I made a paint program, and it works fine, it's just that it causes a lot of annoying screen flickering. I will admit my paint code is not really optimized (lack of time), but it shouldn't be super inefficient either, so I'm puzzled.</p>
  
  <p>What I'm basically doing is creating a compatible DC on init, then create a compatible bitmap. Then I select it into the compatible DC, and paint to the compatible DC. Then I use BitBlit() to copy it to the window hDC...</p>
  
  <p>Could anyone tell me the possible causes for this screen tearing?
  EDIT: btw, screen flickering only occurs during the drawing of a path (before the path gets drawn to the hMemDC, it gets drawn to the hDC of the window)</p>
  
  <p>Code samples:
  (EDIT: If you need to see any more code that you think is relevant, comment and I'll edit)</p>
  
  <hr>
  
  <h2>Path::DrawTo(HDC)</h2>
  
  <pre><code>bool Path::DrawTo(HDC hDC)
  {
      if(hDC == NULL || m_PointVector.size() &lt;= 0) {
          return false;
      }
  
      switch (m_Tool) {
      case Tool_Pen:
          {
              Point2D p = m_PointVector.at(0);
  
              if(m_PointVector.size() &gt; 1) {
                  HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
  
                  MoveToEx(hDC, p.x, p.y, nullptr);
  
                  for(UINT i = 1; i &lt; m_PointVector.size(); ++i) {
                      p = m_PointVector.at(i);
                      LineTo(hDC,p.x,p.y);
                  }
  
                  SelectObject(hDC,oldPen);
                  break;
              } //else
  
              SetPixel(hDC,p.x-1,p.y,m_Col);
              SetPixel(hDC,p.x,p.y,m_Col);
              SetPixel(hDC,p.x+1,p.y,m_Col);
              SetPixel(hDC,p.x,p.y-1,m_Col);
              SetPixel(hDC,p.x,p.y+1,m_Col);
              break;
          }
      case Tool_Line:
          {
              if(m_PointVector.size() &gt; 1) {
                  Point2D p = m_PointVector.at(0);
                  HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
  
                  MoveToEx(hDC, p.x, p.y, nullptr);
  
                  for(UINT i = 1; i &lt; m_PointVector.size(); ++i) {
                      p = m_PointVector.at(i);
                      LineTo(hDC,p.x,p.y);
                  }
  
                  SelectObject(hDC,oldPen);
              }
              break;
          }
      case Tool_Ellipse:
          {
              if(m_PointVector.size() &gt; 1) {
                  HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
                  SelectObject(hDC,m_hBrush);
  
                  Point2D p1 = m_PointVector.at(0);
                  Point2D p2 = m_PointVector.at(1);
  
                  if(p1.x &gt; p2.x) {
                      int iTemp = p1.x;
                      p1.x = p2.x;
                      p2.x = iTemp;
                  }
                  if(p1.y &gt; p2.y) {
                      int iTemp = p1.y;
                      p1.y = p2.y;
                      p2.y = iTemp;
                  }
  
                  Ellipse(hDC,p1.x,p1.y,p2.x,p2.y);
  
                  SelectObject(hDC,oldPen);
              }
              break;
          }
      case Tool_Rectangle:
          {
              if(m_PointVector.size() &gt; 1) {
                  HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
                  SelectObject(hDC,m_hBrush);
  
                  Point2D p1 = m_PointVector.at(0);
                  Point2D p2 = m_PointVector.at(1);
  
                  if(p1.x &gt; p2.x) {
                      int iTemp = p1.x;
                      p1.x = p2.x;
                      p2.x = iTemp;
                  }
                  if(p1.y &gt; p2.y) {
                      int iTemp = p1.y;
                      p1.y = p2.y;
                      p2.y = iTemp;
                  }
  
                  Rectangle(hDC,p1.x,p1.y,p2.x,p2.y);
  
                  SelectObject(hDC,oldPen);
              }
              break;
          }
      case Tool_LineTrack:
          {
              HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
              SelectObject(hDC,m_hBrush);
  
              int vSize = (int)m_PointVector.size();
              Point2D p = m_PointVector.at(0);
  
              if (vSize &lt;= 1) {
                  Ellipse(hDC,p.x-10,p.y-10,p.x+10,p.y+10);
              }
              else {
                  //draw LineTrack
                  Point2D pTemp = m_PointVector.at(1);
                  MoveToEx(hDC,p.x,p.y,nullptr);
  
                  for (int i = 1; i &lt; vSize; ++i) {
                      p = m_PointVector.at(i);
                      pTemp = m_PointVector.at(i-1);
                      LineTo(hDC,p.x,p.y);
                      Ellipse(hDC,pTemp.x-10,pTemp.y-10,pTemp.x+10,pTemp.y+10);
                  }
  
                  Ellipse(hDC,p.x-10,p.y-10,p.x+10,p.y+10);
              }
  
              SelectObject(hDC,oldPen);
              break;
          }
      }
  
      return true;
  }
  </code></pre>
  
  <hr>
  
  <h2>WndProc(HWND, UINT, WPARAM, LPARAM)</h2>
  
  <pre><code>LRESULT MyApp::WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  {
      if(iMsg == WM_CREATE)
      {
          CREATESTRUCT *pCS = (CREATESTRUCT*)lParam;
          SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)pCS-&gt;lpCreateParams);
  
      }
      else
      {
          //retrieve the stored "this" pointer
          MyApp* pApp = (MyApp*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  
          switch (iMsg)
          {
              case WM_PAINT:
                  {
                  pApp-&gt;Paint();
                  return 0;
                  }
  
              case WM_COMMAND:
              {
                  int wmId    = LOWORD(wParam);
                  int wmEvent = HIWORD(wParam);
  
                  // Parse the menu selections:
                  switch (wmId)
                  {
                  case IDM_NEW:
                      {
                          ////
                          return 0;
                      }
                      return 0;
                  case IDM_LOAD:
                      {
                          //////
                          return 0;
                      }
                  case IDM_SAVE:
                      {
                      //////
                      return 0;
                      }
                  case IDM_SAVEAS:
                      {
                          //////
                          return 0;
                      }
                  case IDM_COLOURMAIN:
                      {
                          COLORREF col;
                          if(MyWin32Funcs::OnColorPick(col)) {
                              pApp-&gt;m_pPath-&gt;SetColor1(col);
                          }
                      return 0;
                      }
                  case IDM_COLOURSECONDARY:
                      {
                      COLORREF col;
                          if(MyWin32Funcs::OnColorPick(col)) {
                              pApp-&gt;m_pPath-&gt;SetColor2(col);
                          }
                      return 0;
                      }
                  case IDM_PEN:
                      {
                          pApp-&gt;m_pPath-&gt;SetTool(Tool_Pen);
                          return 0;
                      }
                  case IDM_LINE:
                      {
                          pApp-&gt;m_pPath-&gt;SetTool(Tool_Line);
                          return 0;
                      }
                  case IDM_ELLIPSE:
                      {
                          pApp-&gt;m_pPath-&gt;SetTool(Tool_Ellipse);
                          return 0;
                      }
                  case IDM_RECTANGLE:
                      {
                          pApp-&gt;m_pPath-&gt;SetTool(Tool_Rectangle);
                          return 0;
                      }
                  case IDM_LINETRACK:
                      {
                          pApp-&gt;m_pPath-&gt;SetTool(Tool_LineTrack);
                          return 0;
                      }
                  default:
                      {
                      //////
                      return 0;
                      }
                  }
              }
  
              case WM_LBUTTONUP:
                  {
                      //////
                      Point2D p;
                      p.x = LOWORD(lParam); 
                      p.y = HIWORD(lParam);
  
                      switch(pApp-&gt;m_pPath-&gt;GetTool()) {
                          case Tool_Pen:
                              {
                                  pApp-&gt;m_bPaintToBitmap = true;
                                  InvalidateRect(pApp-&gt;m_hWnd,NULL,true);
                                  break;
                              }
                          case Tool_Ellipse:
                              {
                                  pApp-&gt;m_bPaintToBitmap = true;
                                  InvalidateRect(pApp-&gt;m_hWnd,NULL,true);
                                  break;
                              }
                          case Tool_Rectangle:
                              {
                                  pApp-&gt;m_bPaintToBitmap = true;
                                  InvalidateRect(pApp-&gt;m_hWnd,NULL,true);
                                  break;
                              }
                          case Tool_Line:
                              {
                                  pApp-&gt;m_pPath-&gt;AddPoint(p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                                  InvalidateRect(pApp-&gt;m_hWnd,NULL,false);
                                  break;
                              }
                          case Tool_LineTrack:
                              {
                                  pApp-&gt;m_pPath-&gt;AddPoint(p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                                  InvalidateRect(pApp-&gt;m_hWnd,NULL,false);
                                  break;
                              }
                      }
  
                      return 0;
                  }
  
              case WM_RBUTTONUP:
                  {
                      //////
                      int x = LOWORD(lParam);
                      int y = HIWORD(lParam);
  
                      switch(pApp-&gt;m_pPath-&gt;GetTool()) {
                          case Tool_Line:
                              {
                                  pApp-&gt;m_bPaintToBitmap = true;
                                  InvalidateRect(pApp-&gt;m_hWnd,NULL,true);
                                  break;
                              }
                          case Tool_LineTrack:
                              {
                                  pApp-&gt;m_bPaintToBitmap = true;
                                  InvalidateRect(pApp-&gt;m_hWnd,NULL,true);
                                  break;
                              }
                      }
  
                      return 0;
                  }
              case WM_LBUTTONDOWN:
                  {
                      Point2D p;
                      p.x = LOWORD(lParam);
                      p.y = HIWORD(lParam);
                      switch(pApp-&gt;m_pPath-&gt;GetTool()) {
                      case Tool_Pen:
                          pApp-&gt;m_pPath-&gt;AddPoint(p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                          InvalidateRect(pApp-&gt;m_hWnd,NULL,false);
                          break;
                      }
                  }
              case WM_MOUSEMOVE:
                  {
                      Point2D p;
                      p.x = LOWORD(lParam);
                      p.y = HIWORD(lParam);
                      if (wParam &amp; MK_LBUTTON) {
                          switch(pApp-&gt;m_pPath-&gt;GetTool()) {
                          case Tool_Pen:
                              {
                              pApp-&gt;m_pPath-&gt;AddPoint(p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                              InvalidateRect(pApp-&gt;m_hWnd,NULL,false);
                              break;
                              }
                          case Tool_Ellipse:
                              {
                              if( pApp-&gt;m_pPath-&gt;GetLen() &gt;= 1) {
                                  pApp-&gt;m_pPath-&gt;SetPointAt(1,p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                              }
                              else {
                                  pApp-&gt;m_pPath-&gt;AddPoint(p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                              }
                              InvalidateRect(pApp-&gt;m_hWnd,NULL,false);
                              break;
                              }
                          case Tool_Rectangle:
                              {
                              if( pApp-&gt;m_pPath-&gt;GetLen() &gt;= 1) {
                                  pApp-&gt;m_pPath-&gt;SetPointAt(1,p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                              }
                              else {
                                  pApp-&gt;m_pPath-&gt;AddPoint(p,pApp-&gt;m_pBitmapPainter-&gt;GetBmpSize(),pApp-&gt;m_pBitmapPainter-&gt;GetBmpOffset());
                              }
                              InvalidateRect(pApp-&gt;m_hWnd,NULL,false);
                              break;
                              }
                          }
                      }
  
                      return 0;
                  }
  
              case WM_CLOSE:
                  {
                      //////
                                  return 0;
                              }
                          }
                      PostQuitMessage(0);
                      return 0;
                  }
          }
      }
      return DefWindowProc (hWnd, iMsg, wParam, lParam) ;
  }
  </code></pre>
  
  <hr>
  
  <h2>MyApp::Paint()</h2>
  
  <pre><code>void MyApp::Paint()
  {
      BeginPaint(m_hWnd,&amp;m_PaintStruct);
      if (m_bPaintToBitmap) {
          Point2D p;
          p.x = BMPXOFFSET;
          p.y = BMPYOFFSET;
          m_pPath-&gt;Offset(p);
          m_pPath-&gt;DrawTo(m_pBitmapPainter-&gt;GetMemDC());
          m_pPath-&gt;ClrPath();
          m_pBitmapPainter-&gt;Paint(); //this is where BitBlt() occurs
          m_bPaintToBitmap = false;
          if(m_pBitmapPainter-&gt;IsAdjusted() == false) {
              m_pBitmapPainter-&gt;SetbAdjusted(true);
          }
      }
      else {
          m_pBitmapPainter-&gt;Paint(); //this is where BitBlt() occurs
          m_pPath-&gt;DrawTo(m_hDC);
      }
      EndPaint(m_hWnd,&amp;m_PaintStruct);
  }
  </code></pre>
  
  <p>Any help would much be appreciated.</p>