Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Get DC from QPaintEngine
Forum Updated to NodeBB v4.3 + New Features

Get DC from QPaintEngine

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 3 Posters 1.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    lucbaz
    wrote on last edited by
    #1

    Hi,

    I am working on a code that was written in Qt4. I am working in Qt5. The program needs to display a chart, and it uses a QPainter object to do so.

    This is the problematic line of the original code:

    HDC PaintDC = p.paintEngine()->getDC();
    

    The getDC() has changed in Qt5 and now needs a HWND object.
    So I tried this:

    HWND hwnd = (HWND)p.paintEngine();
    HDC PaintDC = GetDC(hwnd);
    

    But the chart doesn't display. What can I do to fix that?

    Thanks in advance.

    1 Reply Last reply
    0
    • hskoglundH Online
      hskoglundH Online
      hskoglund
      wrote on last edited by
      #8

      Hi, the capability that came with Qt4's getDC(), i.e. to be able to draw using vintage Win32 ::MoveTo(). ::LineTo() etc. in Qt's paintEvent() seems to be gone in Qt5. If you browse Qt5's source you'll still see mention of a getDC(), but it's only present in the private headers :-(

      Your code will run fine, but not in the context of a paintEvent(), i.e. inside it you will be fighting with Qt and flicker will occur for sure.

      But I got an idea that might help, you can use a QTimer to reschedule your drawing to immediately after the paintEvent, that way paintEvent() will be done and you're free to draw, say like this:

      #include "qtimer.h"
      void CalcWnd::paintEvent(QPaintEvent *e)
      {
          QRect r = e->rect();
          QTimer::singleShot(0,[this,r] { DoRedrawPixmap(r); });
      }
      
      1 Reply Last reply
      0
      • hskoglundH Online
        hskoglundH Online
        hskoglund
        wrote on last edited by hskoglund
        #2

        Hi, try:

        auto w = (QWidget*) p.device();
        if (!w)
            return;  // skip this if there was no QWidget
        
        HWND hWnd = reinterpret_cast<HWND>(w->winId());
        HDC paintDC = GetDC(hWnd);
        
        B 1 Reply Last reply
        2
        • hskoglundH hskoglund

          Hi, try:

          auto w = (QWidget*) p.device();
          if (!w)
              return;  // skip this if there was no QWidget
          
          HWND hWnd = reinterpret_cast<HWND>(w->winId());
          HDC paintDC = GetDC(hWnd);
          
          B Offline
          B Offline
          Bonnie
          wrote on last edited by Bonnie
          #3

          @lucbaz Hi, HWND is the Windows platform handle type of a window / widget, so you cannot cast the result of paintEngine() to HWND, because it is not.

          1 Reply Last reply
          0
          • L Offline
            L Offline
            lucbaz
            wrote on last edited by
            #4

            I replaced the code with this:

            HWND hwnd = reinterpret_cast<HWND>(this->winId());
            HDC PaintDC = GetDC(hwnd);
            

            And I can only see the chart for a fraction of a second when I resize or move the window. So this part of the code is probably not causing the error.
            What could be the cause for the disappearance of the chart?

            If it helps, the code mentioned above is part of a private function that is called by paintEvent of the window in question.

            1 Reply Last reply
            0
            • hskoglundH Online
              hskoglundH Online
              hskoglund
              wrote on last edited by
              #5

              Hmm sounds like different DC's fighting for the same hWnd, are you using Qt's paintEvent or?

              1 Reply Last reply
              0
              • L Offline
                L Offline
                lucbaz
                wrote on last edited by
                #6

                Yes, I am using

                void Window::paintEvent(QPaintEvent *e){...}
                

                Actually, there is 4 windows that uses QPainter to display their interfaces. Each of them uses their own paintEvent. Is it possible that they interfere with each other?

                1 Reply Last reply
                0
                • L Offline
                  L Offline
                  lucbaz
                  wrote on last edited by
                  #7

                  This is the code of the paintEvent for one of the 4 windows:

                  void CalcWnd::paintEvent(QPaintEvent *e)
                  {
                     DoRedrawPixmap(e->rect());
                  }
                  
                  void CalcWnd::DoRedrawPixmap(const QRect &rect)
                  {
                     int i;
                     LOGFONT LogFont;
                     HFONT Font, OldFont;
                     HPEN Pen, OldPen;
                     char buf[100];
                     int XI = 50, YI = 50;
                     Calc *C;
                  
                     // Calculate the size of the widget for holding all items
                     // Each item is 17 pixel long
                     int ContentY = 51+CalcData.size()*17;
                     int WndY = Wnd->calcWnd->size().height()-48;
                  
                     this->resize(800, max(ContentY, WndY));
                  
                     HWND hwnd = reinterpret_cast<HWND>(this->effectiveWinId());
                     HDC PaintDC = GetDC(hwnd);
                  
                     QPoint wnd = mapTo(window(), QPoint(0,0));
                     POINT org;
                     GetDCOrgEx(PaintDC, &org);
                     SetViewportOrgEx(PaintDC, wnd.x(), wnd.y(), &org);
                  
                     qDebug() << "Time: " << QTime::currentTime();
                     qDebug() << "wnd: " << wnd;
                     qDebug() << "size(): " << size();
                  
                     // Set the clipping region
                     HRGN hrgn = CreateRectRgn(rect.left()+wnd.x(), rect.top()+wnd.y(),
                     	rect.right()+wnd.x()+1, rect.bottom()+wnd.y()+1);
                     SelectClipRgn(PaintDC, hrgn);
                  
                     LogFont.lfHeight = 15;
                     LogFont.lfWidth = 0;
                     LogFont.lfEscapement = 0;
                     LogFont.lfOrientation = 0;
                     LogFont.lfWeight = FW_NORMAL;
                     LogFont.lfItalic = 0;
                     LogFont.lfUnderline = 0;
                     LogFont.lfStrikeOut = 0;
                     LogFont.lfCharSet = ANSI_CHARSET;
                     LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
                     LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
                     LogFont.lfQuality = DEFAULT_QUALITY;
                     LogFont.lfPitchAndFamily = VARIABLE_PITCH | FF_DONTCARE;
                     strcpy(LogFont.lfFaceName, "TIMES");
                     Font = CreateFontIndirect(&LogFont);        // create font
                     Pen = CreatePen(PS_SOLID, 3, 0x00000000);	// create pen
                     OldPen = (HPEN) SelectObject(PaintDC, Pen);
                     MoveToEx(PaintDC, 2, 35, 0);
                     LineTo(PaintDC, 1000, 35);
                     MoveToEx(PaintDC, 325, 25, 0);
                     LineTo(PaintDC, 325, max(ContentY, WndY));
                     SelectObject(PaintDC, OldPen);
                     DeleteObject(Pen);                          // delete pen
                     OldFont = (HFONT) SelectObject(PaintDC, Font);
                     strcpy(buf, "hkl");
                     TextOut(PaintDC, 50, 15, buf, strlen(buf));
                     strcpy(buf, "E calc");
                     TextOut(PaintDC, 100, 15, buf, strlen(buf));
                     strcpy(buf, "E obs");
                     TextOut(PaintDC, 150, 15, buf, strlen(buf));
                     strcpy(buf, "I calc");
                     TextOut(PaintDC, 200, 15, buf, strlen(buf));
                     strcpy(buf, "I obs");
                     TextOut(PaintDC, 250, 15, buf, strlen(buf));
                     strcpy(buf, "hkl");
                     TextOut(PaintDC, 350, 15, buf, strlen(buf));
                     strcpy(buf, "E calc");
                     TextOut(PaintDC, 400, 15, buf, strlen(buf));
                     strcpy(buf, "E obs");
                     TextOut(PaintDC, 450, 15, buf, strlen(buf));
                     strcpy(buf, "I calc");
                     TextOut(PaintDC, 500, 15, buf, strlen(buf));
                     strcpy(buf, "I obs");
                     TextOut(PaintDC, 550, 15, buf, strlen(buf));
                  
                     int calcSize;
                     CALC::const_iterator iter;
                     for (i = 0, iter = CalcData.begin(), calcSize = CalcData.size();
                     	iter != CalcData.end() && i < 0.5*calcSize;
                     	iter++, calcSize++)
                     {
                     	C = (*iter).get();
                     	sprintf(buf, "%d%d%d", C->h, C->k, C->l);
                     	TextOut(PaintDC, XI, YI, buf, strlen(buf));
                     	sprintf(buf, "%6.3f", C->Ecalc);
                     	TextOut(PaintDC, XI+50, YI, buf, strlen(buf));
                     	if (C->Eobs != 0)
                     		sprintf(buf, "%6.3f", C->Eobs);
                     	else strcpy(buf, "  -");
                     	TextOut(PaintDC, XI+100, YI, buf, strlen(buf));
                     	sprintf(buf, "%6.3f", C->Icalc);
                     	TextOut(PaintDC, XI+150, YI, buf, strlen(buf));
                     	if (C->Iobs != 0)
                     		sprintf(buf, "%6.3f", C->Iobs);
                     	else strcpy(buf, "  -");
                     	TextOut(PaintDC, XI+200, YI, buf, strlen(buf));
                     	YI += 17;
                     }
                     XI = 350;
                     YI = 50;
                     for (; iter != CalcData.end(); iter++)
                     {
                     	C = (*iter).get();
                     	sprintf(buf, "%d%d%d", C->h, C->k, C->l);
                     	TextOut(PaintDC, XI, YI, buf, strlen(buf));
                     	sprintf(buf, "%6.3f", C->Ecalc);
                     	TextOut(PaintDC, XI+50, YI, buf, strlen(buf));
                     	if (C->Eobs != 0)
                     		sprintf(buf, "%6.3f", C->Eobs);
                     	else strcpy(buf, "  -");
                     	TextOut(PaintDC, XI+100, YI, buf, strlen(buf));
                     	sprintf(buf, "%6.3f", C->Icalc);
                     	TextOut(PaintDC, XI+150, YI, buf, strlen(buf));
                     	if (C->Iobs != 0)
                     		sprintf(buf, "%6.3f", C->Iobs);
                     	else strcpy(buf, "  -");
                     	TextOut(PaintDC, XI+200, YI, buf, strlen(buf));
                     	YI += 17;
                     }
                     SelectObject(PaintDC, OldFont);
                     DeleteObject(Font);									// delete font
                     
                     // Restore viewport state
                     SetViewportOrgEx(PaintDC, org.x, org.y, 0);
                  
                     // Release backbuffer handle
                     ReleaseDC(hwnd, PaintDC);
                  
                  }
                  
                  1 Reply Last reply
                  0
                  • hskoglundH Online
                    hskoglundH Online
                    hskoglund
                    wrote on last edited by
                    #8

                    Hi, the capability that came with Qt4's getDC(), i.e. to be able to draw using vintage Win32 ::MoveTo(). ::LineTo() etc. in Qt's paintEvent() seems to be gone in Qt5. If you browse Qt5's source you'll still see mention of a getDC(), but it's only present in the private headers :-(

                    Your code will run fine, but not in the context of a paintEvent(), i.e. inside it you will be fighting with Qt and flicker will occur for sure.

                    But I got an idea that might help, you can use a QTimer to reschedule your drawing to immediately after the paintEvent, that way paintEvent() will be done and you're free to draw, say like this:

                    #include "qtimer.h"
                    void CalcWnd::paintEvent(QPaintEvent *e)
                    {
                        QRect r = e->rect();
                        QTimer::singleShot(0,[this,r] { DoRedrawPixmap(r); });
                    }
                    
                    1 Reply Last reply
                    0
                    • L Offline
                      L Offline
                      lucbaz
                      wrote on last edited by
                      #9

                      Thank you so much for your help.

                      1 Reply Last reply
                      0
                      • Pl45m4P Pl45m4 referenced this topic on

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved