QCompleter在QGraphicsView中仅每隔一次生效的问题排查与解决
问题
在QGraphicsScene中放置带有QCompleter的QLineEdit时,每次按键都会出现自动补全菜单反复显示又消失的异常,该问题仅在QGraphicsView环境下出现,脱离视图时下拉菜单工作正常。
复现代码:
from PySide6 import QtWidgets app = QtWidgets.QApplication([]) scene = QtWidgets.QGraphicsScene() view = QtWidgets.QGraphicsView(scene) line_edit = QtWidgets.QLineEdit() completer = QtWidgets.QCompleter(['123456789', '1234567890']) line_edit.setCompleter(completer) scene.addWidget(line_edit) view.show() app.exec()
异常原因
QCompleter的下拉菜单属于顶级窗口,当它在QGraphicsView内部触发显示时,菜单弹出会触发QGraphicsView的焦点重获取或场景事件重绘,干扰QCompleter的正常状态,导致菜单被意外关闭;随后输入事件又会再次触发补全显示,形成反复闪跳的循环。
本质是QGraphicsScene的事件处理机制与QCompleter的顶级窗口交互存在冲突——QGraphicsView会拦截或重新分发部分事件,破坏了QCompleter原本的焦点和显示逻辑。
修复方案
有两种可靠的解决方式:
方式一:指定QCompleter的父窗口为QGraphicsView
将completer的父对象明确设置为view,让补全菜单的窗口归属脱离QGraphicsScene的事件干扰范围:
from PySide6 import QtWidgets app = QtWidgets.QApplication([]) scene = QtWidgets.QGraphicsScene() view = QtWidgets.QGraphicsView(scene) line_edit = QtWidgets.QLineEdit() # 将父对象指定为view completer = QtWidgets.QCompleter(['123456789', '1234567890'], parent=view) line_edit.setCompleter(completer) scene.addWidget(line_edit) view.show() app.exec()
方式二:自定义QLineEdit稳定焦点
通过事件过滤器确保输入时QLineEdit的焦点不会被意外转移,维持QCompleter的正常显示状态:
from PySide6 import QtWidgets, QtCore class StableLineEdit(QtWidgets.QLineEdit): def __init__(self, parent=None): super().__init__(parent) self.installEventFilter(self) def eventFilter(self, obj, event): if obj is self and event.type() == QtCore.QEvent.KeyPress: # 强制保持自身焦点,避免场景事件干扰 self.setFocus(QtCore.Qt.OtherFocusReason) return super().eventFilter(obj, event) app = QtWidgets.QApplication([]) scene = QtWidgets.QGraphicsScene() view = QtWidgets.QGraphicsView(scene) line_edit = StableLineEdit() completer = QtWidgets.QCompleter(['123456789', '1234567890']) line_edit.setCompleter(completer) scene.addWidget(line_edit) view.show() app.exec()
内容的提问来源于stack exchange,提问作者Aran-Fey
相关产品推荐
相关产品推荐

