Tobias Leupold Tobias Leupold - 1 month ago 20
Python Question

PyQt5 port: how do I hide a window and let it appear at the same position

I'm porting a PyQt4 program to PyQt5. One part of it is hiding the window, taking a screenshot of the area behind the window and showing the window again, which worked just fine with PyQt4.

With my PyQt5 port, everything works fine, but the window appears on the position where it was when the program was started, and not at the position where it was before calling the hide() method.

I'm testing this on a Linux box. The relevant code strips down to:

import sys
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget,
QGridLayout, QPushButton)

class demo(QMainWindow):

def __init__(self):
super().__init__()

mainWidget = QWidget(self)
layout = QGridLayout(mainWidget)
self.setCentralWidget(mainWidget)

self.testButton = QPushButton(self)
self.testButton.setText('Test')
self.testButton.clicked.connect(self.hideMe)
layout.addWidget(self.testButton, 0, 0)

def hideMe(self):
self.hide()
QTimer.singleShot(300, self.showMe)

def showMe(self):
self.show()
self.move(self.pos())

app = QApplication(sys.argv)
mainWindow = demo()
mainWindow.show()
sys.exit(app.exec_())


In showMe(), self.pos() actually contains the right coordinates, but the window isn't moved there (but to it's "original" position it had right after starting).

When I e. g. do a self.move(10, 10) instead, the window is actually moved there. But as soon as I use a variable (I also tried to save the x and y of self.pos in a variable and to use this instead) the window is shown at the position it had after starting.

Why does a move() call with integers actually move the window, but a move() call with variables doesn't? How do I move the window to the position it had before hiding?

Thanks for all help!

Edit (perhaps to find out what's the difference):

The very same code using PyQt4 works:

import sys

from PyQt4.QtCore import QTimer
from PyQt4.QtGui import (QApplication, QMainWindow, QWidget,
QGridLayout, QPushButton)

class demo(QMainWindow):

def __init__(self):
super().__init__()

mainWidget = QWidget(self)
layout = QGridLayout(mainWidget)
self.setCentralWidget(mainWidget)

self.testButton = QPushButton(self)
self.testButton.setText('Test')
self.testButton.clicked.connect(self.hideMe)
layout.addWidget(self.testButton, 0, 0)

def hideMe(self):
self.hide()
QTimer.singleShot(300, self.showMe)

def showMe(self):
self.show()
self.move(self.pos())

app = QApplication(sys.argv)
mainWindow = demo()
mainWindow.show()
sys.exit(app.exec_())


so why behaves Qt5 different to Qt4 in this case?

Answer

It seems that in Qt5 the geometry won't be re-set if it is exactly the same - but I don't know why this behaviour has changed, or whether it is a bug. And note that it is not just the position that is affected - resizing is also ignored.

Here is a hack to work around the problem:

from PyQt5.QtCore import QMargins

class demo(QMainWindow):
    ...

    def hideMe(self):
        print('hide:', self.geometry())
        self.hide()
        QTimer.singleShot(300, self.showMe)

    def showMe(self):
        print('show1:', self.geometry())
        hack = QMargins(0, 0, 0, 1)
        self.setGeometry(self.geometry() + hack)
        self.show()
        self.setGeometry(self.geometry() - hack)
        print('show2:', self.geometry())