0

I use the following code to set a PySide6 app to the minimal possible size. This works fine when increasing the size of the widgets (set - to + in line 37), but not when decreasing it - in effect, the size of the windows does decrease, but it seems to be one step late.

I found a few workarounds, most notably in Qt Layout, resize to minimum after widget size changes, but none of what I tried seems to be working (and I have met other issues with app.processEvents(), which should be avoided anyway).

Edit: In the new code example below, I think the problem is the width of the QPushButton, which is calculated too late.

enter image description here

Interestingly, this width of the QPushButton is solved by the layout.setSizeConstraint(QLayout.SetFixedSize) workaround, but the window width is not.

enter image description here

app.processEvents() works for this example, but I see bad side effects on other signals when using it.

enter image description here


New code example:

from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (QApplication, QLabel, QLayout, QMainWindow,
                               QPushButton, QVBoxLayout, QWidget)


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.i = 0

        self.button = QPushButton("push me!")
        self.button.clicked.connect(self.clicked)

        self.label = QLabel()

        layout = QVBoxLayout()
        layout.addWidget(self.button)
        layout.addWidget(self.label)

        # https://stackoverflow.com/a/21458822/880783
        # layout.setSizeConstraint(QLayout.SetFixedSize)  # (ineffective)

        widget = QWidget()
        widget.setLayout(layout)

        self.setCentralWidget(widget)
        self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint)
        self.clicked()
        self.show()

    def clicked(self):
        npix = 500 - 50 * self.i
        self.label.setPixmap(QPixmap(npix, npix))
        # app.processEvents()  # (effective, but discouraged)
        self.adjustSize()
        self.i += 1


app = QApplication()
win = Window()
app.exec()

Original code example:

import threading
import time

from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (
    QApplication,
    QHBoxLayout,
    QLabel,
    QLayout,
    QMainWindow,
    QWidget,
)


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.label = QLabel()

        layout = QHBoxLayout()
        layout.addWidget(self.label)

        # https://stackoverflow.com/a/21458822/880783
        # layout.setSizeConstraint(QLayout.SetFixedSize)  # (ineffective)

        widget = QWidget()
        widget.setLayout(layout)

        self.setCentralWidget(widget)
        self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint)
        self.show()

    def run(self):
        for i in range(10):
            npix = 500 - 50 * i
            self.label.setPixmap(QPixmap(npix, npix))
            # app.processEvents()  # (ineffective)
            self.adjustSize()
            time.sleep(1)


app = QApplication()
threading.Thread(target=Window().run).start()
app.exec()
bers
  • 4,817
  • 2
  • 40
  • 59
  • Don't use `time.sleep()` as it's blocking and prevents the event loop to properly process all events (including layout resize requests). Use QTimer along with a proper function that sets the new size in the iteration every time it's called. You either use a list, keeping track of the index (or popping elements each time the function is called), or use a generator. – musicamante Sep 20 '22 at 16:47
  • @musicamante I am fairly confident I can post a similar code example tomorrow that does not use `time.sleep` at all, like with a button that I press a few times in a row to decrease the size of the pixmap. In that case, do you still think a `QTimer` is the way to go, like looping infinitely in the background, resizing the window every 0.01 seconds or so? – bers Sep 20 '22 at 18:07
  • @musicamante I have posted a new code example showing the issue with out `time.sleep()` – bers Sep 20 '22 at 20:31
  • 3
    Use `QTimer.singleShot(0, self.adjustSize)`. Note that continuously resizing the window is generally discouraged, as it's seen as very annoying for most users. Besides, if your purpose is to "smoothly" resize the window when the image is changed, you should consider QPropertyAnimation with the `size` property of the window; still, you need to wait for the layout to process the new size hint of the main window, so you still have to use QTimer to properly set the `endValue` of the animation and finally start it. – musicamante Sep 20 '22 at 20:55

1 Answers1

1

@musicamante has posted very helpful comments, which I now turn into an answer.

Basically, this code works great:

from PySide6.QtCore import QMetaObject, Qt, QTimer, Slot
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (QApplication, QLabel, QMainWindow, QPushButton,
                               QVBoxLayout, QWidget)


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.i = 0

        self.button = QPushButton("push me!")
        self.button.clicked.connect(self.clicked)

        self.label = QLabel()

        layout = QVBoxLayout()
        layout.addWidget(self.button)
        layout.addWidget(self.label)

        widget = QWidget()
        widget.setLayout(layout)

        self.setCentralWidget(widget)
        self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint)
        self.clicked()
        self.show()

    # @Slot()
    # def adjustSize(self):
    #     super().adjustSize()

    def clicked(self):
        npix = 500 - 50 * self.i
        self.label.setPixmap(QPixmap(npix, npix))
        self.i += 1

        # # As in https://stackoverflow.com/a/23954088/880783 - does not work
        # QMetaObject.invokeMethod(self, "adjustSize")

        # This works!
        QTimer.singleShot(0, self.adjustSize)


app = QApplication()
win = Window()
app.exec()

As one can see, I have also tried the approach put forward https://stackoverflow.com/a/23954088/880783 - without success, however.

bers
  • 4,817
  • 2
  • 40
  • 59