QListView复杂自定义委托内点击QTableView无法选中父行问题
问题原因
- QTableView属于滚动区控件,实际响应用户交互的是其内部的
viewport子部件,仅给QTableView本身设置NoFocus不会阻止viewport消费鼠标点击事件 - 点击事件被viewport拦截后不会向上冒泡到父级ItemEditor,因此QListView无法捕获点击,也就不会触发
clicked信号和行选中逻辑
解决方法
根据你对QTableView的交互需求,可以二选一:
方案A:无需保留QTableView交互能力(仅作数据展示)
直接设置QTableView的鼠标事件穿透属性,所有点击会直接透传给父级行部件,无需额外逻辑,在ItemEditor的__init__里添加一行即可:
self.table_view.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
方案B:需要保留QTableView的滚动、单元格点击等交互能力
使用事件过滤器将鼠标点击事件同时转发给父级行部件,既不影响QTableView本身的功能,也能触发QListView的行选中,修改如下:
- 头部补充导入QtGui模块
from PyQt5 import QtWidgets, QtCore, QtGui
- 修改
ItemEditor类:
class ItemEditor(QWidget): def __init__(self, parent=None): super().__init__(parent) self.verticalLayout = QVBoxLayout(self) self.line_label = QLabel("This is a line", self) self.verticalLayout.addWidget(self.line_label) self.table_view = QTableView(self) self.table_view.setFocusPolicy(QtCore.Qt.NoFocus) self.table_view.viewport().setFocusPolicy(QtCore.Qt.NoFocus) self.table_view.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) self.table_view.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) self.table_view.horizontalHeader().setVisible(False) self.table_view.verticalHeader().setVisible(False) self.verticalLayout.addWidget(self.table_view) # 给viewport安装事件过滤器 self.table_view.viewport().installEventFilter(self) def eventFilter(self, watched, event): if watched == self.table_view.viewport() and event.type() == QtCore.QEvent.MouseButtonPress: # 转发点击事件到父级行容器 forwarded_event = QtGui.QMouseEvent( event.type(), self.mapFromGlobal(event.globalPos()), event.globalPos(), event.button(), event.buttons(), event.modifiers() ) QtWidgets.QApplication.sendEvent(self.parent(), forwarded_event) # 不拦截原事件,保留给QTableView本身处理 return super().eventFilter(watched, event)
修改完成后运行代码,点击QTableView区域就会正常触发change_line方法,也能正常选中对应行了。
内容的提问来源于stack exchange,提问作者AlexandreS
相关产品推荐
相关产品推荐

