I have QTablewidget by QtDesigner, in which I have added Qcombobox in one of the columns. I have also added event filter to disable mouse wheel events, but it only works for the recently added combo box. How can I make it work for all the comboboxes in the table column?
what am I missing here?
Thanks.
Code by QtDesigner:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(504, 346)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(10, 10, 481, 301))
self.tableWidget.setRowCount(4)
self.tableWidget.setColumnCount(3)
self.tableWidget.setObjectName("tableWidget")
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
self.tableWidget.verticalHeader().setVisible(False)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Name"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Sex"))
item = self.tableWidget.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Age"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
My Script:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QTableWidgetItem
from demoui import Ui_MainWindow
class democode(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(democode, self).__init__()
self.setupUi(self)
#Adding Data
for row in range(0,4):
for column in range(0,3):
if column == 1:
self.combo = QtWidgets.QComboBox()
self.combo.addItem("Male")
self.combo.addItem("Female")
self.combo.installEventFilter(self)
self.tableWidget.setCellWidget(row, column, self.combo)
else:
item = QTableWidgetItem('')
self.tableWidget.setItem(row, column, item)
#Event Filter
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.Wheel and
source is self.combo):
return True
return super(democode, self).eventFilter(source, event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = democode()
window.show()
sys.exit(app.exec_())
You are making a mistake similar to the one I warned you about in this answer:
don't set instance attributes if they are not required: all those self.rowPosition, self.monthList, etc, change everytime the for loop cycles
Everytime you do this:
self.combo = QtWidgets.QComboBox()
you are overwriting the combo
attribute of the instance (self
); this means that the last combo assigned to that attribute will be what self.combo
refers to, and that's why it works for the latest combo only.
What you are doing is practically this:
self.combo = QtWidgets.QComboBox()
self.combo = QtWidgets.QComboBox()
self.combo = QtWidgets.QComboBox()
self.combo = QtWidgets.QComboBox()
# ...
Think about it: what combo will refer self.combo
to? Obviously, the last one.
In simple cases like yours, for which you're only adding a limited set of widgets to the event filter, using isinstance()
might be enough:
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.Wheel and
isinstance(source, QtWidgets.QComboBox)):
return True
return super(democode, self).eventFilter(source, event)
But this will also mean that the filter will match any QCombobox for which you've installed the event filter on. If, for any other reason, you need to install a filter on another combo that is not one in that table, the wheel event will not be received by that combo too.
The most easy and probably correct way to do that is to add those combo to a list, and check in the filter if the source is a member of that list:
class democode(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(democode, self).__init__()
self.setupUi(self)
self.noWheelCombos = []
for row in range(0,4):
for column in range(0,3):
if column == 1:
# note that I'm *NOT* using "self"
combo = QtWidgets.QComboBox()
self.noWheelCombos.append(combo)
combo.addItem("Male")
combo.addItem("Female")
combo.installEventFilter(self)
self.tableWidget.setCellWidget(row, column, combo)
# ...
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.Wheel and
source in self.noWheelCombos):
return True
return super(democode, self).eventFilter(source, event)
Another possibility is to override the wheelEvent
with a function that does nothing. This is almost the same as subclassing and overwriting the wheelEvent
method with a simple pass
; it might not be very elegant, but works fine for very simple situations like this is:
combo = QtWidgets.QComboBox()
combo.wheelEvent = lambda event: None
Finally, a small suggestion: if you always have the same elements for multiple combos, you can create a list outside the for cycle and use addItems()
instead of adding single items everytime:
items = "Male", "Female"
for row in range(0,4):
for column in range(0,3):
if column == 1:
combo = QtWidgets.QComboBox()
combo.addItems(items)
# ...