From e3921b8b3c965150d82109963fdae2b4475aab7f Mon Sep 17 00:00:00 2001 From: Tian Shilin Date: Mon, 15 Jun 2026 15:31:54 +0800 Subject: [PATCH] fix: Optimize tab focus navigation in Remote Management log: setCurrentIndex(...) is called synchronously within the focusOut slot, which triggers setFocus() on the newly selected ItemWidget. Although Qt's focus transfer doesn't actually complete until after focusOutEvent finishes, calling setFocus() synchronously inside a slot is an established pattern already used by existing lambdas in this codebase (the original code also directly called m_pushButton->setFocus() in the slot), so it should be stable. If focus jittering or recursion occurs during testing, fall back to using QMetaObject::invokeMethod(..., Qt::QueuedConnection) for deferred execution. pms: bug-283743 --- src/remotemanage/remotemanagementpanel.cpp | 30 +++++++++++++----- src/views/listview.cpp | 36 +++++++++++++++++++++- src/views/listview.h | 8 +++++ 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/remotemanage/remotemanagementpanel.cpp b/src/remotemanage/remotemanagementpanel.cpp index f88378b3..a36a3a54 100644 --- a/src/remotemanage/remotemanagementpanel.cpp +++ b/src/remotemanage/remotemanagementpanel.cpp @@ -47,8 +47,9 @@ void RemoteManagementPanel::setFocusInPanel() qCDebug(remotemanage) << "list widget is visible, setting focus"; // 列表显示 /******** Modify by ut000610 daizhengwen 2020-07-27:bug#39775 Begin***************/ - // 将焦点设置在列表里的第一项 - m_listWidget->setCurrentIndex(0); + // 将焦点设置在列表里的第一个可聚焦项 + int idx = m_listWidget->firstFocusableIndex(); + m_listWidget->setCurrentIndex(idx >= 0 ? idx : 0); /********************* Modify by ut000610 daizhengwen End ************************/ } else { qCDebug(remotemanage) << "setting focus on add button"; @@ -330,21 +331,36 @@ void RemoteManagementPanel::initUI() }); connect(m_listWidget, &ListView::focusOut, this, [ = ](Qt::FocusReason type) { qCDebug(remotemanage) << "Lambda: list widget focus out signal received"; - if (Qt::TabFocusReason == type || Qt::NoFocusReason == type) { - qCDebug(remotemanage) << "tab or no focus reason, setting focus to add button"; - // 下一个 或 列表为空, 焦点定位到添加按钮上 + if (Qt::TabFocusReason == type) { + int next = m_listWidget->nextFocusableIndex(m_listWidget->currentIndex()); + if (next >= 0) { + m_listWidget->setCurrentIndex(next); + return; + } + // 已到末项或列表空 → 跳到 Add Server m_pushButton->setFocus(); m_listWidget->clearIndex(); qCInfo(remotemanage) << "set focus on add pushButton"; } else if (Qt::BacktabFocusReason == type) { qCDebug(remotemanage) << "back tab focus reason"; - // 判断是否可见,可见设置焦点 + int prev = m_listWidget->prevFocusableIndex(m_listWidget->currentIndex()); + if (prev >= 0) { + m_listWidget->setCurrentIndex(prev); + return; + } + // 已到首项 → 回搜索框(如可见) if (m_searchEdit->isVisible()) { qCDebug(remotemanage) << "search edit is visible, setting focus"; m_searchEdit->lineEdit()->setFocus(); m_listWidget->clearIndex(); - qCInfo(remotemanage) << "set focus on add search edit"; + qCInfo(remotemanage) << "set focus on search edit"; } + } else if (Qt::NoFocusReason == type) { + qCDebug(remotemanage) << "no focus reason, setting focus to add button"; + // 列表为空或索引无效 → 跳到 Add Server + m_pushButton->setFocus(); + m_listWidget->clearIndex(); + qCInfo(remotemanage) << "set focus on add pushButton"; } }); diff --git a/src/views/listview.cpp b/src/views/listview.cpp index cfb16edb..12cfb5d7 100644 --- a/src/views/listview.cpp +++ b/src/views/listview.cpp @@ -225,6 +225,39 @@ int ListView::getNextIndex(int index) } } +static bool isFocusableItemType(ItemFuncType t) +{ + return t != ItemFuncType_GroupLabel && t != ItemFuncType_ItemLabel; +} + +int ListView::firstFocusableIndex() +{ + for (int i = 0; i < m_itemList.count(); ++i) + if (isFocusableItemType(m_itemList.at(i)->getFuncType())) return i; + return -1; +} + +int ListView::lastFocusableIndex() +{ + for (int i = m_itemList.count() - 1; i >= 0; --i) + if (isFocusableItemType(m_itemList.at(i)->getFuncType())) return i; + return -1; +} + +int ListView::nextFocusableIndex(int from) +{ + for (int i = from + 1; i < m_itemList.count(); ++i) + if (isFocusableItemType(m_itemList.at(i)->getFuncType())) return i; + return -1; +} + +int ListView::prevFocusableIndex(int from) +{ + for (int i = from - 1; i >= 0; --i) + if (isFocusableItemType(m_itemList.at(i)->getFuncType())) return i; + return -1; +} + void ListView::setCurrentIndex(int currentIndex) { qCDebug(views) << "ListView::setCurrentIndex() entered, index:" << currentIndex; @@ -698,7 +731,8 @@ void ListView::focusInEvent(QFocusEvent *event) if (event->reason() == Qt::TabFocusReason) { qCDebug(views) << "Branch: TabFocusReason"; - setCurrentIndex(0); + int idx = firstFocusableIndex(); + setCurrentIndex(idx >= 0 ? idx : 0); } else { qCDebug(views) << "Branch: not TabFocusReason"; setCurrentIndex(m_currentIndex); diff --git a/src/views/listview.h b/src/views/listview.h index 58cdf661..3b700f6d 100644 --- a/src/views/listview.h +++ b/src/views/listview.h @@ -117,6 +117,14 @@ class ListView : public DScrollArea * @return */ int getNextIndex(int index); + /** @brief 第一个可聚焦项(跳过 GroupLabel/ItemLabel)的 index,无则 -1 */ + int firstFocusableIndex(); + /** @brief 最后一个可聚焦项的 index,无则 -1 */ + int lastFocusableIndex(); + /** @brief from 之后下一个可聚焦项 index,无则 -1 */ + int nextFocusableIndex(int from); + /** @brief from 之前上一个可聚焦项 index,无则 -1 */ + int prevFocusableIndex(int from); /** * @brief 设置当前焦点 * @author ut000610 戴正文