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

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

本文介绍了多次加载pyqt应用导致分段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a file, Foo.py which holds the code below. When I run the file from command line using, python Foo.py everything works. However, if I use CLI of python

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

第一个调用工作正常,第二个调用带来所有地狱警告,第一个是

The first call works fine, the second brings forward all hell of warnings, the first of which is

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

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

And the last cause a segmentation fault. What's the problem with my code?

#!/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 中重现.

I'm able to reproduce in Python 3 but not Python 2.

它是关于垃圾收集和多个 QApplications 的.Qt 不希望在同一个进程中使用多个 QApplications,并且无论看起来您是否每次都创建一个新的,旧的都存在于解释器的某个地方.在您的 main() 方法的第一次运行时,您需要创建一个 QApplication 并通过将其存储在诸如全局模块或属性之类的地方来防止它被垃圾收集main() 返回时不会被垃圾回收的全局作用域中的类或实例.

It's something about garbage collection and multiple QApplications. Qt doesn't expect multiple QApplications to be used in the same process, and regardless of whether it looks like you're creating a new one every time, the old one is living on somewhere in the interpreter. On the first run of your main() method, You need to create a QApplication and prevent it from being garbage collected by storing it somewhere like a module global or an attribute to a class or instance in the global scope that won't be garbage collected when main() returns.

然后,在后续运行中,您应该访问现有的 QApplication 而不是创建一个新的.如果您有多个可能需要 QApplication 的模块,但您不希望它们必须协调,则可以使用 QApplication.instance() 访问现有实例,并且如果不存在,则仅实例化一个.

Then, on subsequent runs, you should access the existing QApplication instead of making a new one. If you have multiple modules that might need a QApplication but you don't want them to have to coordinate, you can access an existing instance with QApplication.instance(), and then only instantiate one if none exists.

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

So, changing your main() method to the following works:

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 中发生的事情.所以理想情况下,上面不需要 global app 行,但它是为了防止这种垃圾收集业务.

It's odd you have to keep a reference to ensure the QApplication is not garbage collected. Since there is only supposed to be one per process, I would have expected it to live forever even if you don't hold onto a reference to it. That's what seems to happen in Python 2. So ideally the global app line would not be needed above, but it's there to prevent this garbage collection business.

对于这个 QApplication 对象是多么不朽,我们有点犹豫不决......它的寿命太长了,你不能每次都使用一个新的,但不是很长——足以让您在每次运行时重复使用它,而不必通过保留引用来阻止其垃圾收集.这可能是 PyQt 中的 bug,它可能应该为我们做参考.

We're kind of stuck in the middle about how immortal this QApplication object is ... it's too long lived for you to be able to use a new one each time, but not long-lived enough on its own for you to re-use it each run without having to prevent its garbage collection by holding onto a reference. This might be bug in PyQt, which probably ought to do the reference holding for us.

这篇关于多次加载pyqt应用导致分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 14:19