在 spyder 中从一个提示符运行 pyqt 应用程序两次

Posted

技术标签:

【中文标题】在 spyder 中从一个提示符运行 pyqt 应用程序两次【英文标题】:Running a pyqt application twice from one prompt in spyder 【发布时间】:2013-10-18 21:26:37 【问题描述】:

我在spyder 中运行pyqt4 应用程序,然后以QtGui.QMainWindow.close() 退出,它返回到spyder python interpreter 提示符。但是,如果我再次尝试运行该应用程序runfile('C:/Python33/~/qtapp.py', wdir=r'C:/Python33/~/Appdir') 窗口不会显示。我必须关闭 python 解释器窗口并打开一个新窗口,然后才能再次运行我的 pyqt4 应用程序。这表明我是。

    未正确关闭应用程序 应用程序运行不正确

我希望能够在同一提示下运行 pyqt4 应用程序,这将加快我的开发时间

示例代码如下:

from PyQt4 import QtCore, QtGui, Qwt5
import sys

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s
try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(200, 200)
        self.checkBox = QtGui.QCheckBox(MainWindow)
        self.checkBox.setGeometry(QtCore.QRect(100, 100, 70, 17))
        self.checkBox.setObjectName("checkBox")


        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "Dialog",None, QtGui.QApplication.UnicodeUTF8))
        self.checkBox.setText(QtGui.QApplication.translate("MainWindow", "CheckBox", None, QtGui.QApplication.UnicodeUTF8))



class MainWindow(QtGui.QMainWindow,Ui_MainWindow):

    def __init__(self):
        super(MainWindow, self).__init__()     
        self.setupUi(self)


app = QtGui.QApplication(sys.argv)
form = MainWindow()
form.show()
app.exec_()

在窗口出现后运行它,再次运行后窗口不显示, 这是我的版本信息:

Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (Intel)] on win32 输入“help”、“copyright”、“credits”或“license”了解更多信息。

导入 NumPy 1.7.1、SciPy 0.12.0、Matplotlib 1.3.0 + guidata 1.6.1、guiqwt 2.3.1 输入“科学”了解更多详情。

【问题讨论】:

(Spyder dev here) 你能发布一个我可以测试的最小示例吗? 再看上面的帖子... Python Kernel crashes after closing an PyQt4 Gui Application的可能重复 【参考方案1】:

要在 Spyder 中再次运行 PyQt 应用程序,必须删除/销毁正在运行的应用程序,但我们不能使用 sys.exit() 因为它会尝试关闭 Python。一种适用于我的解决方案(Python 3.4.1、Spyder 2.3.5.2、PyQt 4.10.4)是使用QtCore.QCoreApplication.instance().quit()deleteLater,如下例所示:

import sys
from PyQt4 import QtGui, QtCore

class Window(QtGui.QMainWindow):
    """PyQt app that closes successfully in Spyder.
    """
    def __init__(self):
        super().__init__()
        self.setGeometry(200, 100, 400, 300)
        self.button()

    def button(self):
        btn = QtGui.QPushButton('Quit', self)
        btn.setGeometry(150, 125, 100, 50)
        btn.clicked.connect(self.quitApp)

    def quitApp(self):
        QtCore.QCoreApplication.instance().quit()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    app.aboutToQuit.connect(app.deleteLater)
    win = Window()
    win.show()
    app.exec_()

【讨论】:

【参考方案2】:

我遇到过同样的问题,但从未真正找到真正的解决方法。但是,我找到了一种解决方法,可以为我解决问题,也适用于 Eelco van Vliet 回答中的示例代码。

问题似乎是 Python 解释器中存储了一个全局 QApplication,它在程序调用之间没有被破坏。我没有在执行开始时实例化一个新的 QApplication,而是检查它是否存在,如果存在,我使用现有的而不是创建一个新的:

if __name__=="__main__":
    if QCoreApplication.instance() != None:
        app = QCoreApplication.instance()
    else:
        app = QApplication(sys.argv)
    form = Form()
    form.show()
    app.exec_()

【讨论】:

【参考方案3】:

这实际上似乎是 IPython 内核及其与 PyQt 交互的问题。基本上,IPython 似乎挂在 Qt 实例上,需要在重新实例化之前清除它。这可以通过将保存 Qt 实例的变量重新绑定到其他东西来非常简单地完成:

app = 0
app = QtGui.QApplication([])
...
sys.exit(app.exec_())

这是从here 派生的,而here 是从here 派生的(并且得到了更充分的解释)。

【讨论】:

【参考方案4】:

我遇到了同样的问题。下面的简单示例重现了该问题(使用 python 3.4)

当您第一次运行它时,关闭窗口并第二次运行失败。您可以在 spyder 中使用重置内核,但这会减慢开发时间。

对我有用的是输入

%重置

在当前内核的命令行上。这将重置变量 QtCriticalMsg、QtSystemMsg 等。之后您可以重新运行代码。

虽然这比重新启动内核要快一些,但还是很烦人。显然,关闭窗口后 Qt 变量不会从内存中清除。有人建议如何在退出后从程序中强制清理内存?这可能会避免每次都输入 reset 并解决问题

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Form(QDialog):

    def __init__(self, parent=None):
        super(Form, self).__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok|
                                     QDialogButtonBox.Cancel)
        grid = QGridLayout()
        grid.addWidget(buttonBox, 4, 0, 1, 2)
        self.setLayout(grid)

        self.connect(buttonBox, SIGNAL("accepted()"),
                     self, SLOT("accept()"))
        self.connect(buttonBox, SIGNAL("rejected()"),
                     self, SLOT("reject()"))
        self.setWindowTitle("Set Number Format (Modal)")


if __name__=="__main__":
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    app.exec_()

【讨论】:

以上是关于在 spyder 中从一个提示符运行 pyqt 应用程序两次的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Miniconda 没有运行最新版本的 Spyder?

如何重启spyder

Spyder启动报错:ModuleNotFoundError: No module named ‘PyQt5.QtWebKitWidgets‘ 解决方法

以管理员身份运行时如何打开第二个 spyder 控制台?

pip 安装特定版本的 PyQt5

Spyder IDE 中的 iPython 控制台挂起任何代码执行