确定在按下按钮之前最后一个焦点的 QWidget
Posted
技术标签:
【中文标题】确定在按下按钮之前最后一个焦点的 QWidget【英文标题】:Determine QWidget that had last focus before button press 【发布时间】:2017-10-12 09:57:07 【问题描述】:我想在我的 Qt 应用程序中实现以下功能:
用户打开一个或多个“输入”小部件(InputWidget
类的实例),每个小部件都包含一个 QLineEdit
小部件
用户打开一个“帮助”对话框
用户在“帮助”对话框中选择一个值
用户在“帮助”对话框中按下“插入”QPushButton
“帮助”对话框中的选定值被插入到“输入”对话框的 QLineEdit
中,该对话框在按下“插入”按钮之前具有最后一个焦点
所以,基本上,我想要的是,如果用户在以下屏幕截图中单击“插入”,则字符串“Apple”应该出现在焦点输入对话框中。下面的代码示例确实有效,只是将字符串(通常见下文)插入到第二个字符串中。
这是创建此设置的代码示例:
from PyQt5.QtWidgets import (QApplication, QWidget, QHBoxLayout,
QLineEdit, QLabel, QPushButton, QComboBox)
import sys
# this is the missing bit
def determineWhichWidgetHadLastFocus():
for widget in QApplication.instance().topLevelWidgets():
if isinstance(widget, InputWidget):
# do something wonderful to determine whether this widget
# is the one that had last focus
wonderful = True
if wonderful:
return widget
return None
class BaseWidget(QWidget):
""" Base widget type """
def __init__(self, name):
super(BaseWidget, self).__init__()
self.setWindowTitle(name)
self.setupUi()
self.show()
def setupUi(self):
pass
class InputWidget(BaseWidget):
""" InputWidget contains a QLabel and a QLineEdit widget """
def setupUi(self):
self.label = QLabel("Input string:")
self.edit = QLineEdit()
layout = QHBoxLayout(self)
layout.addWidget(self.label)
layout.addWidget(self.edit)
class HelperWidget(BaseWidget):
""" HelperWidget contains a QLineEdit and a QPushButton widget. Pressing
the button inserts the content of the edit widget into the edit widget of
the last activated InputWidget """
def setupUi(self):
self.combo = QComboBox()
self.combo.addItems(["Apple", "Pear", "Banana"])
self.button = QPushButton("Insert")
self.button.clicked.connect(self.insertString)
layout = QHBoxLayout(self)
layout.addWidget(self.combo)
layout.addWidget(self.button)
def insertString(self):
widget = determineWhichWidgetHadLastFocus()
if widget:
widget.edit.insert(self.combo.currentText())
def main():
app = QApplication(sys.argv)
diag1 = InputWidget("Input dialog")
diag2 = InputWidget("Another input")
helper = HelperWidget("Helper")
app.exec_()
if __name__ == "__main__":
main()
缺少的部分是determineWhichWidgetHadLastFocus()
函数。
这个函数应该做一些很棒的事情,允许它确定哪个“输入”是最后一个保持焦点的。目前,它会遍历来自QApplication
的***小部件列表,但***小部件的顺序并不反映激活顺序(通常,但并不总是显示为创建顺序)。
我想到的一个想法是安装一个事件过滤器来跟踪FocusIn
事件。这对于我的示例中的 InputWidget
类来说很容易,但对于我的实际应用程序可能不太适用,因为它有许多 QLineEdit
s、QTextEdit
s 和遍布各处的后代类。我宁愿不走那条路。
还有其他想法吗?
【问题讨论】:
【参考方案1】:事实证明,事件过滤器的想法毕竟是要走的路。我所做的是首先创建一个事件过滤器类,如果发送对象是QLineEdit
对象,它会发出信号:
from PyQt5.QtCore import QObject, QEvent, pyqtSignal
class inputFocusFilter(QObject):
focusIn = pyqtSignal(object)
def eventFilter(self, widget, event):
if event.type() == QEvent.FocusIn and isinstance(widget, QLineEdit):
# emit a `focusIn` signal, with the widget as its argument:
self.focusIn.emit(widget)
return super(inputFocusFilter, self).eventFilter(widget, event)
为自定义QApplication
类安装此过滤器,以便创建的任何事件都通过过滤器。信号focusIn
连接到一个设置函数,该函数会记住最后一个获得焦点的输入小部件:
class MyApplication(QApplication):
def __init__(self, *arg, **kwarg):
super(MyApplication, self).__init__(*arg, **kwarg)
self._input_focus_widget = None
self.event_filter = inputFocusFilter()
self.event_filter.focusIn.connect(self.setInputFocusWidget)
self.installEventFilter(self.event_filter)
def setInputFocusWidget(self, widget):
self._input_focus_widget = widget
def inputFocusWidget(self):
return self._input_focus_widget
在main()
的第一行使用MyApplication
代替QApplication
。现在,HelperWidget.insertString()
中对determineWhichWidgetHadLastFocus()
的调用可以替换为QApplication.instance().inputFocusWidget()
,一切正常。
【讨论】:
以上是关于确定在按下按钮之前最后一个焦点的 QWidget的主要内容,如果未能解决你的问题,请参考以下文章