Как установить отступ данных расширяемых строк в QTreeView, PyQt5

Вопрос или проблема

Это небольшой пример моего TableWidget:

from PyQt5.QtGui import QStandardItem, QStandardItemModel, QIcon

from PyQt5.QtWidgets import QVBoxLayout, QWidget, QStyledItemDelegate, QStyle, QTreeView, QApplication, \
    QStyleOptionViewItem
from PyQt5.QtCore import Qt, QSize

leftArrow = "path\to\left-arrow.png"
downArrow = "path\to\down-arrow.png"


class GroupDelegate(QStyledItemDelegate):
    def __init__(self, pic1=None, pic2=None, parent=None):
        super().__init__(parent)
        self._pic1 = QIcon(pic1)
        self._pic2 = QIcon(pic2)

    def initStyleOption(self, option, index):
        option.state &= ~QStyle.State_Selected
        super().initStyleOption(option, index)
        if index.column() == index.model().columnCount() - 1 and not index.parent().isValid():
            is_open = bool(option.state & QStyle.State_Open)
            option.features |= QStyleOptionViewItem.HasDecoration
            icon = self._pic2 if is_open else self._pic1
            option.icon = icon
            option.decorationSize = option.rect.size()

    def sizeHint(self, option, index):
        padding = 20

        if index.data(Qt.UserRole + 1):
            lines = index.data().count('\n') + 1
            font_metrics = option.fontMetrics
            line_height = font_metrics.lineSpacing()
            return QSize(option.rect.width(), line_height * lines + padding)
        return QSize(option.rect.width(), option.fontMetrics.height() + padding)


class GroupView(QTreeView):
    def __init__(self, model, parent=None):
        super().__init__(parent)
        self.setIndentation(0)
        self.clicked.connect(self.on_clicked)
        self.setItemDelegate(GroupDelegate(pic1=leftArrow, pic2=downArrow, parent=self))
        self.setModel(model)

    def on_clicked(self, index):
        if not index.parent().isValid():
            parent_index = self.model().index(index.row(), 0)
            self.setExpanded(parent_index, not self.isExpanded(parent_index))


class GroupModel(QStandardItemModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        headers = ["Столбец 1", "Столбец 2", "Столбец 3", ""]
        self.setColumnCount(len(headers))
        for i, header in enumerate(headers):
            self.setHeaderData(i, Qt.Horizontal, header)

    def add_group(self, row_data, additional_info):
        parent_items = [QStandardItem(col_data) for col_data in row_data]
        for item in parent_items:
            item.setEditable(False)
        self.appendRow(parent_items)

        additional_info_item = QStandardItem(additional_info)
        additional_info_item.setData(True, Qt.UserRole + 1)
        additional_info_item.setEditable(False)

        parent_items[0].appendRow([additional_info_item] + [QStandardItem("")] * (self.columnCount() - 1))
        return parent_items[0].index()


class TableWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QVBoxLayout(self)
        model = GroupModel(self)
        tree_view = GroupView(model)
        layout.addWidget(tree_view)

        # Добавить пример данных
        model.add_group(["Родительская строка 1", "Данные 1", "Данные 2"], "Дополнительная информация для строки 1")
        model.add_group(["Родительская строка 2", "Данные 3", "Данные 4"], "Дополнительная информация для строки 2")

        # Расширить строку дополнительной информации на все столбцы
        for row in range(model.rowCount()):
            parent_index = model.index(row, 0)
            additional_row = model.itemFromIndex(parent_index).rowCount() - 1
            tree_view.setFirstColumnSpanned(additional_row, parent_index, True)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = TableWidget()
    window.show()
    window.resize(600, 400)
    sys.exit(app.exec_())

Я хочу сделать отступ для данных в раскрывной строке. Когда я ставлю self.setIndentation(0) на что-то выше 0, это создает отступ, но я также вижу стрелку слева, чего я не хочу. Как видно из кода, я поместил значки в последний столбец, чтобы разместить стрелки справа, так что нет необходимости в оригинальной стрелке QTreeView.

Мой виджет основан на этом решении:
Как сделать таблицу, которая может сворачивать свои строки в категории в Qt?

Кроме того, я хочу сделать текст, который я помещаю в раскрывную строку, с более темным фоном и закругленными краями, чтобы он выглядел лучше.

Я пытался поместить в него метку, но это только привело к тому, что текст больше не был виден, возможно, я сделал это неправильно.

Надеюсь, есть адекватное решение моей проблемы.

Резюме:
Я хочу сделать отступ для текста в раскрывной строке (без видимой оригинальной стрелки QTreeView) и сделать фон светло-серым с закругленными краями.

Ответ или решение

Чтобы решить задачу с выравниванием текста в расширяемых строках QTreeView, а также для улучшения визуального представления с закругленными краями и фоновым цветом, необходимо внести изменения в ваш код, следуя нескольким ключевым шагам.

1. Индентация текста без отображения стандартной стрелки

Чтобы избежать отображения стандартной стрелки QTreeView при использовании индентации, вам нужно установить значение setIndentation выше нуля. Тем не менее, для скрытия стандартной стрелки, используйте метод setUniformRowHeights(True) в классе GroupView и переопределите стиль представления элементов с помощью пользовательского делегата.

class GroupView(QTreeView):
    def __init__(self, model, parent=None):
        super().__init__(parent)
        self.setUniformRowHeights(True)
        self.setIndentation(20)  # Установите нужное значение для индентации
        self.clicked.connect(self.on_clicked)
        self.setItemDelegate(GroupDelegate(pic1=leftArrow, pic2=downArrow, parent=self))
        self.setModel(model)

Установка setUniformRowHeights(True) позволит избежать стилей стрелок, так как они не будут отображены при увеличении индентации. Это позволяет сохранить аккуратное и чистое представление.

2. Настройка цвета фона и закругленных краев

Чтобы создать эффект закругленного угла и задать цвет фона для дополнительной записи, необходимо реализовать таблицу, расширив метод paint делегата. Вам нужно будет указать закругленные углы и цвет фона.

Пример кода для изменения метода paint в вашем делегате:

from PyQt5.QtWidgets import QPainter

class GroupDelegate(QStyledItemDelegate):
    ...
    def paint(self, painter, option, index):
        if index.data(Qt.UserRole + 1):
            # Установите цвет фона
            painter.save()
            painter.setBrush(Qt.lightGray)  # Задайте светло-серый цвет фона
            painter.drawRoundedRect(option.rect, 10, 10)  # Рисуем закругленный прямоугольник
            painter.restore()

        # Далее рисуем текст
        super().paint(painter, option, index)

3. Структура модели для непрерывного отображения

Теперь, когда рендеринг установлен, убедитесь, что вы правильно добавляете строки в вашу модель, чтобы данные не терялись, когда вы добавляете записи с дополнительной информацией. Сохраняйте данные четко и убедитесь, что они легко читаемы.

Заключение

После того как вы внесли все изменения, ваше приложение должно отображать текст в расширяемых строках дерева с правильной индентацией, а также иметь аккуратный светло-серый фон с закругленными углами. Таким образом, пользователи получат более эстетичное и удобное отображение данных.

Эти корректировки не только улучшат визуальную составляющую вашего приложения, но и повысят его функциональность, сделав использование более интуитивно понятным. Обязательно протестируйте каждое изменение, чтобы убедиться, что все работает как задумано.

Оцените материал
Добавить комментарий

Капча загружается...