In Windows 10, if I run the following test case GUI application from the command line ('python ./pyqt_freeze_testcase.py'), I see the following completely repeatable GUI freeze/hang/unresponsive behavior; every time the GUI becomes unresponsive, I can 'bring it back to life' by typing any key in the shell.
UPDATE: this seems to be triggered (and cured) by toggling the focus-follows-mouse-without-raising-the-window behavior; now the question becomes how to prevent freezes when focus-follows-mouse-without-raising is enabled. I posted a new question for that topic: PyQt5 GUI freeze caused by Windows focus-follows-mouse
The behavior is the same for the built-in shell ('cmd') and for PowerShell. Detailed script of actions and responses to illustrate the freeze is at the bottom of this post. How can I prevent the freeze / make sure the GUI application stays responsive?
pyqt_freeze_testcase.py:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
# import the UI file created with pyuic5
from minimal_ui import Ui_Dialog
class MyWindow(QDialog,Ui_Dialog):
def __init__(self,parent):
QDialog.__init__(self)
self.parent=parent
self.ui=Ui_Dialog()
self.ui.setupUi(self)
def showMsg(self):
self.really1=QMessageBox(QMessageBox.Warning,"Really?","Really do stuff?",
QMessageBox.Yes|QMessageBox.No,self,Qt.WindowTitleHint|Qt.WindowCloseButtonHint|Qt.Dialog|Qt.MSWindowsFixedSizeDialogHint|Qt.WindowStaysOnTopHint)
self.really1.show()
self.really1.raise_()
if self.really1.exec_()==QMessageBox.No:
print("nope")
return
print("yep")
def main():
app = QApplication(sys.argv)
w = MyWindow(app)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
The GUI is just a dialog with a lineedit and a button (with signal/slot).
Accompanying UI file minimal_ui.py (from Qt Designer and pyuic5):
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'minimal.ui'
#
# Created by: PyQt5 UI code generator 5.8.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 300)
self.lineEdit = QtWidgets.QLineEdit(Dialog)
self.lineEdit.setGeometry(QtCore.QRect(120, 90, 113, 22))
self.lineEdit.setObjectName("lineEdit")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(130, 150, 93, 28))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
self.pushButton.clicked.connect(Dialog.showMsg)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "PushButton"))
The detailed actions and responses, beginning from a new PowerShell:
- python ./pyqt_freeze_testcase.py
- move the GUI window so it is next to (not inside of) the PowerShell; reasoning is apparent below
- left click the lineedit and type some stuff --> said stuff shows up in the lineedit, as expected
- left click the pushbutton --> the 'Really?' QMessageBox appears
- left click anywhere in the PowerShell --> the PowerShell is raised, which would obscure the GUI application, which is the reason for step 2 above
- left click either 'Yes' or 'No' --> the messagebox closes, but, no output is shown in the shell, and, the GUI is unresponsive (it soon gets the spinner / hourglass, the banner says 'Dialog (Not Responding)' and you can't select the lineedit to type more stuff, and clicking the pushbutton does nothing; for all appearances, the GUI is frozen, but:
- left click anywhere in the PowerShell
- press any key --> the expected response (yep or nope) appears in the shell, and the GUI is now responsive again, i.e. you can repeat all of this starting at step 3; also note that any additional typing you may have done during the freeze will now appear in the lineedit