在终端中单击 pyqt5 会导致 GUI 冻结



在Windows 10中,如果我从命令行('python ./pyqt_freeze_testcase.py'(运行以下测试用例GUI应用程序,我会看到以下完全可重复的GUI冻结/挂起/无响应行为;每次GUI变得无响应时,我都可以通过在shell中键入任何键来"使其恢复活力"。

更新:这似乎是通过切换焦点跟随鼠标而不抬起窗口行为来触发(和治愈(的; 现在的问题变成了当启用焦点跟随鼠标而不抬起时如何防止冻结。 我为该主题发布了一个新问题:由Windows焦点跟随鼠标引起的PyQt5 GUI冻结

内置外壳("cmd"(和PowerShell的行为是相同的。 说明冻结的详细行动和响应脚本在这篇文章的底部。 如何防止冻结/确保 GUI 应用程序保持响应?

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()

GUI只是一个带有行编辑和按钮(带有信号/插槽(的对话框。

随附的UI文件minimal_ui.py(来自Qt Designer和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"))

详细的操作和响应,从新的PowerShell开始:

  1. 蟒蛇 ./pyqt_freeze_testcase.py
  2. 移动GUI
  3. 窗口,使其位于PowerShell旁边(而不是内部(;推理在下面很明显
  4. 左键单击行编辑并键入一些内容 -->所说的东西出现在行编辑中,正如预期的那样
  5. 左键单击按钮 -->"真的吗?QMessageBox 出现
  6. 左键单击PowerShell中的任意位置 --> PowerShell 被抬起,这会掩盖 GUI 应用程序,这就是上面步骤 2 的原因
  7. 左键单击"是"或"否" -->消息框关闭,但是,shell中没有显示任何输出,并且GUI无响应(它很快就会得到微调器/沙漏,横幅上写着"对话框(无响应(",您无法选择行编辑来键入更多内容,单击按钮没有任何作用;对于所有外观,GUI都被冻结,但是:
  8. 左键单击PowerShell中的任意位置
  9. 按任意键 --> 预期的响应(是或否(出现在 shell 中,并且 GUI 现在再次响应,即您可以从步骤 3 开始重复所有这些操作;另请注意,您在冻结期间可能完成的任何其他输入现在将显示在行编辑中

作为评论,这可能更好,但我没有这样做的声誉点,一些反馈可能对你来说总比没有好。

我用python3和python2.7测试了您在Windows 10机器上所做的工作,我无法复制您在问题中概述的情况。一切都按预期工作,"否"和"是"消息立即出现。你可以尝试这样的事情:PySide/Python GUI冻结,但打印语句不应该冻结你的GUI并且不在控制台中打印。您绝对应该检查其他一些像您这样的简单 GUI,看看哪些冻结,哪些不会冻结。不过我会先重新启动您的计算机。如果这不能得到任何答案,也许可以尝试重新安装 PyQt5。

暴力解决方案适用于上面链接的问题(由Windows焦点跟随鼠标引起的PyQt5 GUI冻结(;完整的代码发布在那里。

希望有人可以提供更优化或更"正确"的解决方案?

基本上,在 MainWindow init 中禁用活动窗口跟踪,并在 MainWindow closeEvent 中恢复到其初始设置。 也许有一个更优化的解决方案,但是,这个解决方案简短而可靠。 来自 https://joelpurra.com/projects/X-Mouse_Controls/的方法立即生效,而注册表黑客在重新启动之前不会生效。

最新更新