Get DC from QPaintEngine
-
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.
-
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); }); }
-
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);
-
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.
-
Hmm sounds like different DC's fighting for the same hWnd, are you using Qt's paintEvent or?
-
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); }
-
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); }); }
-
P Pl45m4 referenced this topic on