多次加载pyqt应用程序会导致分段错误

我有一个文件Foo.py,其中包含下面的代码.当我从命令行使用python Foo.py运行文件时,一切正常.但是,如果我使用python的CLI

python 
import Foo
Foo.main()
Foo.main()
Foo.main()

第一个调用正常,第二个提出所有警告,第一个是

(python:5389): Gtk-CRITICAL **: IA__gtk_container_add: assertion 'GTK_IS_CONTAINER (container)' failed

最后导致分割错误.我的代码有什么问题?

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import os
from PyQt4 import Qt
from PyQt4 import QtGui,QtCore

class Foo (QtGui.QWidget):

    def __init__(self,parent=None):
        super(Foo,self).__init__()
        self.setUI()
        self.showMaximized()


    def setUI(self):
        self.setGeometry(100,100,1150,650)
        self.grid = QtGui.QGridLayout()
        self.setLayout(self.grid)

        #For convininece, I set different ui "concepts" in their own function
        self.setInterfaceLine()
        self.setMainText()



    def setMainText(self):
        #the main box, where information is displayed
        self.main_label = QtGui.QLabel('Details')
        self.main_text = QtGui.QLabel()
        self.main_text.setAlignment(QtCore.Qt.AlignTop)
        #Reading the welcome message from file

        self.main_text.setText('')


        self.main_text.setWordWrap(True) #To handle long sentenses
        self.grid.addWidget(self.main_text,1,1,25,8)


    def setInterfaceLine(self):

        #Create the interface section
        self.msg_label = QtGui.QLabel('Now Reading:',self)
        self.msg_line = QtGui.QLabel('commands',self) #the user message label
        self.input_line = QtGui.QLineEdit('',self) #The command line
        self.input_line.returnPressed.connect(self.executeCommand)
        self.grid.addWidget(self.input_line,26,1,1,10)
        self.grid.addWidget(self.msg_label,25,1,1,1)
        self.grid.addWidget(self.msg_line,25,2,1,7)


    def executeCommand(self):
        fullcommand = self.input_line.text() #Get the command
        args = fullcommand.split(' ')
        if fullcommand =='exit':
            self.exit()





    def exit(self):
        #Exit the program, for now, no confirmation
        QtGui.QApplication.quit()



def main():
    app = QtGui.QApplication(sys.argv)
    foo = Foo(sys.argv)
    app.exit(app.exec_())

if __name__ in ['__main__']:
    main()

解决方法:

我可以在Python 3中复制,但不能在Python 2中复制.

这与垃圾回收和多个QApplications有关. Qt并不希望在同一过程中使用多个QApplications,并且不管看起来每次都在创建一个新的QApplication,旧的API都位于解释器中的某个位置.在main()方法的第一次运行中,您需要创建一个QApplication并通过将其存储在模块全局或全局范围内的类或实例的属性(例如不会成为垃圾的属性)的某个位置来防止其被垃圾回收.在main()返回时收集.

然后,在随后的运行中,您应该访问现有的QApplication,而不是制作一个新的QApplication.如果您有多个可能需要QApplication的模块,但又不想让它们协调,则可以使用QApplication.instance()访问现有实例,然后在没有实例的情况下仅实例化一个实例.

因此,将main()方法更改为以下工作:

def main():
    global app
    app = QtGui.QApplication.instance()
    if app is None:
        app = QtGui.QApplication(sys.argv)
    foo = Foo(sys.argv)
    app.exit(app.exec_())

奇怪的是,您必须保留一个引用以确保QApplication不被垃圾回收.由于每个进程应该只有一个,因此即使您不保留对它的引用,我也希望它能够永久存在.这就是Python 2中似乎发生的情况.因此,理想情况下,上面不需要全局应用程序行,但是它可以防止垃圾回收业务.

我们对这个QApplication对象的永续性感到困惑不解…它的寿命太长了,您无法每次使用一个新的对象,但它的寿命不够长,您无法重新使用它.每次运行都使用它,而不必通过保持引用来防止其垃圾回收.这可能是PyQt中的错误,它可能应该为我们提供参考.

上一篇:agc002E - Candy Piles(博弈论)


下一篇:python-QtGui.QTextEdit设置线条颜色基于行包含的文本