7

What is the best way to resize the main window automatically if one widget is hidden? I also need to resize the window if I make the widget visible again. See the images below...

What settings should I set in Qt Designer for MainWindow (sizePolicy), centralwidget (sizePolicy, layoutSizeConstraint) and gridLayout (sizePolicy, layoutSizeConstraint) in particular?

How can I hide the textEdit widget? self.textEditObject.setVisible(False) works: textEditObject is not visible, but is this the right way to resize the window?

I think I don't understand some basic stuff, as I cannot get the desired behaviour.

enter image description here

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
Igor
  • 358
  • 3
  • 6
  • 14
  • possible duplicate of [Resizing qt widgets when their children are hidden](http://stackoverflow.com/questions/2469186/resizing-qt-widgets-when-their-children-are-hidden) – NoDataDumpNoContribution Jan 29 '15 at 09:06

3 Answers3

7

Even simpler than a manual resize is QWidget.adjustSize().

Here is an example:

from PySide import QtGui

def hide_show():
    x.setVisible(not x.isVisible()) # toggles visibility of the label
    w.adjustSize() # adjusts size of widget

app = QtGui.QApplication([])

w = QtGui.QWidget()
l = QtGui.QVBoxLayout(w)
b = QtGui.QPushButton('Click me')
l.addWidget(b)
x = QtGui.QLabel('Some Text')
l.addWidget(x)
b.clicked.connect(hide_show)
w.show()

app.exec_()

If you have a QMainWidget I actually only managed to shrink it somewhat but not completely. Maybe than other solutions are better.

from PySide import QtGui

def hide_show():
    x.setVisible(not x.isVisible()) # toggles visibility of the label
    w2.adjustSize() # adjusts size of widget
    w.adjustSize() # adjusts size of main window

app = QtGui.QApplication([])

w = QtGui.QMainWindow()
w2 = QtGui.QWidget()
l = QtGui.QVBoxLayout(w2)
b = QtGui.QPushButton('Click me')
l.addWidget(b)
x = QtGui.QTextEdit('Some Text')
l.addWidget(x)
b.clicked.connect(hide_show)
w.setCentralWidget(w2)
w.show()

app.exec_()
NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
  • 1
    It works, thank you! I would like also to resize the window by making the textEditObject visible: but `self.adjustSize()` does not work in this case. Have you any ideas how can I make it working? – Igor Jan 29 '15 at 17:59
  • @Igor I cannot follow what you mean. My example works for getting visible as well as getting invisible and for any kind of widget (label, textedit, ...). It doesn't matter. Can you specify more what you mean? – NoDataDumpNoContribution Jan 29 '15 at 18:36
  • Your example does not work, if I want to enlarge the main window (QMainWindow). I don't know why. Can you follow me? May be it is important: I have a vertical layout (QVBoxLayout) in the central widget in my MainWindow. – Igor Jan 29 '15 at 18:54
  • I mean, `self.adjustSize()` does not work. If I use `self.resize(...)` - it works. – Igor Jan 29 '15 at 19:07
  • @Igor I see. Yeah my solution does not work with QMainWindow. Sorry. – NoDataDumpNoContribution Jan 29 '15 at 21:23
  • The example works now with QMainWindow. But I found it breaks with deeper nested layouts. Tried to go down all my 3 levels but it refused to adjust properly. – ewerybody Jun 19 '15 at 10:37
  • confirm `adjustSize()` not with qwidget either (no mainwindow) – droid192 Sep 19 '19 at 10:03
  • self.adjustSize() works for me, but you need a tasty QtWidgets.QApplication.processEvents() before it. – Adam Sirrelle Feb 19 '21 at 08:34
6

You can resize the window to minimumSizeHint() after hiding the widget:

self.resize(minimumSizeHint())

This will shrink the window to minimum size.

If you want to only shrink in height, then you can do something like:

self.resize(width(), minimumSizeHint().height())

But you should consider that the minimum size is not computed until some events are processed in the event loop. So when you hide your widget, just process the event loop for some iterations and then resize to minimum.

It's like :

for i in range(0, 10):
      QApplication.processEvents()

self.resize(width(), minimumSizeHint().height())

Another option is to single shot a QTimer which calls a slot in which you resize the window to minimum. This way when you resize the window, the minimum size hint is computed correctly.

Nejat
  • 31,784
  • 12
  • 106
  • 138
  • Thank you, it works, if i hide the widget but not vice versa. I use `self.resize(self.width(), self.minimumSizeHint().height())` for hidding the widget and `self.resize(self.width(), self.maximumHeight())` if i make it visible again. But i don't want to use the `maximumHeight()`. How can i do it with something like your method? Notice: `self.adjustSize()` does not work in my code (see my comment to the mail from Trilarion). – Igor Jan 29 '15 at 19:23
  • You can use the same approach when you make the widget visible. Just use `minimumSizeHint` again and the widget is made visible and the minimum size is computed accordingly. – Nejat Jan 29 '15 at 19:41
  • @Najat The same approach does not work in my code to enlarge the window size. I don't know why. I have the same problem with `self.adjustSize()`. – Igor Jan 29 '15 at 21:14
  • Do you call `QApplication.processEvents()` after making the widget visible? – Nejat Jan 30 '15 at 10:36
  • Yes, i call `QApplication.processEvents()` but it does not work. For minimization it works with and without `QApplication.processEvents()`. – Igor Jan 30 '15 at 10:51
  • Nice Nejat! Unfortunately I'm not always able to get the app. Or am I? I mean when using this as a library module.. So could you give an example of what you mean whith the QTimer? Thanks! – ewerybody Jun 17 '15 at 21:27
0

OK. Here is some code to test the QTimer approach as Nejat suggested and based on Trilarions example. Althought I don't know if it is what Nejat meant it works best so far for me.

from PySide import QtCore, QtGui


class TestWin(QtGui.QMainWindow):
    def __init__(self):
        super(TestWin, self).__init__()
        self.w2 = QtGui.QWidget()
        self.l = QtGui.QVBoxLayout(self.w2)

        self.h = QtGui.QHBoxLayout(self.w2)
        self.b = QtGui.QPushButton('hierarchic adjustSize()')
        self.b2 = QtGui.QPushButton('deferred resize()')
        self.h.addWidget(self.b)
        self.h.addWidget(self.b2)
        self.l.addLayout(self.h)

        self.x = QtGui.QTextEdit('Some Text')
        self.l.addWidget(self.x)
        self.b.clicked.connect(self.adjustSize_hide_show)
        self.b2.clicked.connect(self.qtimer_hide_show)
        self.setCentralWidget(self.w2)

    def toggleVis(self):
        self.x.setVisible(not self.x.isVisible())

    def adjustSize_hide_show(self):
        self.toggleVis()
        self.w2.adjustSize() # adjusts size of widget
        self.adjustSize() # adjusts size of main window

    def qtimer_hide_show(self):
        self.toggleVis()
        _timer = QtCore.QTimer()
        _timer.singleShot(30, self._resizeHeight)

    def _resizeHeight(self):
        self.resize(self.width(), self.minimumSizeHint().height())


if __name__ == '__main__':
    app = QtGui.QApplication([])
    win = TestWin()
    win.show()
    app.exec_()

This way you don't need acces to the app and you can actually resize in a specific direction.

I'm not so comfortable with relying on a delay here. But it still works like 90% of the time with a 1ms delay! As long as I tried 2ms was 100% success. So 20ms will surely suceed in almost all cases inducing a very small flicker tho (probably depending on your layout too)

ewerybody
  • 1,443
  • 16
  • 29