diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2017-12-13 13:35:52 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-12-14 07:16:20 +0000 |
commit | 3ec6d04d976249d162f6ec92666d9008f4c21c34 (patch) | |
tree | 2faeeae7d2c3fb5e086c91ccd5c1c9bda834005c /src | |
parent | 1c265b23ef7494abc6a00094e781a8e48de87121 (diff) |
ComboBox: use deferred execution
As a special case, ComboBox defers the execution of the popup until
the popup is either accessed or made visible. This gives a nice boost
in creation time benchmarks (20->25, ~25%). The old optimization of
setting the delegate model only when the popup is visible is no longer
needed.
Task-number: QTBUG-50992
Change-Id: Ifeaceb759ab676bb54c6bc09dc97810eade72ca1
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/imports/controls/ComboBox.qml | 6 | ||||
-rw-r--r-- | src/imports/controls/material/ComboBox.qml | 6 | ||||
-rw-r--r-- | src/imports/controls/universal/ComboBox.qml | 6 | ||||
-rw-r--r-- | src/quicktemplates2/qquickcombobox.cpp | 106 | ||||
-rw-r--r-- | src/quicktemplates2/qquickcombobox_p.h | 1 |
5 files changed, 90 insertions, 35 deletions
diff --git a/src/imports/controls/ComboBox.qml b/src/imports/controls/ComboBox.qml index 6a885320..8d1a28be 100644 --- a/src/imports/controls/ComboBox.qml +++ b/src/imports/controls/ComboBox.qml @@ -80,7 +80,7 @@ T.ComboBox { enabled: control.editable autoScroll: control.editable - readOnly: control.popup.visible + readOnly: control.down inputMethodHints: control.inputMethodHints validator: control.validator @@ -104,7 +104,7 @@ T.ComboBox { implicitHeight: 40 color: !control.editable && control.visualFocus ? (control.pressed ? Default.focusPressedColor : Default.focusLightColor) : - (control.down || popup.visible ? Default.buttonPressedColor : Default.buttonColor) + (control.down ? Default.buttonPressedColor : Default.buttonColor) border.color: Default.focusColor border.width: !control.editable && control.visualFocus ? 2 : 0 visible: !control.flat || control.down @@ -120,7 +120,7 @@ T.ComboBox { contentItem: ListView { clip: true implicitHeight: contentHeight - model: control.popup.visible ? control.delegateModel : null + model: control.delegateModel currentIndex: control.highlightedIndex highlightRangeMode: ListView.ApplyRange highlightMoveDuration: 0 diff --git a/src/imports/controls/material/ComboBox.qml b/src/imports/controls/material/ComboBox.qml index da9fd73c..d2ca7679 100644 --- a/src/imports/controls/material/ComboBox.qml +++ b/src/imports/controls/material/ComboBox.qml @@ -84,7 +84,7 @@ T.ComboBox { enabled: control.editable autoScroll: control.editable - readOnly: control.popup.visible + readOnly: control.down inputMethodHints: control.inputMethodHints validator: control.validator @@ -161,7 +161,7 @@ T.ComboBox { contentItem: ListView { clip: true implicitHeight: contentHeight - model: control.popup.visible ? control.delegateModel : null + model: control.delegateModel currentIndex: control.highlightedIndex highlightRangeMode: ListView.ApplyRange highlightMoveDuration: 0 @@ -171,7 +171,7 @@ T.ComboBox { background: Rectangle { radius: 2 - color: control.popup.Material.dialogColor + color: parent.Material.dialogColor layer.enabled: control.enabled layer.effect: ElevationEffect { diff --git a/src/imports/controls/universal/ComboBox.qml b/src/imports/controls/universal/ComboBox.qml index a2ba0236..596dcf5b 100644 --- a/src/imports/controls/universal/ComboBox.qml +++ b/src/imports/controls/universal/ComboBox.qml @@ -91,7 +91,7 @@ T.ComboBox { enabled: control.editable autoScroll: control.editable - readOnly: control.popup.visible + readOnly: control.down inputMethodHints: control.inputMethodHints validator: control.validator @@ -111,7 +111,7 @@ T.ComboBox { border.width: control.flat ? 0 : 2 // ComboBoxBorderThemeThickness border.color: !control.enabled ? control.Universal.baseLowColor : control.editable && control.activeFocus ? control.Universal.accent : - control.down || popup.visible ? control.Universal.baseMediumLowColor : + control.down ? control.Universal.baseMediumLowColor : control.hovered ? control.Universal.baseMediumColor : control.Universal.baseMediumLowColor color: !control.enabled ? control.Universal.baseLowColor : control.down ? control.Universal.listMediumColor : @@ -143,7 +143,7 @@ T.ComboBox { contentItem: ListView { clip: true implicitHeight: contentHeight - model: control.popup.visible ? control.delegateModel : null + model: control.delegateModel currentIndex: control.highlightedIndex highlightRangeMode: ListView.ApplyRange highlightMoveDuration: 0 diff --git a/src/quicktemplates2/qquickcombobox.cpp b/src/quicktemplates2/qquickcombobox.cpp index d22e09d5..dde27e2a 100644 --- a/src/quicktemplates2/qquickcombobox.cpp +++ b/src/quicktemplates2/qquickcombobox.cpp @@ -38,6 +38,7 @@ #include "qquickcontrol_p_p.h" #include "qquickabstractbutton_p.h" #include "qquickpopup_p_p.h" +#include "qquickdeferredexecute_p_p.h" #include <QtCore/qregexp.h> #include <QtCore/qabstractitemmodel.h> @@ -252,6 +253,11 @@ public: void handleRelease(const QPointF &point) override; void handleUngrab() override; + QQuickItem *getContentItem() override; + + void executeIndicator(bool complete = false); + void executePopup(bool complete = false); + bool flat; bool down; bool hasDown; @@ -268,8 +274,8 @@ public: QQuickItem *pressedItem; QQmlInstanceModel *delegateModel; QQmlComponent *delegate; - QQuickItem *indicator; - QQuickPopup *popup; + QQuickDeferredPointer<QQuickItem> indicator; + QQuickDeferredPointer<QQuickPopup> popup; struct ExtraData { ExtraData() @@ -313,6 +319,9 @@ bool QQuickComboBoxPrivate::isPopupVisible() const void QQuickComboBoxPrivate::showPopup() { + if (!popup) + executePopup(true); + if (popup && !popup->isVisible()) popup->open(); } @@ -330,13 +339,10 @@ void QQuickComboBoxPrivate::hidePopup(bool accept) void QQuickComboBoxPrivate::togglePopup(bool accept) { - if (!popup) - return; - - if (popup->isVisible()) - hidePopup(accept); - else + if (!popup || !popup->isVisible()) showPopup(); + else + hidePopup(accept); } void QQuickComboBoxPrivate::popupVisibleChanged() @@ -366,8 +372,11 @@ void QQuickComboBoxPrivate::createdItem(int index, QObject *object) { Q_Q(QQuickComboBox); QQuickItem *item = qobject_cast<QQuickItem *>(object); - if (popup && item && !item->parentItem()) { - item->setParentItem(popup->contentItem()); + if (item && !item->parentItem()) { + if (popup) + item->setParentItem(popup->contentItem()); + else + item->setParentItem(q); QQuickItemPrivate::get(item)->setCulled(true); } @@ -662,6 +671,41 @@ void QQuickComboBoxPrivate::handleUngrab() q->setPressed(false); } +QQuickItem *QQuickComboBoxPrivate::getContentItem() +{ + if (!contentItem) + executeContentItem(); + return contentItem; +} + +static inline QString indicatorName() { return QStringLiteral("indicator"); } + +void QQuickComboBoxPrivate::executeIndicator(bool complete) +{ + Q_Q(QQuickComboBox); + if (indicator.wasExecuted()) + return; + + if (!indicator) + quickBeginDeferred(q, indicatorName(), indicator); + if (complete) + quickCompleteDeferred(q, indicatorName(), indicator); +} + +static inline QString popupName() { return QStringLiteral("popup"); } + +void QQuickComboBoxPrivate::executePopup(bool complete) +{ + Q_Q(QQuickComboBox); + if (popup.wasExecuted()) + return; + + if (!popup) + quickBeginDeferred(q, popupName(), popup); + if (complete) + quickCompleteDeferred(q, popupName(), popup); +} + QQuickComboBox::QQuickComboBox(QQuickItem *parent) : QQuickControl(*(new QQuickComboBoxPrivate), parent) { @@ -677,14 +721,13 @@ QQuickComboBox::QQuickComboBox(QQuickItem *parent) QQuickComboBox::~QQuickComboBox() { Q_D(QQuickComboBox); - // Disconnect visibleChanged() to avoid a spurious highlightedIndexChanged() signal - // emission during the destruction of the (visible) popup. (QTBUG-57650) - QObjectPrivate::disconnect(d->popup, &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged); - - // Delete the popup directly instead of calling setPopup(nullptr) to avoid calling - // destroyDelegate(popup) and potentially accessing a destroyed QML context. (QTBUG-50992) - delete d->popup; - d->popup = nullptr; + if (d->popup) { + // Disconnect visibleChanged() to avoid a spurious highlightedIndexChanged() signal + // emission during the destruction of the (visible) popup. (QTBUG-57650) + QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged); + delete d->popup; + d->popup = nullptr; + } } /*! @@ -969,7 +1012,9 @@ void QQuickComboBox::setDelegate(QQmlComponent* delegate) */ QQuickItem *QQuickComboBox::indicator() const { - Q_D(const QQuickComboBox); + QQuickComboBoxPrivate *d = const_cast<QQuickComboBoxPrivate *>(d_func()); + if (!d->indicator) + d->executeIndicator(); return d->indicator; } @@ -979,13 +1024,14 @@ void QQuickComboBox::setIndicator(QQuickItem *indicator) if (d->indicator == indicator) return; - QQuickControlPrivate::destroyDelegate(d->indicator, this); + delete d->indicator; d->indicator = indicator; if (indicator) { if (!indicator->parentItem()) indicator->setParentItem(this); } - emit indicatorChanged(); + if (!d->indicator.isExecuting()) + emit indicatorChanged(); } /*! @@ -1003,7 +1049,9 @@ void QQuickComboBox::setIndicator(QQuickItem *indicator) */ QQuickPopup *QQuickComboBox::popup() const { - Q_D(const QQuickComboBox); + QQuickComboBoxPrivate *d = const_cast<QQuickComboBoxPrivate *>(d_func()); + if (!d->popup) + d->executePopup(isComponentComplete()); return d->popup; } @@ -1014,8 +1062,8 @@ void QQuickComboBox::setPopup(QQuickPopup *popup) return; if (d->popup) { - QObjectPrivate::disconnect(d->popup, &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged); - QQuickControlPrivate::destroyDelegate(d->popup, this); + QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged); + delete d->popup; } if (popup) { QQuickPopupPrivate::get(popup)->allowVerticalFlip = true; @@ -1023,7 +1071,8 @@ void QQuickComboBox::setPopup(QQuickPopup *popup) QObjectPrivate::connect(popup, &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged); } d->popup = popup; - emit popupChanged(); + if (!d->popup.isExecuting()) + emit popupChanged(); } /*! @@ -1494,7 +1543,7 @@ void QQuickComboBox::keyReleaseEvent(QKeyEvent *event) { Q_D(QQuickComboBox); QQuickControl::keyReleaseEvent(event); - if (!d->popup || event->isAutoRepeat()) + if (event->isAutoRepeat()) return; switch (event->key()) { @@ -1541,6 +1590,11 @@ void QQuickComboBox::wheelEvent(QWheelEvent *event) void QQuickComboBox::componentComplete() { Q_D(QQuickComboBox); + d->executeIndicator(true); + d->executeBackground(true); + d->executeContentItem(true); + if (d->popup) + d->executePopup(true); QQuickControl::componentComplete(); if (d->delegateModel && d->ownModel) diff --git a/src/quicktemplates2/qquickcombobox_p.h b/src/quicktemplates2/qquickcombobox_p.h index 030d068b..7c27ca99 100644 --- a/src/quicktemplates2/qquickcombobox_p.h +++ b/src/quicktemplates2/qquickcombobox_p.h @@ -82,6 +82,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickComboBox : public QQuickControl Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints NOTIFY inputMethodHintsChanged FINAL REVISION 2) Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged FINAL REVISION 2) Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged FINAL REVISION 2) + Q_CLASSINFO("DeferredPropertyNames", "background,contentItem,indicator,popup") public: explicit QQuickComboBox(QQuickItem *parent = nullptr); |