Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

resizing a dialog with PyQt4

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?

like image 704
ilstam Avatar asked Dec 22 '11 18:12

ilstam


4 Answers

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.

like image 162
Avaris Avatar answered Nov 05 '22 23:11

Avaris


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)
like image 21
gseattle Avatar answered Nov 05 '22 23:11

gseattle


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)
like image 31
ekhumoro Avatar answered Nov 06 '22 01:11

ekhumoro


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)

like image 27
NotCamelCase Avatar answered Nov 06 '22 01:11

NotCamelCase