首页 > 解决方案 > 是否可以在 QtableWidget 的垂直标题上应用 LableHeaderView?

问题描述

我试图在 QtableWidget 上将 LabelHeaderView 应用于将 Qlabel 作为标题项的垂直标题,它适用于具有水平标题的表格,但不适用于具有垂直标题的表格。所以,如何在 QtableWidget 的垂直标题上添加 Qlabel这个类LabelHeaderView的帮助?

from PyQt5 import QtCore, QtGui, QtWidgets


class HeaderProxyStyle(QtWidgets.QProxyStyle):
    def drawControl(self, element, option, painter, widget=None):
        if element == QtWidgets.QStyle.CE_Header:
            option.text = ""
        super(HeaderProxyStyle, self).drawControl(
            element, option, painter, widget
        )


class LabelHeaderView(QtWidgets.QHeaderView):
    def __init__(self, parent):
        super(LabelHeaderView, self).__init__(QtCore.Qt.Horizontal, parent)
        self.m_labels = []
        self.sectionResized.connect(self.adjustPositions)
        self.sectionCountChanged.connect(self.onSectionCountChanged)
        self.parent().horizontalScrollBar().valueChanged.connect(
            self.adjustPositions
        )
        proxy_style = HeaderProxyStyle(self.style())
        self.setStyle(proxy_style)

    @QtCore.pyqtSlot()
    def onSectionCountChanged(self):
        while self.m_labels:
            label = self.m_labels.pop()
            label.deleteLater()
        for i in range(self.count()):
            label = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignCenter)
            self.m_labels.append(label)
            self.update_data()
            self.adjustPositions()

    def setModel(self, model):
        super(LabelHeaderView, self).setModel(model)
        if self.model() is not None:
            self.model().headerDataChanged.connect(self.update_data)

    def update_data(self):
        option = QtWidgets.QStyleOptionHeader()
        self.initStyleOption(option)
        for i, label in enumerate(self.m_labels):
            text = self.model().headerData(
                i, self.orientation(), QtCore.Qt.DisplayRole
            )
            label.setText(str(text))
            pal = label.palette()
            bc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.BackgroundRole
            )
            if bc is None:
                bc = option.palette.brush(QtGui.QPalette.Window)
            pal.setBrush(QtGui.QPalette.Window, bc)

            fc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.ForegroundRole
            )
            if fc is None:
                fc = option.palette.brush(QtGui.QPalette.ButtonText)
            pal.setBrush(QtGui.QPalette.ButtonText, fc)

            label.setPalette(pal)

            textAlignment = self.model().headerData(
                i, self.orientation(), QtCore.Qt.TextAlignmentRole
            )
            if textAlignment is None:
                textAlignment = self.defaultAlignment()
            label.setAlignment(textAlignment)

    def updateGeometries(self):
        super(LabelHeaderView, self).updateGeometries()
        self.adjustPositions()

    @QtCore.pyqtSlot()
    def adjustPositions(self):
        for index, label in enumerate(self.m_labels):
            geom = QtCore.QRect(
                self.sectionViewportPosition(index),
                0,
                self.sectionSize(index),
                self.height(),
            )
            geom.adjust(2, 0, -2, 0)
            label.setGeometry(geom)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QTableWidget(10, 10)
    header = LabelHeaderView(w)
    w.setVerticalHeader(header)

    header_labels = []
    for i in range(w.columnCount()):
        header_label = "<sub>%s</sub><b>Header</b><sup>%s</sup>" % (i, i)
        header_labels.append(header_label)
    w.setVerticalHeaderLabels(header_labels)

    w.resize(320, 240)
    w.show()
    sys.exit(app.exec_())

标签: pythonpyqt5

解决方案


您必须更改 QHeaderView 的几何计算和方向:

from PyQt5 import QtCore, QtGui, QtWidgets


class HeaderProxyStyle(QtWidgets.QProxyStyle):
    def drawControl(self, element, option, painter, widget=None):
        if element == QtWidgets.QStyle.CE_Header:
            option.text = ""
        super(HeaderProxyStyle, self).drawControl(element, option, painter, widget)


class LabelHeaderView(QtWidgets.QHeaderView):
    def __init__(self, parent):
        super(LabelHeaderView, self).__init__(QtCore.Qt.Vertical, parent)
        self.m_labels = []
        self.sectionResized.connect(self.adjustPositions)
        self.sectionCountChanged.connect(self.onSectionCountChanged)
        self.parent().horizontalScrollBar().valueChanged.connect(self.adjustPositions)
        proxy_style = HeaderProxyStyle(self.style())
        self.setStyle(proxy_style)

    @QtCore.pyqtSlot()
    def onSectionCountChanged(self):
        while self.m_labels:
            label = self.m_labels.pop()
            label.deleteLater()
        for i in range(self.count()):
            label = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignCenter)
            self.m_labels.append(label)
            self.update_data()
            self.adjustPositions()

    def setModel(self, model):
        super(LabelHeaderView, self).setModel(model)
        if self.model() is not None:
            self.model().headerDataChanged.connect(self.update_data)

    def update_data(self):
        option = QtWidgets.QStyleOptionHeader()
        self.initStyleOption(option)
        for i, label in enumerate(self.m_labels):
            text = self.model().headerData(i, self.orientation(), QtCore.Qt.DisplayRole)
            label.setText(str(text))
            pal = label.palette()
            bc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.BackgroundRole
            )
            if bc is None:
                bc = option.palette.brush(QtGui.QPalette.Window)
            pal.setBrush(QtGui.QPalette.Window, bc)

            fc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.ForegroundRole
            )
            if fc is None:
                fc = option.palette.brush(QtGui.QPalette.ButtonText)
            pal.setBrush(QtGui.QPalette.ButtonText, fc)

            label.setPalette(pal)

            textAlignment = self.model().headerData(
                i, self.orientation(), QtCore.Qt.TextAlignmentRole
            )
            if textAlignment is None:
                textAlignment = self.defaultAlignment()
            label.setAlignment(textAlignment)

    def updateGeometries(self):
        super(LabelHeaderView, self).updateGeometries()
        self.adjustPositions()

    @QtCore.pyqtSlot()
    def adjustPositions(self):
        w = -1
        for index, label in enumerate(self.m_labels):
            geom = QtCore.QRect(
                0,
                self.sectionViewportPosition(index),
                label.sizeHint().width(),
                self.sectionSize(index),
            )
            w = geom.width() if w == -1 else max(w, geom.width())
            geom.adjust(0, 2, 0, -2)
            label.setGeometry(geom)
        self.setFixedWidth(w + 10)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QTableWidget(10, 10)
    header = LabelHeaderView(w)
    w.setVerticalHeader(header)

    header_labels = []
    for i in range(w.columnCount()):
        header_label = "<sub>%s</sub><b>Header</b><sup>%s</sup>" % (i, i)
        header_labels.append(header_label)
    w.setVerticalHeaderLabels(header_labels)

    w.resize(320, 240)
    w.show()
    sys.exit(app.exec_())

推荐阅读