From 2eb866f331503a9d098283933d9b046a2e043731 Mon Sep 17 00:00:00 2001 From: zhangkun Date: Tue, 16 Jun 2026 11:41:20 +0800 Subject: [PATCH] fix(DPopupWindowHandle): restore focus to parent on popup close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add onPopupVisibleChanged slot to detect popup hide event 2. Add restoreParentFocus to return focus to parent window 3. Save active focus item before popup takes focus 4. Restore saved focus item when popup becomes invisible 5. Handle null window case in onWindowChanged to trigger restore Log: Fix focus not returning to parent window when popup closes fix(DPopupWindowHandle): 弹窗关闭时恢复父窗口焦点 1. 新增 onPopupVisibleChanged 槽函数检测弹窗隐藏事件 2. 新增 restoreParentFocus 方法将焦点归还父窗口 3. 弹窗获取焦点前保存当前活动焦点项 4. 弹窗不可见时恢复之前保存的焦点项 5. 在 onWindowChanged 中处理 window 为空时触发焦点恢复 Log: 修复弹窗关闭后焦点未归还父窗口的问题 PMS: BUG-366067 --- qt6/src/qml/Popup.qml | 1 + src/private/dpopupwindowhandle.cpp | 64 +++++++++++++++++++++++++++++- src/private/dpopupwindowhandle_p.h | 5 +++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/qt6/src/qml/Popup.qml b/qt6/src/qml/Popup.qml index 91f01d01..b9ab1e8d 100644 --- a/qt6/src/qml/Popup.qml +++ b/qt6/src/qml/Popup.qml @@ -12,6 +12,7 @@ T.Popup { id: control palette: D.DTK.palette + focus: popupType === Popup.Window property bool closeOnInactive: true readonly property bool active: parent && parent.Window.active diff --git a/src/private/dpopupwindowhandle.cpp b/src/private/dpopupwindowhandle.cpp index 647269a4..486dc4f3 100644 --- a/src/private/dpopupwindowhandle.cpp +++ b/src/private/dpopupwindowhandle.cpp @@ -15,6 +15,7 @@ #include #include +#include DQUICK_BEGIN_NAMESPACE @@ -52,6 +53,7 @@ DPopupWindowHandle::DPopupWindowHandle(QObject *popup) popupItemReparented(); connect(popup, SIGNAL(popupTypeChanged()), this, SLOT(updateEnabled())); + connect(popup, SIGNAL(visibleChanged()), this, SLOT(onPopupVisibleChanged())); } DQuickWindowAttached *DPopupWindowHandle::qmlAttachedProperties(QObject *object) @@ -124,6 +126,9 @@ bool DPopupWindowHandle::isEnabled() const void DPopupWindowHandle::onWindowChanged(QQuickWindow *window) { + if (!window) + restoreParentFocus(); + // Cleanup old filters if (m_popupWin) { m_popupWin->removeEventFilter(this); @@ -154,12 +159,24 @@ void DPopupWindowHandle::onWindowChanged(QQuickWindow *window) } } +void DPopupWindowHandle::onPopupVisibleChanged() +{ + if (!m_popup || m_popup->property("visible").toBool()) + return; + + restoreParentFocus(); +} + bool DPopupWindowHandle::eventFilter(QObject *watched, QEvent *event) { if (watched == m_popupWin && event->type() == QEvent::Move) { adjustPopupPosition(); } + if (watched == m_popupWin && event->type() == QEvent::Show) { + requestPopupFocus(); + } + // Close popup on parent window click (only while popup is visible) if (watched == m_parentWindow && event->type() == QEvent::MouseButtonPress && m_popup->property("visible").toBool()) { @@ -280,7 +297,52 @@ void DPopupWindowHandle::adjustPopupPosition() m_popupWin->setPosition(newPos); } +void DPopupWindowHandle::requestPopupFocus() +{ + if (!m_popup || !isEnabled() || !m_popupWin || !m_popupWin->isVisible()) + return; + if (!m_popup->property("focus").toBool()) + return; + + m_restoreFocusItem = m_parentWindow ? m_parentWindow->activeFocusItem() : nullptr; + + QMetaObject::invokeMethod(this, [this] { + if (!isEnabled() || !m_popup->property("focus").toBool() || !m_popupWin || !m_popupWin->isVisible()) + return; + + QPointer item = popupItem(); + if (!item || item->window() != m_popupWin) + return; + + m_popupFocusRequested = true; + m_popupWin->requestActivate(); + }, Qt::QueuedConnection); +} + +void DPopupWindowHandle::restoreParentFocus() +{ + if (!m_popupFocusRequested) + return; + + m_popupFocusRequested = false; + + if (!m_popupWin || !m_parentWindow || !m_parentWindow->isVisible()) { + m_restoreFocusItem.clear(); + return; + } + + m_parentWindow->requestActivate(); + if (QGuiApplication::focusWindow() == m_popupWin) + QWindowSystemInterface::handleFocusWindowChanged(m_parentWindow, Qt::PopupFocusReason); + + if (m_restoreFocusItem && m_restoreFocusItem->window() == m_parentWindow + && m_restoreFocusItem->isVisible() && m_restoreFocusItem->isEnabled()) { + m_restoreFocusItem->forceActiveFocus(Qt::OtherFocusReason); + } + + m_restoreFocusItem.clear(); +} + DQUICK_END_NAMESPACE #include "moc_dpopupwindowhandle_p.cpp" - diff --git a/src/private/dpopupwindowhandle_p.h b/src/private/dpopupwindowhandle_p.h index 43018920..8bf5f56c 100644 --- a/src/private/dpopupwindowhandle_p.h +++ b/src/private/dpopupwindowhandle_p.h @@ -51,6 +51,7 @@ class DPopupWindowHandle : public QObject, public QQuickItemChangeListener private Q_SLOTS: void updateEnabled(); void onWindowChanged(QQuickWindow *window); + void onPopupVisibleChanged(); private: QQuickWindow *popupWindow() const; @@ -59,6 +60,8 @@ private Q_SLOTS: bool isEnabled() const; void adjustPopupPosition(); + void requestPopupFocus(); + void restoreParentFocus(); private: QObject *m_popup = nullptr; @@ -68,6 +71,8 @@ private Q_SLOTS: QPointer m_parentWindow = nullptr; QPointer m_popupWin = nullptr; QPointer m_trackedItem = nullptr; + QPointer m_restoreFocusItem = nullptr; + bool m_popupFocusRequested = false; }; DQUICK_END_NAMESPACE