How to do QtWidgets.QTableWidget.setHorizontalHeader() to maintain default behavior?

72 Views Asked by At

pyqt5. Regular table:

from PyQt5 import QtWidgets

app = QtWidgets.QApplication([])

table = QtWidgets.QTableWidget(3, 3)

table.setHorizontalHeaderLabels(['1', '2', '3'])

table.show()
app.exec_()

Here, clicking on column header selects the whole column.

If I try to pass explicitly the QtWidgets.QHeaderView, I lose some of the default behavior, notably clicking on header no longer selects the column:

from PyQt5 import QtWidgets, QtCore

class CustomTableWidget(QtWidgets.QTableWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setHorizontalHeader(QtWidgets.QHeaderView(QtCore.Qt.Horizontal))

app = QtWidgets.QApplication([])

table = CustomTableWidget(3, 3)
table.setHorizontalHeaderLabels(['1', '2', '3'])
table.show()

app.exec_()

I tried selecting different parent widgets for QHeaderView including the table, subclassing QHeaderView, etc. Could not achieve default behavior. (I obviously wouldn't want to reimplement explicitly the defaults from scatch)

2

There are 2 best solutions below

2
BlueSky On

You have a normal table, and when trying to subclass it you lose the default behavior of being able to select columns ?

That will be since you added the line self.setHorizontalHeader(QtWidgets.QHeaderView(QtCore.Qt.Horizontal)) . When you make a declaration like this its going to override any default behavior inbuilt. Removing it will give your expected result.

from PyQt6 import QtWidgets, QtCore

class CustomTableWidget(QtWidgets.QTableWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # @SomebodyYoung Do not set a new horizontal header explicitly as it will just override the normal set behaviour

app = QtWidgets.QApplication([])
table = CustomTableWidget(3, 3)
table.setHorizontalHeaderLabels(['1', '2', '3'])
table.show()
app.exec()

I made thin as a PyQT6 version as its most recent, but do change anyway you want. Hope that helps.

1
Somebody Young On

QTableWidget for some weird reason does additional steps during init (https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/itemviews/qtableview.cpp#n587) instead of subclassing QHeaderView. Therefore to get full default behavior, need to implement those additional steps:

from PyQt5 import QtWidgets, QtCore


class CustomTableWidget(QtWidgets.QTableWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.header = QtWidgets.QHeaderView(QtCore.Qt.Horizontal)
        self.header.setSectionsClickable(True)  # From QTableWidget's init
        self.header.setHighlightSections(True)  # From QTableWidget's init
        self.setHorizontalHeader(self.header)
        self.setHorizontalHeader(self.header)


app = QtWidgets.QApplication([])
table = CustomTableWidget(3, 3)
table.setHorizontalHeaderLabels(['1', '2', '3'])
table.show()
app.exec_()