Стилизация заголовка таблицы QTableWidget

Рейтинг: 1Ответов: 2Опубликовано: 13.03.2023

Была таблица. Получала данные из БД, отрисовывала данные и т.д. И стала она длинной в километр.
И захотелось мне повернуть текст в заголовках на 90 градусов. Сам этого тоже не смог, ответили в другой теме.


Было вот так: введите сюда описание изображения

Применил следующий код:

    from PyQt6 import QtWidgets, QtGui, QtCore
        from PyQt6.QtCore import Qt
        from PyQt6.QtWidgets import *
        from PyQt6.QtWidgets import QTableWidgetItem
    
        class MyHeaderView(QHeaderView):
        def __init__(self, parent=None):
    
            super().__init__(QtCore.Qt.Orientation.Horizontal, parent)
            self._font = QtGui.QFont("Times", 10, QFont.Weight.Bold)
            self._metrics = QtGui.QFontMetrics(self._font)
            self._descent = self._metrics.descent()
            # self.setStyleSheet("QHeaderView {background-color: #ffffff;}")
    
        def paintSection(self, painter, rect, index):
            data = self._get_data(index)
            if index == 2 or index == 3 or index >= 7:
                painter.drawRect(rect)
                painter.rotate(-90)
                painter.setFont(self._font)
                painter.drawText(
                    QtCore.QPointF(- rect.height(), rect.left() + (rect.width() + self._descent) / 2), data)
            else:
                super().paintSection(painter, rect, index)
    
        def sizeHint(self):
            return QtCore.QSize(0, self._get_text_width() + 2)
        #
        def _get_text_width(self):
            return max([self._metrics.boundingRect(self._get_data(i)).width() for i in range(0, self.model().columnCount())])
    
        def _get_data(self, index):
            return self.model().headerData(index, self.orientation())
    
    
        class WindowBakeryTablesEdit(QtWidgets.QMainWindow):
            def __init__(self):
                super().__init__()
                self.centralwidget = QtWidgets.QWidget(WindowBakeryTables)
                self.centralwidget.setObjectName("centralwidget")
                self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
                self.verticalLayout.setObjectName("verticalLayout")
                self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
                self.tableWidget.setObjectName("tableWidget")
                self.verticalLayout.addWidget(self.tableWidget)
                self.tableWidget.setRowCount(7) # Для примера
                self.tableWidget.setColumnCount(11) # Для примера
                self.verticalLayout.addWidget(self.tableWidget)
                self.columnLables = ['', '', 'Кф. товара', 'Выкладка', 'Код блюда', 'Блюдо', 'Категория блюда', 'Беговая', 'Вольск', 'Горького', 'Гранд'] # Далее еще очень много заголовков.
                self.headerView = MyHeaderView()
                self.tableWidget.setHorizontalHeader(self.headerView)
                self.tableWidget.setHorizontalHeaderLabels(self.columnLables)
                self.font = QtGui.QFont("Times", 10, QFont.Weight.Bold)
                self.tableWidget.horizontalHeader().setFont(self.font)
    
        if __name__ == "__main__":
            import sys
            app = QtWidgets.QApplication(sys.argv)
            WindowBakeryTables = QtWidgets.QMainWindow()
            WindowBakeryTables.show()
            sys.exit(app.exec())

И вроде бы все хорошо. Нужные мне заголовки развернулись.

введите сюда описание изображения


Но появилась другая проблема. Изменилось оформление этих заголовков, а очень хочется что бы все было в едином стиле. Как на первом скрине.

Если есть знающие люди, подскажите как можно исправить?
Сразу прошу прощения, если код может оказаться неполный. Сам UI делал в программе и подключал отдельно. Но постарался перенести все необходимое для минимального примера.

Если раскоментировать эту часть:

# self.setStyleSheet("QHeaderView {background-color: #ffffff;}") 

то получается вот такой результат:

введите сюда описание изображения

Лучше, но я так и не смог поправить границы ячеек. Мучаю этот вопрос уже 3 день, очень хотелось найти решение самому, но силы мои слабеют))

Ответы

▲ 0

Для стилизации можно использовать любой виджет, например:

def paintSection(self, painter, rect, index):
        # Если надо рамочку, то рисовать тут же
        data = self._get_data(index)

        # Виджет-мул
        edit = QLineEdit()

## или, например, с QLabel
##        edit = QLabel()
##        edit.setFrameShadow(QFrame.Shadow.Raised)
##        edit.setFrameShape(QFrame.Shape.WinPanel)

        edit.setText(data)
        # Где-то тут можно изменить шрифт текста, css и тому подобный стаф
        # edit.setStyleSheet("background-color: orange") # ммм, апельсиновый

        # Размер виджета-мула соответствует размеру ячейки с 
        # переставленными высотой и шириной
        edit.setGeometry(rect.left(), rect.top(), rect.height(), rect.width())
 
        # pixmap нужен, чтобы на него отобразить виджет, 
        # а затем нарисовать его на холсте QPainter
        pixmap = QPixmap(edit.size())
        # Рендерим (отображаем) виджет на pixmap
        edit.render(pixmap ) 

        # Не самый шустрый способ поворота, но в 98,5% случаев норм
        t = QTransform() # трансформатор
        t.translate(rect.center().x(), rect.center().y()) # смещаемся в центр
        t.rotate(-90) # Задаем вращение
        pixmap = pixmap.transformed(t) # Трансформируем

        # Рисуем повернутую картинку на холсте ячейки
        painter.drawPixmap(rect.topLeft(), pixmap)
▲ 0

Как вариант:

'''
from PyQt6 import QtWidgets, QtGui, QtCore
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import *
from PyQt6.QtWidgets import QTableWidgetItem
'''
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.Qt import *


class MyHeaderView(QHeaderView):
    def __init__(self, parent=None):
        super().__init__(QtCore.Qt.Orientation.Horizontal, parent)
        
        self._font = QtGui.QFont("Times", 10, QFont.Weight.Bold)
        self._metrics = QtGui.QFontMetrics(self._font)
        self._descent = self._metrics.descent()
       
    def paintSection(self, painter, rect, index):
        data = self._get_data(index)
        painter.setPen(QPen(Qt.blue, 2, Qt.SolidLine))
        painter.drawRect(rect.x(), rect.y(), rect.width()+.1, rect.height()+1.2)  
      
        if index == 2 or index == 3 or index >= 7:
            painter.rotate(-90)
            painter.setFont(self._font)
            painter.drawText(
                QtCore.QPointF(
                    - rect.height()+15, 
                    rect.left() + (rect.width() + self._descent) / 2
                ), 
                data
            )
        else:
            super().paintSection(painter, rect, index)

    def sizeHint(self):
        return QtCore.QSize(0, self._get_text_width() + 2)

    def _get_text_width(self):
        return max([self._metrics.boundingRect(self._get_data(i)).width() \
            for i in range(0, self.model().columnCount())])

    def _get_data(self, index):
        return self.model().headerData(index, self.orientation())


class WindowBakeryTablesEdit(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.centralwidget = QtWidgets.QWidget()           
        self.centralwidget.setObjectName("centralwidget")  
        self.setCentralWidget(self.centralwidget)
        
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setObjectName("tableWidget")
        self.verticalLayout.addWidget(self.tableWidget)
        self.tableWidget.setRowCount(7)               
        self.tableWidget.setColumnCount(11)           
        
        self.columnLables = ['', '', 'Кф. товара', 'Выкладка', 
            'Код блюда', 'Блюдо', 'Категория блюда', 'Беговая', 
            'Вольск', 'Горького', 'Гранд']    

        self.headerView = MyHeaderView()
        self.tableWidget.setHorizontalHeader(self.headerView)
        self.tableWidget.setHorizontalHeaderLabels(self.columnLables)
        self.font = QtGui.QFont("Times", 10, QFont.Weight.Bold)
        self.tableWidget.horizontalHeader().setFont(self.font)
        self.tableWidget.horizontalHeader().setStyleSheet('''
            QHeaderView {
                border: none;
                border-bottom: 2px solid blue;
                border-top: 2px solid blue;
                color: #00f;
            }
            QHeaderView::section:horizontal {
                border: none;
                border-right: 2px solid blue;
                border-left: 1px solid blue;
                min-height: 48px;
            }
        ''')


if __name__ == '__main__':
    import sys
    
    app = QtWidgets.QApplication(sys.argv)
    
    app.setStyle(QStyleFactory.create("Fusion"))
    
    w = WindowBakeryTablesEdit()
    w.resize(1160, 400)
    w.show()
    sys.exit(app.exec())

введите сюда описание изображения