重置选项卡式停靠小部件中的焦点

Reset focus in tabified dock widgets

目前我在处理表格化 QDockWidgets 的焦点时遇到了问题。 使用两个制表 QDockWidgets 处理这个小例子:

from PyQt5.QtWidgets import QApplication, QMainWindow, QDockWidget, QTextEdit
from PyQt5.Qt import Qt

app = QApplication( [] )
main = QMainWindow(None, Qt.Window)
main.show()

dock1 = QDockWidget( "D1", main )
dock1.setWidget( QTextEdit( dock1 ) )
main.addDockWidget( Qt.TopDockWidgetArea, dock1 )

dock2 = QDockWidget( "D2", main )
dock2.setWidget( QTextEdit( dock2 ) )
main.tabifyDockWidget( dock1, dock2 )

exit( app.exec() )

我发现 QTextEdits 在切换到标签化小部件的其他标签时不会失去焦点。

  1. 在其中一个字段中写入文本
  2. 单击 QTabBar 上的另一个选项卡
  3. 继续您的键盘输入

您写的第二个文本仍然在第一个小部件的焦点上。


所以,一般来说:
有没有办法失去标签化小部件的焦点,无论它是 QTextEdit 还是其他一些小部件(甚至可能具有复杂的子布局结构)?

我在 QDockWidget 上尝试了 clearFocus(),但如果 QDockWidget 本身包含焦点(不是它的子对象),这似乎才有效。
在之前使用 setFocus() 似乎也不是一个好的选择,因为小部件(或其子项)可能不会在所有情况下都包含焦点。因此,从其他小部件中窃取它是不合适的。


我认为最好的反应锚是:

如果你想找到动态创建的 QTabBar:

一个非常简单的方法是检查当前 focus widget 是否是 QDockWidget 的后代,只要选项卡发生变化,然后在必要时重置焦点:

from PyQt5.QtWidgets import QApplication, QMainWindow, QDockWidget, QTextEdit
from PyQt5.QtCore import Qt

class DockWidget(QDockWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWidget(QTextEdit(self))
        self.visibilityChanged.connect(self.updateFocus)

    def updateFocus(self, visible):
        if visible:
            widget = QApplication.instance().focusWidget()
            while widget is not None:
                if isinstance(widget, QDockWidget):
                    widget = None
                elif widget.parentWidget() is not None:
                    widget = widget.parentWidget()
                else:
                    break
            if widget is None:
                self.setFocus()
                self.focusNextChild()

app = QApplication([''])
main = QMainWindow()
main.setCentralWidget(QTextEdit(main))

dock1 = DockWidget("D1", main)
main.addDockWidget(Qt.TopDockWidgetArea, dock1)

dock2 = DockWidget("D2", main)
main.tabifyDockWidget(dock1, dock2)

main.show()
app.exec()