pythonpyqt4qtexteditsizingmodel-view

Minimizing the size of a QTextEdit in a QTreeWidgetItem


I have a QTreeWidget filling with some itemwidgets, whose main widget will be a QTextEdit. The problem I'm having seems to be getting the size down to something managable. The usual method of setting the size policy to maximum doesn't seem to work. Here's the example code:

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.tree = QTreeWidget(self)
        self.tree.setColumnCount(1)
        self.setCentralWidget(self.tree)

        textEdit = QTextEdit()
        textEdit.setText("very Small Text Edit")
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
        textEdit.setSizePolicy(sizePolicy)

        itemWidget = QTreeWidgetItem()
        itemWidget.setText(0, "")
        self.tree.addTopLevelItem(itemWidget)
        self.tree.setItemWidget(itemWidget, 0, textEdit)        

        biggerTextEdit = QTextEdit()
        biggerTextEdit.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas et mauris in felis tempus molestie eu sit amet sapien. Proin dapibus pretium ipsum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque feugiat semper sem a accumsan. Nulla sollicitudin enim quis velit blandit posuere. Ut fringilla vulputate dolor, a accumsan lectus gravida a. Sed convallis facilisis mi et ullamcorper. Integer consectetur aliquet odio sit amet posuere.")        

        itemWidget2 = QTreeWidgetItem()
        itemWidget2.setText(0, "")
        self.tree.addTopLevelItem(itemWidget2)
        self.tree.setItemWidget(itemWidget2, 0, biggerTextEdit)        

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    ui = MyMainWindow()
    ui.show()
    sys.exit(app.exec_())

Note that no matter the length of the text doesn't seem to have any effect on the height of the textedits. How does one have a QTextEdit scale itself (vertically, at least) to the smallest possible size, and for the sake of knowledge, why doesn't it behave like many other widgets in this manner? Thanks in advance!

Edit: I should now note that I tried to cheat this effect by using a QLabel (which in regards to resizing, display, and word-warp, works just like i want) and setting the Text Interaction flags to editable. This almost works were there a way to accessing the Label's edited text. Unfortunately any call of .text() on the label yields the original text. A QLineEdit cannot be multi-line or word-wrap, a QTextEdit seems overly complicated.

The question now becomes, what's the best widget for creating a small (300 characters or less) text-displaying widget that can also be editable?


Solution

  • For achieving your goal you have to customise item delegates, because they provide presentation and editing services to your tree widget. The Qt docs have some useful information regarding models, views and delegates (including a tutorial). The following code fixes your problem using delegates:

    from PyQt4.QtGui import *
    from PyQt4.QtCore import *
    
    class MyMainWindow(QMainWindow):
        def __init__(self, parent=None):
            QMainWindow.__init__(self, parent)
    
            self.tree = QTreeWidget(self)
            self.tree.setColumnCount(1)
            self.tree.setItemDelegate(MyDelegate(self))
            self.setCentralWidget(self.tree)
    
            itemWidget = QTreeWidgetItem()
            itemWidget.setFlags(itemWidget.flags() | Qt.ItemIsEditable)
            itemWidget.setText(0, "very Small Text Edit")
            self.tree.addTopLevelItem(itemWidget)
    
            itemWidget2 = QTreeWidgetItem()
            itemWidget2.setFlags(itemWidget.flags() | Qt.ItemIsEditable)
            itemWidget2.setText(0, """very Small Text Edit\n
            very Small Text Edit\n
            very Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Editvery Small Text Edit""")
            self.tree.addTopLevelItem(itemWidget2)
    
    class MyDelegate(QStyledItemDelegate):
    
        def sizeHint(self, option, index):
            default = QStyledItemDelegate.sizeHint(self, option, index)
            return QSize(default.width(), default.height() + 12)
    
        def createEditor(self, parent, option, index):
            editor = QTextEdit(parent)
            return editor
    
        def setEditorData(self, editor, index):
            text = index.model().data(index, Qt.DisplayRole).toString()
            editor.setText(text)
    
        def setModelData(self, editor, model, index):
            model.setData(index, QVariant(editor.toPlainText()))
    
    
    if __name__ == "__main__":
        import sys
        app = QApplication(sys.argv)
        ui = MyMainWindow()
        ui.show()
        sys.exit(app.exec_())
    

    The code contains a naive reimplementation of sizeHint(). Note also that you can customise your QTextEdit in the createEditor method. You may want to reimplement the paint() method too (it depends on your needs).

    Please note that subclassing QTreeWidgetItem is not the way to go (it is not even a QWidget). However QTreeWidget is a convenience class which uses a predefined tree model so it makes sense to solve the problem in the framework of model/view programming.