Вопрос

I run a pyqt4 application in spyder, I exit with QtGui.QMainWindow.close() and it returns me to the spyder python interpreter prompt. However, if I try and run the application again runfile('C:/Python33/~/qtapp.py', wdir=r'C:/Python33/~/Appdir') The window doesn't show. I have to shut the python interpreter window down and open a new one up before I can run my pyqt4 app again. This suggest to me that I am.

  1. Not shutting down the app correctly
  2. Not running the app correctly

I want to be able to run the pyqt4 app from the same prompt, this would speed up my dev time

Here is the example code:

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

After I run it once the window shows up, after I run it again the window doesn't show up, Here's my version info:

Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information.

Imported NumPy 1.7.1, SciPy 0.12.0, Matplotlib 1.3.0 + guidata 1.6.1, guiqwt 2.3.1 Type "scientific" for more details.

Это было полезно?

Решение

To run the PyQt application again in Spyder, the running application must be deleted/destroyed but we can't use sys.exit() because it will try to close Python. One solution that works for me (Python 3.4.1, Spyder 2.3.5.2, PyQt 4.10.4) is to use QtCore.QCoreApplication.instance().quit() and deleteLater as shown in this example:

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

Другие советы

I have experienced the same problem but never really found a true fix. However, I have found a workaround that solves the problem for me, and also works for the sample code in Eelco van Vliet's answer.

The problem seems to be that there is a global QApplication stored in the Python interpreter that is not destroyed between invocations of the program. Instead of instantiating a new QApplication at the start of execution, I check to see if this exists and if it does, I use the existing one rather than creating a new one:

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

This actually appears to a problem with the IPython kernel and its interaction with PyQt. Basically, IPython seems to hang on to the Qt instance and it needs to get cleared before being reinstantiated. This can be done quite simply by rebinding the variable holding the Qt instance to something else:

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

This is derived from here, which is derived from (and more fully explained) here.

I had the same problem. The simple example below reproduces the issue (using python 3.4)

When you run this this the first time it works, closing the window and running the second time fails. You can use the reset kernel in spyder, but this slows down development time.

What works for me is to type

%reset

on the command line of the current kernel. This will reset the variables QtCriticalMsg, QtSystemMsg, etc. After that you can rerun your code.

Although this is slightly faster than restarting the kernel, it is still annoying. Apparently the Qt variables are not cleared from the memory after closing the window. Anybody a suggestion how to force a clean memory from the program after exitting ? This would probably prevent having to type reset each time and solve the issue

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_()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top