Pyqt QTablewidget wordwrap lines - PullRequest
       15

Pyqt QTablewidget wordwrap lines

0 голосов
/ 13 декабря 2018

Как я могу установить ширину столбца QTableWidget и сделать так, чтобы текст в каждой ячейке начинался с новой строки, если ее ширина больше, чем заданная ширина (вроде как в Excel, для текста разрешено иметь / быть завернутым в слово)).Прямо сейчас мой дырочный текст на ячейку написан одной действительно длинной строкой, но мне бы хотелось, чтобы в destopapplication было приятно посмотреть / прочитать его.Поэтому я хотел бы сохранить текст в одной ячейке, но иметь перенос слов / сделать так, чтобы в тексте были новые строки.

Вот мой код, который содержит команду self.table.setWordWrap(True), которая ничего не будет делать.Пожалуйста, обратите внимание, что весь qtablewidget был перезаписан для раскраски текста (я думаю, что это может быть проблемой, почему WordWrap может не работать):

from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport
import sys

found_words_num =int ('100')
data_single = {'Position':['hallo i like to do this and it would be nice if there was a new line. othere lines and so one.','b'], 'LV-Text': ['c','d'], 'Fundwörter': ['e','f'], 'Hersteller': ['g','h']}
words_in_columns = ['a','b']

textMargins = 12
borderMargins = 10


class HighlightDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HighlightDelegate, self).__init__(parent)
        self.doc = QtGui.QTextDocument(self)
        self._filters = []

    def paint(self, painter, option, index):
        painter.save()
        options = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        self.doc.setPlainText(options.text)
        self.apply_highlight()
        options.text = ""
        style = QtWidgets.QApplication.style() if options.widget is None \
            else options.widget.style()
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)

        ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
        if option.state & QtWidgets.QStyle.State_Selected:
            ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
        else:
            ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                QtGui.QPalette.Active, QtGui.QPalette.Text))

        textRect = style.subElementRect(
            QtWidgets.QStyle.SE_ItemViewItemText, options)

        if index.column() != 0:
            textRect.adjust(5, 0, 0, 0)

        the_constant = 4
        margin = (option.rect.height() - options.fontMetrics.height()) // 2
        margin = margin - the_constant
        textRect.setTop(textRect.top() + margin)

        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        self.doc.documentLayout().draw(painter, ctx)

        painter.restore()

    def apply_highlight(self):
        cursor = QtGui.QTextCursor(self.doc)
        cursor.beginEditBlock()
        fmt = QtGui.QTextCharFormat()
        fmt.setForeground(QtCore.Qt.red)
        for f in self.filters():
            highlightCursor = QtGui.QTextCursor(self.doc)
            while not highlightCursor.isNull() and not highlightCursor.atEnd():
                highlightCursor = self.doc.find(f, highlightCursor)
                if not highlightCursor.isNull():
                    highlightCursor.mergeCharFormat(fmt)
        cursor.endEditBlock()

    @QtCore.pyqtSlot(list)
    def setFilters(self, filters):
        if self._filters == filters: return
        self._filters = filters

    def filters(self):
        return self._filters


class main_result_pos(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(main_result_pos, self).__init__(parent)

        self.setGeometry(50, 50, 1100, 850)  # Fenstergröße festlegen

        self.table = QTableWidget(self)
        self.table.setGeometry(QtCore.QRect(10, 10, 900, 600))
        self.table.setRowCount(found_words_num)
        self.table.setColumnCount(6)
        self.table.setSortingEnabled(True)
        self.table.setWordWrap(True)

        self._delegate = HighlightDelegate(self.table)  ##Klasse aufrufen
        self.table.setItemDelegate(self._delegate)
        le = QtWidgets.QLineEdit()
        le.textChanged.connect(self.on_textChanged)

        search_list = [word for column in words_in_columns for word in column]
        list_c_str = ' '.join(search_list)
        le.setText(list_c_str)

        horHeaders = []
        for col, key in enumerate(sorted(data_single.keys())):
            horHeaders.append(key)
            for row, item in enumerate(data_single[key]):
                newitem = QTableWidgetItem(item)
                newitem.setTextAlignment(QtCore.Qt.AlignCenter)
                self.table.setItem(row, col, newitem)

        self.table.setHorizontalHeaderLabels(['A', 'B','C', 'D' , 'E', 'F'])

        self.table.resizeRowsToContents()
        self.table.resizeColumnsToContents()

    @QtCore.pyqtSlot(str)
    def on_textChanged(self, text):
        self._delegate.setFilters(list(set(text.split())))
        self.table.viewport().update()


def main():
    app = QApplication(sys.argv)
    ex = main_result_pos()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

1 Ответ

0 голосов
/ 14 декабря 2018

Вы должны включить перенос слов в QTextDocument в дополнение к установке sectionResizeMode вертикального заголовка в QHeaderView :: ResizeToContents:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class HighlightDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HighlightDelegate, self).__init__(parent)
        self._filters = []
        self._wordwrap = False
        self.doc = QtGui.QTextDocument(self)

    def paint(self, painter, option, index):
        painter.save()
        options = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        self.doc.setPlainText(options.text)
        self.apply_highlight()

        if self._wordwrap:
            self.doc.setTextWidth(options.rect.width())
        options.text = ""

        style = QApplication.style() if options.widget is None else options.widget.style()
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)

        if self._wordwrap:
            painter.translate(options.rect.left(), options.rect.top())
            clip = QtCore.QRectF(QtCore.QPointF(), QtCore.QSizeF(options.rect.size()))
            self.doc.drawContents(painter, clip)
        else:
            ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
            if option.state & QtWidgets.QStyle.State_Selected:
                ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                    QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
            else:
                ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                    QtGui.QPalette.Active, QtGui.QPalette.Text))
            textRect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options, None)
            if index.column() != 0:
                textRect.adjust(5, 0, 0, 0)
            constant = 4
            margin = (option.rect.height() - options.fontMetrics.height()) // 2
            margin = margin - constant
            textRect.setTop(textRect.top() + margin)
            painter.translate(textRect.topLeft())
            painter.setClipRect(textRect.translated(-textRect.topLeft()))
            self.doc.documentLayout().draw(painter, ctx)

        painter.restore()
        s = QtCore.QSize(self.doc.idealWidth(), self.doc.size().height())
        index.model().setData(index, s, QtCore.Qt.SizeHintRole)

    def apply_highlight(self):
        cursor = QtGui.QTextCursor(self.doc)
        cursor.beginEditBlock()
        fmt = QtGui.QTextCharFormat()
        fmt.setForeground(QtCore.Qt.red)
        for f in self.filters():
            highlightCursor = QtGui.QTextCursor(self.doc)
            while not highlightCursor.isNull() and not highlightCursor.atEnd():
                highlightCursor = self.doc.find(f, highlightCursor)
                if not highlightCursor.isNull():
                    highlightCursor.mergeCharFormat(fmt)
        cursor.endEditBlock()

    @QtCore.pyqtSlot(list)
    def setFilters(self, filters):
        if self._filters == filters: return
        self._filters = filters
        self.parent().viewport().update()

    def filters(self):
        return self._filters

    def setWordWrap(self, on):
        self._wordwrap = on
        mode = QtGui.QTextOption.WordWrap if on else QtGui.QTextOption.WrapAtWordBoundaryOrAnywhere

        textOption = QtGui.QTextOption(self.doc.defaultTextOption())
        textOption.setWrapMode(mode)
        self.doc.setDefaultTextOption(textOption)
        self.parent().viewport().update()

data_single = {'Position':['hallo i like to do this and it would be nice if there was a new line. othere lines and so one.','b'], 'LV-Text': ['c','d'], 'Fundwörter': ['e','f'], 'Hersteller': ['g','h']}
words_in_columns = ['a','b']

class main_result_pos(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(main_result_pos, self).__init__(parent)
        self.table = QtWidgets.QTableWidget(100, 6)
        self.table.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
        self.table.setSortingEnabled(True)

        self._delegate = HighlightDelegate(self.table)
        self.table.setItemDelegate(self._delegate)
        le = QtWidgets.QLineEdit(textChanged=self.on_textChanged)

        search_list = [word for column in words_in_columns for word in column]
        list_c_str = ' '.join(search_list)
        le.setText(list_c_str)

        horHeaders = []
        for col, key in enumerate(sorted(data_single.keys())):
            horHeaders.append(key)
            for row, item in enumerate(data_single[key]):
                newitem = QtWidgets.QTableWidgetItem(item)
                self.table.setItem(row, col, newitem)
        self.table.setHorizontalHeaderLabels(horHeaders)

        self._delegate.setWordWrap(True)
        self.resize(640, 480)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(le)
        lay.addWidget(self.table)

    @QtCore.pyqtSlot(str)
    def on_textChanged(self, text):
        self._delegate.setFilters(list(set(text.split())))

def main():
    app = QtWidgets.QApplication(sys.argv)
    ex = main_result_pos()
    ex.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

enter image description here

...