Setup description
Problem description
If button in delegate is disabled [setEnabled(False)], the scrolling of table is not working when mouse is above the disabled button.
Other
When buttons are enabled,everything works well.
In my application, I'm enabling/disabling buttons based on the data.
Scrolling should work in any case, because otherwise the functionality is not user friendly, when scrolling is not working at one of the table columns - with disabled button(s).
I tried few things with eventFilter but nothing worked.
Tested with PySide6 (6.2.2.1), Python 3.9, Windows 10, Debian
Possibly the same problem (but no solution listed):
https://forum.qt.io/topic/123495/disabled-widget-hogs-scrollevents-how-to-disable
Minimal functioning example:
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())
I can reproduce this with PyQt6 so I can confirm that it's related to Qt6
The difference is that a Wheel
event is always accepted on disabled buttons in Qt6 while it's ignored on Qt5, and it's related to the special behavior of QAbstractButton for input events. This has been actually considered a wrong behavior for Qt5, so it cannot be considered a bug (see QTBUG-79102 and QTBUG-67032).
The solution is to set the set the event as not accepted in the event filter of the delegate, and return True
to propagate the event to the parent:
class ButtonDelegate(QStyledItemDelegate):
def eventFilter(self, obj, event):
if event.type() == event.Type.Wheel:
event.setAccepted(False)
return True
return super().eventFilter(obj, event)
Note that opening the editor in the paint
function is not a good idea: while the function usually is "ignored" when the editor is already open, any operation that can cause repaint (and, potentially, geometry changes) should never happen inside painting functions.