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
This commit is contained in:
chris2oph
2019-01-31 09:49:11 +00:00
committed by Vadim Zeitlin
parent 7d2e6e805f
commit f8c345ca95
4 changed files with 51 additions and 13 deletions

View File

@@ -10,6 +10,10 @@
#include "wx/qt/dc.h" #include "wx/qt/dc.h"
#include "wx/scopedptr.h"
class QPicture;
class WXDLLIMPEXP_CORE wxWindowDCImpl : public wxQtDCImpl class WXDLLIMPEXP_CORE wxWindowDCImpl : public wxQtDCImpl
{ {
public: public:
@@ -35,6 +39,8 @@ public:
~wxClientDCImpl(); ~wxClientDCImpl();
private: private:
wxScopedPtr<QPicture> m_pict;
wxDECLARE_CLASS(wxClientDCImpl); wxDECLARE_CLASS(wxClientDCImpl);
wxDECLARE_NO_COPY_CLASS(wxClientDCImpl); wxDECLARE_NO_COPY_CLASS(wxClientDCImpl);
}; };

View File

@@ -145,7 +145,8 @@ public:
// wxQt implementation internals: // wxQt implementation internals:
virtual QPicture *QtGetPicture() const; // Caller maintains ownership of pict - window will NOT delete it
void QtSetPicture( QPicture* pict );
QPainter *QtGetPainter(); QPainter *QtGetPainter();

View File

@@ -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); wxIMPLEMENT_CLASS(wxWindowDCImpl,wxQtDCImpl);
wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) wxWindowDCImpl::wxWindowDCImpl( wxDC *owner )
@@ -54,7 +78,7 @@ wxWindowDCImpl::~wxWindowDCImpl()
} }
if ( m_window ) 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; m_qtPainter = NULL;
} }
} }
@@ -67,6 +91,7 @@ wxClientDCImpl::wxClientDCImpl( wxDC *owner )
: wxWindowDCImpl( owner ) : wxWindowDCImpl( owner )
{ {
m_window = NULL; m_window = NULL;
m_qtPainter = NULL;
} }
wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *win ) wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *win )
@@ -74,8 +99,11 @@ wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *win )
{ {
m_window = win; m_window = win;
QPicture *pic = win->QtGetPicture(); m_qtPainter = new QPainter();
m_ok = m_qtPainter->begin( pic );
m_pict.reset(new QPicture());
m_ok = m_qtPainter->begin( m_pict.get() );
QtPreparePainter(); QtPreparePainter();
} }
@@ -88,10 +116,11 @@ wxClientDCImpl::~wxClientDCImpl()
{ {
m_qtPainter->end(); m_qtPainter->end();
m_ok = false; m_ok = false;
QPicture *pict = m_window->QtGetPicture();
if ( m_window != NULL ) if ( m_window != NULL )
{ {
QtPictureSetter pictureSetter(m_window, m_pict.get());
// get the inner widget in scroll areas: // get the inner widget in scroll areas:
QWidget *widget; QWidget *widget;
if ( m_window->QtGetScrollBarsContainer() ) if ( m_window->QtGetScrollBarsContainer() )
@@ -102,8 +131,8 @@ wxClientDCImpl::~wxClientDCImpl()
} }
// force paint event if there is something to replay and // force paint event if there is something to replay and
// if not currently inside a paint event (to avoid recursion) // if not currently inside a paint event (to avoid recursion)
QRect rect = pict->boundingRect(); QRect rect = m_pict->boundingRect();
if ( !pict->isNull() && !widget->paintingActive() && !rect.isEmpty() ) if ( !m_pict->isNull() && !widget->paintingActive() && !rect.isEmpty() )
{ {
// only force the update of the rect affected by the DC // only force the update of the rect affected by the DC
widget->update( rect ); widget->update( rect );
@@ -111,12 +140,15 @@ wxClientDCImpl::~wxClientDCImpl()
else else
{ {
// Not drawing anything, reset picture to avoid issues in handler // 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) // let destroy the m_qtPainter (see inherited classes destructors)
m_window = NULL; m_window = NULL;
} }
} }
// Painter will be deleted by base class
} }
//############################################################################## //##############################################################################

View File

@@ -210,7 +210,7 @@ void wxWindowQt::Init()
m_horzScrollBar = NULL; m_horzScrollBar = NULL;
m_vertScrollBar = NULL; m_vertScrollBar = NULL;
m_qtPicture = new QPicture(); m_qtPicture = NULL;
m_qtPainter = new QPainter(); m_qtPainter = new QPainter();
m_mouseInside = false; m_mouseInside = false;
@@ -251,7 +251,6 @@ wxWindowQt::~wxWindowQt()
DestroyChildren(); // This also destroys scrollbars DestroyChildren(); // This also destroys scrollbars
delete m_qtPicture;
delete m_qtPainter; delete m_qtPainter;
#if wxUSE_ACCEL #if wxUSE_ACCEL
@@ -1126,7 +1125,7 @@ bool wxWindowQt::QtHandlePaintEvent ( QWidget *handler, QPaintEvent *event )
{ {
bool handled; bool handled;
if ( m_qtPicture->isNull() ) if ( m_qtPicture == NULL )
{ {
// Real paint event (not for wxClientDC), prepare the background // Real paint event (not for wxClientDC), prepare the background
switch ( GetBackgroundStyle() ) switch ( GetBackgroundStyle() )
@@ -1558,9 +1557,9 @@ QScrollArea *wxWindowQt::QtGetScrollBarsContainer() const
return m_qtContainer; return m_qtContainer;
} }
QPicture *wxWindowQt::QtGetPicture() const void wxWindowQt::QtSetPicture( QPicture* pict )
{ {
return m_qtPicture; m_qtPicture = pict;
} }
QPainter *wxWindowQt::QtGetPainter() QPainter *wxWindowQt::QtGetPainter()