通过信号调用时无法捕获LeftMouseButtonGesture的解决方案咨询
问题
我有一组列表项,需要点击查看其详细信息。由于项数量及详情内容庞大,我需要通过左键实现滚动(因UI偏好无法使用滚动条)。
当直接调用view_details方法时,QTableWidget和QTextEdit均可正常滚动;但将QTableWidget的cellClicked信号连接到view_details后,弹窗内的QTextEdit无法再通过左键滚动。我怀疑QTableWidget拦截了手势事件,尝试事件过滤器后发现未生成事件。以下是复现问题的最小示例代码:
# PySide 5.15.2.1 from PySide2.QtWidgets import ( QApplication, QTableWidget, QTextEdit, QVBoxLayout, QWidget, QTableWidgetItem, QScroller, QDialog, ) from PySide2.QtCore import Qt DUMMYTEXT = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sagittis venenatis metus eget lobortis. Quisque purus neque, faucibus ac molestie sit amet, mollis ut lectus. Cras interdum volutpat lacus dignissim rutrum. Curabitur non magna et justo condimentum mattis. Sed nec congue mi. Duis lacinia enim sed enim consequat, facilisis sagittis nunc malesuada. Sed nec commodo orci. In feugiat efficitur elit, vel finibus urna gravida in. Duis a nunc in dolor rhoncus egestas vel ac leo. Nullam scelerisque facilisis lorem in sodales. Curabitur mattis, lacus commodo lobortis pulvinar, lorem neque malesuada massa, nec elementum lectus metus lobortis ante. Nulla sed lorem lacus. Nullam pharetra finibus sem. Nulla diam enim, accumsan tempus lacinia a, mattis sed sapien. Suspendisse dapibus neque eget purus pellentesque, vel porttitor lectus eleifend. Integer sed ante lacus. Pellentesque pretium maximus enim ut suscipit. Curabitur eu urna elit. Nunc eget feugiat odio, non posuere mi. Nam lacinia tellus sed massa efficitur vestibulum. Maecenas pharetra mattis lectus, et consequat magna finibus sit amet. Mauris non urna hendrerit, mattis eros et, rutrum sapien. Praesent tortor nunc, fringilla ac neque quis, feugiat tristique libero. Pellentesque ultrices tristique augue vitae tristique. """ class MyWidget(QWidget): def __init__(self): super().__init__() self.setMinimumSize(200, 300) self.table_widget = QTableWidget(self) self.table_widget.setColumnCount(1) self.table_widget.setRowCount(10) self.table_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) for i in range(10): item = QTableWidgetItem() item.setText("Item") self.table_widget.setItem(i, 0, item) layout = QVBoxLayout() layout.addWidget(self.table_widget) self.setLayout(layout) self.setScroller(self.table_widget) ### 直接调用时,弹窗的QTextEdit可正常获取滚动手势 self.view_details() ### 通过表格cellClicked信号调用时,弹窗的QTextEdit无法获取滚动手势 self.table_widget.cellClicked.connect(self.view_details) def setScroller(self, widget): scroller = QScroller.scroller(widget) scroller.grabGesture(widget, QScroller.LeftMouseButtonGesture) def view_details(self): dialog = QDialog(self) text_edit = QTextEdit(dialog) text_edit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) text_edit.setTextInteractionFlags(Qt.NoTextInteraction) text_edit.setText(DUMMYTEXT) self.setScroller(text_edit) layout = QVBoxLayout(dialog) layout.addWidget(text_edit) dialog.exec() if __name__ == "__main__": app = QApplication() main_widget = MyWidget() main_widget.show() app.exec_()
解决方案
问题核心是QTableWidget的左键滚动手势未及时释放,导致弹窗的QTextEdit无法接管手势事件。以下是两种可行的解决方式:
方式一:临时释放表格手势,弹窗关闭后恢复
在view_details方法开头先取消表格的手势抓取,弹窗关闭后重新启用,确保弹窗能正常获取手势:def view_details(self): # 临时释放表格的左键滚动手势 QScroller.scroller(self.table_widget).ungrabGesture(self.table_widget) dialog = QDialog(self) # 原有弹窗代码保持不变 dialog.exec() # 弹窗关闭后重新启用表格的手势 self.setScroller(self.table_widget)方式二:明确弹窗窗口标志,强化模态优先级
创建QDialog时指定Qt.Dialog窗口标志,确保弹窗的事件循环能优先接管输入事件:def view_details(self): # 指定窗口标志,提升弹窗的事件优先级 dialog = QDialog(self, Qt.Dialog) # 原有弹窗代码保持不变 dialog.exec()
修改后的完整代码:
# PySide 5.15.2.1 from PySide2.QtWidgets import ( QApplication, QTableWidget, QTextEdit, QVBoxLayout, QWidget, QTableWidgetItem, QScroller, QDialog, ) from PySide2.QtCore import Qt DUMMYTEXT = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sagittis venenatis metus eget lobortis. Quisque purus neque, faucibus ac molestie sit amet, mollis ut lectus. Cras interdum volutpat lacus dignissim rutrum. Curabitur non magna et justo condimentum mattis. Sed nec congue mi. Duis lacinia enim sed enim consequat, facilisis sagittis nunc malesuada. Sed nec commodo orci. In feugiat efficitur elit, vel finibus urna gravida in. Duis a nunc in dolor rhoncus egestas vel ac leo. Nullam scelerisque facilisis lorem in sodales. Curabitur mattis, lacus commodo lobortis pulvinar, lorem neque malesuada massa, nec elementum lectus metus lobortis ante. Nulla sed lorem lacus. Nullam pharetra finibus sem. Nulla diam enim, accumsan tempus lacinia a, mattis sed sapien. Suspendisse dapibus neque eget purus pellentesque, vel porttitor lectus eleifend. Integer sed ante lacus. Pellentesque pretium maximus enim ut suscipit. Curabitur eu urna elit. Nunc eget feugiat odio, non posuere mi. Nam lacinia tellus sed massa efficitur vestibulum. Maecenas pharetra mattis lectus, et consequat magna finibus sit amet. Mauris non urna hendrerit, mattis eros et, rutrum sapien. Praesent tortor nunc, fringilla ac neque quis, feugiat tristique libero. Pellentesque ultrices tristique augue vitae tristique. """ class MyWidget(QWidget): def __init__(self): super().__init__() self.setMinimumSize(200, 300) self.table_widget = QTableWidget(self) self.table_widget.setColumnCount(1) self.table_widget.setRowCount(10) self.table_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) for i in range(10): item = QTableWidgetItem() item.setText("Item") self.table_widget.setItem(i, 0, item) layout = QVBoxLayout() layout.addWidget(self.table_widget) self.setLayout(layout) self.setScroller(self.table_widget) self.view_details() self.table_widget.cellClicked.connect(self.view_details) def setScroller(self, widget): scroller = QScroller.scroller(widget) scroller.grabGesture(widget, QScroller.LeftMouseButtonGesture) def view_details(self): # 临时释放表格的左键滚动手势 QScroller.scroller(self.table_widget).ungrabGesture(self.table_widget) dialog = QDialog(self) text_edit = QTextEdit(dialog) text_edit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) text_edit.setTextInteractionFlags(Qt.NoTextInteraction) text_edit.setText(DUMMYTEXT) self.setScroller(text_edit) layout = QVBoxLayout(dialog) layout.addWidget(text_edit) dialog.exec() # 弹窗关闭后重新启用表格的手势 self.setScroller(self.table_widget) if __name__ == "__main__": app = QApplication() main_widget = MyWidget() main_widget.show() app.exec_()
原理说明:
通过cellClicked触发弹窗时,QTableWidget的滚动手势仍处于激活状态,会拦截鼠标事件。临时释放手势后,弹窗的QTextEdit能正常获取滚动控制权;弹窗关闭后恢复表格手势,不影响原功能。
内容的提问来源于stack exchange,提问作者redstart
相关产品推荐
相关产品推荐

