当鼠标位于禁用的委托按钮时 QTableView 不滚动
QTableView not scrolling when mouse is at disabled delegate button
设置说明
- Table 在 PySide 中用
创建
QMainWindow -> QWidget -> QTableView -> TableModel (QAbstractTableModel) -> array[[]]
- 为第二列创建 ButtonDelegate(QStyledItemDelegate)
问题描述
如果委托中的按钮被禁用 [setEnabled(False)],当鼠标位于禁用按钮上方时 table 的滚动不起作用。
其他
启用按钮后,一切正常。
在我的应用程序中,我是 enabling/disabling 基于数据的按钮。
滚动应该在任何情况下都有效,否则当滚动在 table 列之一不起作用时,该功能对用户不友好 - 禁用按钮。
我用 eventFilter 尝试了一些东西,但没有任何效果。
已使用 PySide6 (6.2.2.1)、Python 3.9、Windows 10、Debian
进行测试
可能是同样的问题(但没有列出解决方案):
https://forum.qt.io/topic/123495/disabled-widget-hogs-scrollevents-how-to-disable
最小功能示例:
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout
from PySide6.QtWidgets import QTableView, QWidget, QStyledItemDelegate, QPushButton
from PySide6.QtCore import Qt, QModelIndex, QAbstractTableModel, QItemSelectionModel
class ButtonDelegate(QStyledItemDelegate):
def __init__(self, parent):
QStyledItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
self.parent().openPersistentEditor(index)
super(ButtonDelegate, self).paint(painter, option, index)
def createEditor(self, parent, option, index):
editor = QPushButton("Button", parent)
editor.setEnabled(False)
return editor
class TableModel(QAbstractTableModel):
def __init__(self, localData=[[]], parent=None):
super().__init__(parent)
self.modelData = localData
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
if role == Qt.DisplayRole:
if orientation == Qt.Vertical:
return "Row " + str(section)
def columnCount(self, parent=None):
return len(self.modelData[0])
def rowCount(self, parent=None):
return len(self.modelData)
def data(self, index: QModelIndex, role: int):
if role == Qt.DisplayRole:
row = index.row()
col = index.column()
return self.modelData[row][col]
app = QApplication()
data = [['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],
['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],
['1', '2'],['1', '2'],['1', '2'],['1', '2']]
model = TableModel(data)
tableView = QTableView()
tableView.setModel(model)
selectionModel = QItemSelectionModel(model)
tableView.setSelectionModel(selectionModel)
tableView.setItemDelegateForColumn(1, ButtonDelegate(tableView))
widget = QWidget()
widget.horizontalHeader = tableView.horizontalHeader()
widget.horizontalHeader.setStretchLastSection(True)
widget.mainLayout = QVBoxLayout()
widget.mainLayout.setContentsMargins(1,1,1,1)
widget.mainLayout.addWidget(tableView)
widget.setLayout(widget.mainLayout)
mainWindow = QMainWindow()
mainWindow.setCentralWidget(widget)
mainWindow.setGeometry(0, 0, 300, 300)
mainWindow.show()
exit(app.exec())
我可以用 PyQt6 重现这个,所以我可以确认它与 Qt6 有关
不同之处在于,Wheel
事件在 Qt6 中的禁用按钮上总是 accepted 而在 Qt5 中被忽略,这与 QAbstractButton 的特殊行为有关输入事件。这实际上被认为是 Qt5 的错误行为,因此不能将其视为错误(参见 QTBUG-79102 and QTBUG-67032)。
解决方案是将事件设置为 not 在委托的事件过滤器中接受,并 return True
传播事件致家长:
class ButtonDelegate(QStyledItemDelegate):
def eventFilter(self, obj, event):
if event.type() == event.Type.Wheel:
event.setAccepted(False)
return True
return super().eventFilter(obj, event)
请注意,在 paint
函数中打开编辑器不是一个好主意:虽然该函数通常在编辑器已经打开时被“忽略”,但任何可能导致重绘的操作(并且,可能,几何变化)应该永远不会发生在绘画函数中。
设置说明
- Table 在 PySide 中用
创建 QMainWindow -> QWidget -> QTableView -> TableModel (QAbstractTableModel) -> array[[]] - 为第二列创建 ButtonDelegate(QStyledItemDelegate)
问题描述
如果委托中的按钮被禁用 [setEnabled(False)],当鼠标位于禁用按钮上方时 table 的滚动不起作用。
其他
启用按钮后,一切正常。
在我的应用程序中,我是 enabling/disabling 基于数据的按钮。
滚动应该在任何情况下都有效,否则当滚动在 table 列之一不起作用时,该功能对用户不友好 - 禁用按钮。
我用 eventFilter 尝试了一些东西,但没有任何效果。
已使用 PySide6 (6.2.2.1)、Python 3.9、Windows 10、Debian
进行测试可能是同样的问题(但没有列出解决方案):
https://forum.qt.io/topic/123495/disabled-widget-hogs-scrollevents-how-to-disable
最小功能示例:
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout
from PySide6.QtWidgets import QTableView, QWidget, QStyledItemDelegate, QPushButton
from PySide6.QtCore import Qt, QModelIndex, QAbstractTableModel, QItemSelectionModel
class ButtonDelegate(QStyledItemDelegate):
def __init__(self, parent):
QStyledItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
self.parent().openPersistentEditor(index)
super(ButtonDelegate, self).paint(painter, option, index)
def createEditor(self, parent, option, index):
editor = QPushButton("Button", parent)
editor.setEnabled(False)
return editor
class TableModel(QAbstractTableModel):
def __init__(self, localData=[[]], parent=None):
super().__init__(parent)
self.modelData = localData
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
if role == Qt.DisplayRole:
if orientation == Qt.Vertical:
return "Row " + str(section)
def columnCount(self, parent=None):
return len(self.modelData[0])
def rowCount(self, parent=None):
return len(self.modelData)
def data(self, index: QModelIndex, role: int):
if role == Qt.DisplayRole:
row = index.row()
col = index.column()
return self.modelData[row][col]
app = QApplication()
data = [['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],
['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],['1', '2'],
['1', '2'],['1', '2'],['1', '2'],['1', '2']]
model = TableModel(data)
tableView = QTableView()
tableView.setModel(model)
selectionModel = QItemSelectionModel(model)
tableView.setSelectionModel(selectionModel)
tableView.setItemDelegateForColumn(1, ButtonDelegate(tableView))
widget = QWidget()
widget.horizontalHeader = tableView.horizontalHeader()
widget.horizontalHeader.setStretchLastSection(True)
widget.mainLayout = QVBoxLayout()
widget.mainLayout.setContentsMargins(1,1,1,1)
widget.mainLayout.addWidget(tableView)
widget.setLayout(widget.mainLayout)
mainWindow = QMainWindow()
mainWindow.setCentralWidget(widget)
mainWindow.setGeometry(0, 0, 300, 300)
mainWindow.show()
exit(app.exec())
我可以用 PyQt6 重现这个,所以我可以确认它与 Qt6 有关
不同之处在于,Wheel
事件在 Qt6 中的禁用按钮上总是 accepted 而在 Qt5 中被忽略,这与 QAbstractButton 的特殊行为有关输入事件。这实际上被认为是 Qt5 的错误行为,因此不能将其视为错误(参见 QTBUG-79102 and QTBUG-67032)。
解决方案是将事件设置为 not 在委托的事件过滤器中接受,并 return True
传播事件致家长:
class ButtonDelegate(QStyledItemDelegate):
def eventFilter(self, obj, event):
if event.type() == event.Type.Wheel:
event.setAccepted(False)
return True
return super().eventFilter(obj, event)
请注意,在 paint
函数中打开编辑器不是一个好主意:虽然该函数通常在编辑器已经打开时被“忽略”,但任何可能导致重绘的操作(并且,可能,几何变化)应该永远不会发生在绘画函数中。