From e3e7296da09f6d84e0c6868fbd119131fbda3402 Mon Sep 17 00:00:00 2001 From: Jan-Arve Saether Date: Wed, 23 Nov 2011 12:02:22 +0100 Subject: [PATCH] Do not paint the widget twice if it is added to a layout. When an item not part of the scene is added to a layout it several things will happen: 1. It will be plugged into to the layout structures. 2. It will be reparented to be a child of the widget that holds the layout, thus it will also be added to the scene and made visible 3. The layout will be invalidated This means that layout->addItem(item) will cause that 1. a paint event is posted (because its made visible) 2. MetaCall for _q_relayout() is posted (because the layout was invalidated) The next event loop, the two events are processed in this order: 1. Paint event will be processed, (causing it to be painted with its default geometry). 2. Then, the MetaCall is processed. This will finally change the geometry the item(s) in the layout, which again will call prepareGeometryChange(), which will eventually post a paint event. The next event loop, the paint event is processed, causing it to be painted with the expected/arranged geometry. The solution is to not add the item to the scene in addItem(), but rather do that when the MetaCall is received. This means that the widget is shown at the same time as the potential other items are rearranged. This kind of makes sense, because then *all* geometry changes, (including the ones we get by making a widget visible) is done at the same time. Unfortunately this has a slight behaviour change if you consider this code: QGraphicsWidget *parent = new QGraphicsWidget; QGraphicsWidget *w = new QGraphicsWidget; parent->layout()->addItem(w); Q_ASSERT(w->parentItem() == parent); After this patch the assert will trigger. However, if you wait until the event is processed it won't trigger: // Will process the _q_relayout-> calls activate() and then reparent. QApplication::processEvents(); Q_ASSERT(w->parentItem() == parent); // now we're fine. The patch might regress slightly in performance in some cases, but this can be improved. --- src/gui/graphicsview/qgraphicslayout_p.cpp | 5 ++++- src/gui/graphicsview/qgraphicslayout_p.h | 2 ++ src/gui/graphicsview/qgraphicslinearlayout.cpp | 9 ++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicslayout_p.cpp b/src/gui/graphicsview/qgraphicslayout_p.cpp index a68dd4e..77de856 100644 --- a/src/gui/graphicsview/qgraphicslayout_p.cpp +++ b/src/gui/graphicsview/qgraphicslayout_p.cpp @@ -115,7 +115,7 @@ Qt::LayoutDirection QGraphicsLayoutPrivate::visualDirection() const return QApplication::layoutDirection(); } -static bool removeLayoutItemFromLayout(QGraphicsLayout *lay, QGraphicsLayoutItem *layoutItem) +bool removeLayoutItemFromLayout(QGraphicsLayout *lay, QGraphicsLayoutItem *layoutItem) { if (!lay) return false; @@ -179,6 +179,9 @@ void QGraphicsLayoutPrivate::addChildLayoutItem(QGraphicsLayoutItem *layoutItem) void QGraphicsLayoutPrivate::activateRecursive(QGraphicsLayoutItem *item) { if (item->isLayout()) { + if (QGraphicsItem *parItem = parentItem()) + static_cast(item)->d_func()->reparentChildItems(parItem); + QGraphicsLayout *layout = static_cast(item); if (layout->d_func()->activated) { if (QGraphicsLayout::instantInvalidatePropagation()) { diff --git a/src/gui/graphicsview/qgraphicslayout_p.h b/src/gui/graphicsview/qgraphicslayout_p.h index 586cbc7..19a6e80 100644 --- a/src/gui/graphicsview/qgraphicslayout_p.h +++ b/src/gui/graphicsview/qgraphicslayout_p.h @@ -78,6 +78,8 @@ inline bool qt_graphicsLayoutDebug() } #endif +bool removeLayoutItemFromLayout(QGraphicsLayout *lay, QGraphicsLayoutItem *layoutItem); + class QLayoutStyleInfo { diff --git a/src/gui/graphicsview/qgraphicslinearlayout.cpp b/src/gui/graphicsview/qgraphicslinearlayout.cpp index 2a5d5a5..e4e4fd3 100644 --- a/src/gui/graphicsview/qgraphicslinearlayout.cpp +++ b/src/gui/graphicsview/qgraphicslinearlayout.cpp @@ -275,7 +275,14 @@ void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item) qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself"); return; } - d->addChildLayoutItem(item); + + // Reparent it in the layout hierarchy + if (QGraphicsLayoutItem *maybeLayout = item->parentLayoutItem()) { + if (maybeLayout->isLayout()) + removeLayoutItemFromLayout(static_cast(maybeLayout), item); + } + item->setParentLayoutItem(this); + Q_ASSERT(item); d->fixIndex(&index); -- 1.7.6.msysgit.0