10

I have this sample of code:

import sys
from PyQt4.QtGui import (QApplication, QHBoxLayout, QVBoxLayout, QDialog,
                                          QFrame, QPushButton, QComboBox)

class Form(QDialog):
    def __init__(self, parent=None):
        super(Form, self).__init__(parent)

        moreButton = QPushButton('moreButton')
        moreButton.setCheckable(True)
        resizeButton = QPushButton('Resize')
        combo = QComboBox()
        combo.addItems(['item1', 'item2'])

        layout1 = QHBoxLayout()
        layout1.addWidget(moreButton)
        layout1.addWidget(resizeButton)

        layout2 = QHBoxLayout()
        layout2.addWidget(combo)
        self.frame = QFrame()
        self.frame.setLayout(layout2)
        self.frame.hide()

        layout3 = QVBoxLayout()
        layout3.addLayout(layout1)
        layout3.addWidget(self.frame)

        moreButton.toggled.connect(self.frame.setVisible)
        moreButton.clicked.connect(self.method)
        resizeButton.clicked.connect(self.method)

        self.setLayout(layout3)
        self.resize(630, 50)

    def method(self):
        if self.frame.isVisible():           
            self.resize(630, 150)
        else:
            self.resize(630, 250)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

I run it and when moreButton clicked the ComboBox appears or disappears. Dialog's size also changes. But if I change the method to:

def method(self):
    if self.frame.isVisible():           
        self.resize(630, 150)
    else:
        self.resize(630, 50)

(in order to set the initial size when combo is hidden) the resizing does not work. However, if I click resizeButton -which is connected to the same method- the resizing works properly.

I know that there are other ways to achieve such a result (eg. layout.setSizeConstraint(QLayout.SetFixedSize)), but I want to declare size explicitly.

What am I doing wrong?

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
ilstam
  • 1,473
  • 4
  • 18
  • 32

4 Answers4

8

My guess is that you are trying to resize the QDialog before it has time to re-adjust its size after you hide stuff. So at the time resize is called it has a minimumSize that makes sure the buttons and the combobox visible. When you call it after some time, it now has proper miminumSize and responds properly.

A quick fix is manually overriding minimumSize before resizing:

def method(self):
    if self.frame.isVisible():
        # uncomment below, if you like symmetry :)
        # self.setMinimumSize(630, 150)
        self.resize(630, 150)
    else:
        self.setMinimumSize(630, 50)
        self.resize(630, 50)

But, if I were to tackle this, I'd just leave managing resizing to the layout and use sizeConstraint. That's what these layouts for anyways.

Avaris
  • 35,883
  • 7
  • 81
  • 72
  • yes, this might be the reason. it works properly with this change. it also works with "layout3.setSizeConstraint(QLayout.SetNoConstraint)" as mentioned above. Is the latter a "better" solution? – ilstam Dec 22 '11 at 21:05
  • finally I noticed that in more complicated situations (therefore more complicated ui) only that answer works fine. Thank you very much! – ilstam Dec 22 '11 at 21:23
3

This question and the answers were helpful in my situation: Automatic sizing of a QDialog with QLayout/QVBoxLayout containing a QLabel of variable size content/message to the user while also avoiding the double arrow cursor at the border of the overall QDialog container. The sizePolicy of the dialog itself was set to Fixed and yet the arrows would appear even though it cannot be resized (wouldn't budge). And even though the inner layout does automatically/magically resize, using SetFixedSize on the layout (surprise, surprise) made those annoying double arrows of the overall QDialog go away.

QDialog: QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
QLayout: setSizeConstraint(QLayout.SetFixedSize)
QLabel:  QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

...and now the dialog sizes itself appropriately to the volume contained in the label yet the dialog itself is not (seemingly) user-resizable, which is good for info and error messages.

Seemed counterintuitive to me so I thought worth adding here for others.
A bit more detail...

self.label = QtGui.QLabel(self)
self.label.sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
self.label.setSizePolicy(self.label.sizePolicy)
self.label.setMinimumSize(QtCore.QSize(450, 40))
self.label.setWordWrap(True)

self.verticalLayout = QtGui.QVBoxLayout(self)
# get rid of overall dialog resize arrows
self.verticalLayout.setSizeConstraint(QtGui.QLayout.SetFixedSize)  # no resize arrows
self.verticalLayout.addWidget(self.label)
gseattle
  • 986
  • 1
  • 14
  • 23
2

This problem appears to be caused by the order in which events are processed.

Here's a simple fix:

def method(self):
    app.processEvents()
    if self.frame.isVisible():           
        self.resize(630, 150)
    else:
        self.resize(630, 50)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
1

did you try this ? unless i misunderstand, this is what you wanna do.

def method(self):
    if self.frame.isVisible():   
        self.resize(630, 150)
        self.frame.setVisible(False)
    else:
        self.resize(630, 50)

edit : the final answer is layout3.setSizeConstraint(QLayout.SetNoConstraint)

NotCamelCase
  • 1,073
  • 1
  • 10
  • 18
  • I have managed to set the frame visible or invisible. "moreButton.toggled.connect(self.frame.setVisible)" is responsible for this. The problem is that when i set the the frame invisible I can't bring dialog back to its initial size and there is some empty space. – ilstam Dec 22 '11 at 19:47
  • oh sorry then, I can't now think of a different solution from layout3.setSizeConstraint(QLayout.SetNoConstraint) – NotCamelCase Dec 22 '11 at 20:40
  • then i'm updating my answer so that one might later needs it. – NotCamelCase Dec 22 '11 at 21:01