Данные в виде таблицы, но не QTableWidget

Необходимо что-то похожее на такую структуру:

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

Особенности:

  1. Текст в первой ячейке с левого края и по центру, в остальных - по центру.
  2. При изменении размеров таблицы изменяется длина и высота ячеек.
  3. Высота ячейки подгоняется под её содержимое, как в ответе на мой предыдущий вопрос Динамическое изменение размера QTextEdit

Сразу же отбросил мысль о использовании QTableWidget, т.к. ячейки статичны. Решил использовать измененный QPlainTextEdit из предыдущего вопроса + QGridLayout, но столкнулся с проблемой - из-за разного количества данных в ячейках, высоты у них тоже разные:

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

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

from PyQt5 import QtCore, QtGui, QtWidgets

class PlainTextEdit(QtWidgets.QPlainTextEdit):

    def __init__(self, parent=None):
        super(PlainTextEdit, self).__init__(parent)

    def text_to_center(self):
        self.updateRequest.connect(lambda: self.handle_updateRequest(self))

    def handle_updateRequest(self, a):

        doc = a.document()
        tb = doc.findBlockByNumber(doc.blockCount() - 1)
        h = a.blockBoundingGeometry(tb).bottom() + 2 * doc.documentMargin()
        a.setFixedHeight(h)


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")

        self.centralwidget = QtWidgets.QWidget(MainWindow)

        self.grid = QtWidgets.QGridLayout(self.centralwidget)

        self.centralwidget.setStyleSheet("QFrame{background-color: rgb(255, 255, 255);}")

        self.frame1 = QtWidgets.QFrame()
        self.frame1.setFrameShape(QtWidgets.QFrame.Box)
        self.frame1.setMaximumHeight(65)
        self.vlay1 = QtWidgets.QVBoxLayout(self.frame1)
        self.textEdit1 = PlainTextEdit(self.frame1)
        self.textEdit1.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.textEdit1.setPlainText('GoGOGO GoGOGO GoGOGO')
        self.textEdit1.text_to_center()
        self.vlay1.addWidget(self.textEdit1)
        self.grid.addWidget(self.frame1, 0, 0, 1, 1)

        self.frame2 = QtWidgets.QFrame()
        self.frame2.setFrameShape(QtWidgets.QFrame.Box)
        self.frame2.setMaximumHeight(65)
        self.vlay2 = QtWidgets.QVBoxLayout(self.frame2)
        self.textEdit2 = PlainTextEdit(self.frame2)
        self.textEdit2.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.textEdit2.setPlainText('GoGOGO GoGOGO')
        self.textEdit2.text_to_center()
        self.vlay2.addWidget(self.textEdit2)
        self.grid.addWidget(self.frame2, 0, 1, 1, 1)


        self.frame3 = QtWidgets.QFrame()
        self.frame3.setFrameShape(QtWidgets.QFrame.Box)
        self.frame3.setMaximumHeight(65)
        self.vlay3 = QtWidgets.QVBoxLayout(self.frame3)
        self.textEdit3 = PlainTextEdit(self.frame3)
        self.textEdit3.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.textEdit3.setPlainText('GoGOGO')
        self.textEdit3.text_to_center()
        self.vlay3.addWidget(self.textEdit3)
        self.grid.addWidget(self.frame3, 0, 2, 1, 1)


        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))




class Window(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__()
        self.setupUi(self)




if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

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

И результат-то меня устраивает. Ячейки ведут себя так, как надо, но... Костыль же + в 2 раза больше объектов.

Вопросы:

  1. Можно ли всё таки изменить QTableWidget так, чтобы появилось необходимое поведение?
  2. Есть ли более элегантное решение на основе QPlainTextEdit?

Ответы (1 шт):

Автор решения: gil9red

А если так:

from PyQt5.QtWidgets import QApplication, QTableWidget, QTableWidgetItem, QHeaderView
from PyQt5.QtCore import Qt


class MainWindow(QTableWidget):
    def __init__(self):
        super().__init__()

        items = [
            ['Поле 1:\n' * 3, '123\n' * 2, 'abc ' * 10],
            ['Поле 2:\n' * 3, '456\n' * 2, 'def ' * 10],
        ]

        self.setRowCount(len(items))
        self.setColumnCount(len(items[0]))

        for col in range(self.columnCount()):
            self.horizontalHeader().setSectionResizeMode(col, QHeaderView.Stretch)

        for row in range(self.rowCount()):
            item = QTableWidgetItem(items[row][0])
            self.setItem(row, 0, item)

            item = QTableWidgetItem(items[row][1])
            item.setTextAlignment(Qt.AlignCenter)
            self.setItem(row, 1, item)

            item = QTableWidgetItem(items[row][2])
            item.setTextAlignment(Qt.AlignCenter)
            self.setItem(row, 2, item)

        self.resizeRowsToContents()


if __name__ == '__main__':
    app = QApplication([])

    mw = MainWindow()
    mw.show()

    app.exec()

Скриншот:

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

→ Ссылка