qtpysideqtexteditqvboxlayout

QTextEdit expand until fully visible


I have a QDialog(QVBoxLayout) with the following widgets in order: QTextEdit, QLabel, [layout stretch], QPushButton

The problem is that I would like the QTextEdit to expand with the QDialog, but only until the scrollbar disappears, after which the layout stretch should start expanding, revealing a gap between the QLabel and the QPushButton.

What would be a sensible way to go about this?
Note: The QDialog is resizable and the QTextEdit has word wrapping on.

Edit: For Qt4/PySide, the following should work

class TextEdit(qt.QTextEdit):
    def __init__(self, *args, **kwargs):
        qt.QTextEdit.__init__(self, *args, **kwargs)
        self.document().modificationChanged.connect(self.updateMaxHeight)

    def updateMaxHeight(self, *args):
        self.setMaximumHeight(self.document().size().height())

    def resizeEvent(self, e):
        qt.QTextEdit.resizeEvent(self, e)
        self.updateMaxHeight()

class MyDialog(qt.QDialog):
    def __init__(self, *args, **kwargs):
        qt.QDialog.__init__(self, *args, **kwargs)
        self.setLayout(qt.QVBoxLayout())
        self.textEdit = TextEdit('Example text')
        self.layout().addWidget(self.textEdit, 1) #1 for resizable
        self.layout().addWidget(qt.QLabel('Example label')
        self.layout().addStretch()
        self.layout().addWidget(qt.QPushButton('Example button')

Solution

  • This is more difficult than it seems:

    class TextEdit : public QTextEdit
    {
    public:
      TextEdit(QWidget *parent = nullptr)
        : QTextEdit(parent)
      {
        setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
        connect(this, &TextEdit::textChanged, this, &TextEdit::updateGeometry);
      }
    
      QSize viewportSizeHint() const override
      {
        return document()->size().toSize();
      }
    };
    

    The idea is to make the viewport size hint correspond to the size of the document and make the scroll area adjust to the size of the viewport. You also have to make sure the the layout gets notified when new lines are added to the document.

    The final piece of the puzzle is to give your stretch item a bigger stretch factor so that it doesn't start sharing space with the editor:

    layout->addStretch(1);