The minimal example code below renders the following GUI:
What I would like to achieve, instead, is this (manually edited image):
… which is to say, I would like the column (horizontal) headings to have two lines of text, centered: the top line of text in bigger font size, and the bottom one in smaller font size and bold font.
I originally hoped that I could just use HTML and QCSS styling for this, but
- https://forum.qt.io/topic/30598/solved-how-to-display-subscript-text-in-header-of-qtableview
this is not supported by Qt, you would need to implement a QStyledItemDelegate and set it to your QHeaderView.
The example below shows clearly HTML is not accepted in headings, too.
Unfortunately, I could not find any example that demonstrates how to use a QStyledItemDelegate
with an effect similar to what I’m looking for, so I tried something in my code below from some examples I could find – and as the first screenshot shows, obviously it does not work.
So, how can I get a heading that has two lines of text, one under the other, where the second line of text has a different font from the first one?
Code example:
# base of example from https://www.pythonguis.com/tutorials/qtableview-modelviews-numpy-pandas/
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QStyledItemDelegate, QWidget, QVBoxLayout, QLabel
coltxts = {
0: "STANDARD_COLUMN_DESCRIPTION",
1: "ADVANCED_COLUMN_DESCRIPTION",
2: "VERBOSE_COLUMN_DESCRIPTION",
}
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data):
super(TableModel, self).__init__()
self._data = data
def data(self, index, role):
if role == Qt.DisplayRole:
return self._data[index.row()][index.column()]
def headerData(self, section, orientation, role=Qt.DisplayRole): # SO:64287713
if orientation == Qt.Horizontal:
if role == Qt.DisplayRole:
retstr = "Column {}".format(section)
if section == 0:
retstr += "<br>{}".format(coltxts[section])
else:
retstr += "n{}".format(coltxts[section])
return retstr
return super().headerData(section, orientation, role)
def rowCount(self, index):
return len(self._data)
def columnCount(self, index):
return len(self._data[0])
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.table = QtWidgets.QTableView()
data = [
[4, 9, 2],
[1, 0, 0],
[3, 5, 0],
[3, 3, 2],
[7, 8, 9],
]
self.model = TableModel(data)
self.table.setModel(self.model)
htest_item = TwoLineTableWidgetItemDelegate(self.table)
self.table.setItemDelegateForColumn(0, htest_item)
#self.table.horizontalHeader().setStyleSheet("QHeaderView { font-size: 8pt; font-weight: bold; }");
QTimer.singleShot(10, self.table.resizeColumnsToContents)
self.setCentralWidget(self.table)
class TwoLineTableWidgetItemDelegate(QStyledItemDelegate): # via SO:52545316, bit of SO:24024815
"""
Tried to start this by building on:
/q/52545316/
/q/24024815/
"""
def __init__(self, icons, parent=None):
super(TwoLineTableWidgetItemDelegate, self).__init__(parent)
self.main_widget = QWidget()
self.layout = QVBoxLayout()
self.label_top = QLabel()
self.label_bottom = QLabel()
self.layout.addWidget(self.label_top)
self.layout.addWidget(self.label_bottom)
self.main_widget.setLayout(self.layout)
def paint(self, painter, option, index):
#icon = self.get_icon(index)
self.label_top.setText(str(index.row()))
self.label_bottom.setText(str(index.column()))
#self.main_widget.paint(painter, option.rect, QtCore.Qt.AlignCenter) # no paint here
self.main_widget.update()
app=QtWidgets.QApplication(sys.argv)
window=MainWindow()
window.show()
app.exec_()