From f8c345ca953e6ca3927f50f7c8b771cff806d281 Mon Sep 17 00:00:00 2001 From: chris2oph Date: Thu, 31 Jan 2019 09:49:11 +0000 Subject: [PATCH] Fix painting logic in wxQt wxClientDC implementation The original drawing mechanism was generating lots of QWarning messages when running samples (e.g. htlbox, caret, etc.) and in some cases was not actually completely drawing every element of the sample. The issue was that the QPicture was being shared incorrectly between wxWindow and wxClientDC and attempts to start painting, update, etc. were generating console warnings. Closes https://github.com/wxWidgets/wxWidgets/pull/1152 --- include/wx/qt/dcclient.h | 6 ++++++ include/wx/qt/window.h | 3 ++- src/qt/dcclient.cpp | 46 ++++++++++++++++++++++++++++++++++------ src/qt/window.cpp | 9 ++++---- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/include/wx/qt/dcclient.h b/include/wx/qt/dcclient.h index fdec1abbed..c9a5986838 100644 --- a/include/wx/qt/dcclient.h +++ b/include/wx/qt/dcclient.h @@ -10,6 +10,10 @@ #include "wx/qt/dc.h" +#include "wx/scopedptr.h" + +class QPicture; + class WXDLLIMPEXP_CORE wxWindowDCImpl : public wxQtDCImpl { public: @@ -35,6 +39,8 @@ public: ~wxClientDCImpl(); private: + wxScopedPtr m_pict; + wxDECLARE_CLASS(wxClientDCImpl); wxDECLARE_NO_COPY_CLASS(wxClientDCImpl); }; diff --git a/include/wx/qt/window.h b/include/wx/qt/window.h index 6f5a2a87e1..e9d14424bf 100644 --- a/include/wx/qt/window.h +++ b/include/wx/qt/window.h @@ -145,7 +145,8 @@ public: // wxQt implementation internals: - virtual QPicture *QtGetPicture() const; + // Caller maintains ownership of pict - window will NOT delete it + void QtSetPicture( QPicture* pict ); QPainter *QtGetPainter(); diff --git a/src/qt/dcclient.cpp b/src/qt/dcclient.cpp index 0137f4d6e1..1a8efb2ab2 100644 --- a/src/qt/dcclient.cpp +++ b/src/qt/dcclient.cpp @@ -27,6 +27,30 @@ //############################################################################## +namespace +{ +class QtPictureSetter +{ +public: + QtPictureSetter(wxWindow *window, QPicture *pict) + : m_window( window ) + { + m_window->QtSetPicture( pict ); + } + + ~QtPictureSetter() + { + m_window->QtSetPicture( NULL ); + } + +private: + wxWindow* const m_window; + + wxDECLARE_NO_COPY_CLASS(QtPictureSetter); +}; +} + + wxIMPLEMENT_CLASS(wxWindowDCImpl,wxQtDCImpl); wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) @@ -54,7 +78,7 @@ wxWindowDCImpl::~wxWindowDCImpl() } if ( m_window ) { - // do not destroy as it is owned by the window + // do not destroy in base class as it is owned by the window m_qtPainter = NULL; } } @@ -67,6 +91,7 @@ wxClientDCImpl::wxClientDCImpl( wxDC *owner ) : wxWindowDCImpl( owner ) { m_window = NULL; + m_qtPainter = NULL; } wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *win ) @@ -74,8 +99,11 @@ wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *win ) { m_window = win; - QPicture *pic = win->QtGetPicture(); - m_ok = m_qtPainter->begin( pic ); + m_qtPainter = new QPainter(); + + m_pict.reset(new QPicture()); + m_ok = m_qtPainter->begin( m_pict.get() ); + QtPreparePainter(); } @@ -88,10 +116,11 @@ wxClientDCImpl::~wxClientDCImpl() { m_qtPainter->end(); m_ok = false; - QPicture *pict = m_window->QtGetPicture(); if ( m_window != NULL ) { + QtPictureSetter pictureSetter(m_window, m_pict.get()); + // get the inner widget in scroll areas: QWidget *widget; if ( m_window->QtGetScrollBarsContainer() ) @@ -102,8 +131,8 @@ wxClientDCImpl::~wxClientDCImpl() } // force paint event if there is something to replay and // if not currently inside a paint event (to avoid recursion) - QRect rect = pict->boundingRect(); - if ( !pict->isNull() && !widget->paintingActive() && !rect.isEmpty() ) + QRect rect = m_pict->boundingRect(); + if ( !m_pict->isNull() && !widget->paintingActive() && !rect.isEmpty() ) { // only force the update of the rect affected by the DC widget->update( rect ); @@ -111,12 +140,15 @@ wxClientDCImpl::~wxClientDCImpl() else { // Not drawing anything, reset picture to avoid issues in handler - pict->setData( NULL, 0 ); + m_pict->setData( NULL, 0 ); } + // let destroy the m_qtPainter (see inherited classes destructors) m_window = NULL; } } + + // Painter will be deleted by base class } //############################################################################## diff --git a/src/qt/window.cpp b/src/qt/window.cpp index 21dea1b8f3..4f88730f47 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -210,7 +210,7 @@ void wxWindowQt::Init() m_horzScrollBar = NULL; m_vertScrollBar = NULL; - m_qtPicture = new QPicture(); + m_qtPicture = NULL; m_qtPainter = new QPainter(); m_mouseInside = false; @@ -251,7 +251,6 @@ wxWindowQt::~wxWindowQt() DestroyChildren(); // This also destroys scrollbars - delete m_qtPicture; delete m_qtPainter; #if wxUSE_ACCEL @@ -1126,7 +1125,7 @@ bool wxWindowQt::QtHandlePaintEvent ( QWidget *handler, QPaintEvent *event ) { bool handled; - if ( m_qtPicture->isNull() ) + if ( m_qtPicture == NULL ) { // Real paint event (not for wxClientDC), prepare the background switch ( GetBackgroundStyle() ) @@ -1558,9 +1557,9 @@ QScrollArea *wxWindowQt::QtGetScrollBarsContainer() const return m_qtContainer; } -QPicture *wxWindowQt::QtGetPicture() const +void wxWindowQt::QtSetPicture( QPicture* pict ) { - return m_qtPicture; + m_qtPicture = pict; } QPainter *wxWindowQt::QtGetPainter()