开发者

How do I shut down PyQt's QtApplication correctly?

I don't know the first thing about Qt, but I'm trying to be cheeky and borrow code from elsewhere (http://lateral.netmanagers.com.ar/weblog/posts/BB901.html#disqus_thread). ;)

I have a problem. When I run test() the first time, everything works swimmingly. However, when I run it the second time, I get nasty segfaults. I suspect that the problem is that I'm not ending the qt stuff correctly. What should I change about this program to make it work multiple times? Thanks in advance!

from PyQt4 import QtCore, QtGui, QtWebKit
import logging

logging.basicConfig(level=logging.DEBUG)

class Capturer(object):
    """A class to capture webpages as images"""

    def __init__(self, url, filename, app):
        self.url = url
        self.app = app
        self.filename = filename
        self.saw_initial_layout = False
        self.saw_document_complete = False

    def loadFinishedSlot(self):
        self.saw_document_complete = True
        if self.saw_initial_layout and self.saw_document_complete:
            self.doCapture()

    def initialLayoutSlot(self):
        self.saw_initial_layout = True
        if self.saw_initial_layout and self.saw_document_complete:
            self.doCapture()

    def capture(self):
        """Captures url as an image to the file specified"""
        self.wb = QtWebKit.QWebPage()
        self.wb.mainFrame().setScrollBarPolicy(
            QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
        self.wb.mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
        self.wb.loadFinished.connect(self.loadFinishedSlot)
        self.wb.mainFrame().initialLayoutCompleted.connect(
            self.initialLayoutSlot)
        logging.debug("Load %s", self.url)
        self.wb.mainFrame().load(QtCore.QUrl(self.url))

    def doCapture(self):
        logging.debug("Beginning capture")
        self.wb.setViewportSize(self.wb.mainFrame().contentsSize())
        img = QtGui.QImage(self.wb.viewportSize(), QtGui.QImage.Format_ARGB32)
        painter = QtGui.QPainter(img)
        self.wb.mainFrame().render(painter)
        painter.end()
        img.save(self.filename)
        self.app.quit()

def test():
    """Run a simple capture"""
    app = QtGui.QApplication([])
    c = Capturer("http://www.google.com", "google.png", app)
    c.capture()
    logging.debug("About to run exec_")
    app.exec_()

DEBUG:root:Load http://www.google.com
QObject::connect: Cannot c开发者_开发问答onnect (null)::configurationAdded(QNetworkConfiguration) to QNetworkConfigurationManager::configurationAdded(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationRemoved(QNetworkConfiguration) to QNetworkConfigurationManager::configurationRemoved(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationUpdateComplete() to QNetworkConfigurationManager::updateCompleted()
QObject::connect: Cannot connect (null)::onlineStateChanged(bool) to QNetworkConfigurationManager::onlineStateChanged(bool)
QObject::connect: Cannot connect (null)::configurationChanged(QNetworkConfiguration) to QNetworkConfigurationManager::configurationChanged(QNetworkConfiguration)

Process Python segmentation fault (this last line is comes from emacs)


You need to handle the QApplication outside of the test functions, sort of like a singleton (it's actually appropriate here).

What you can do is to check if QtCore.qApp is something (or if QApplication.instance() returns None or something else) and only then create your qApp, otherwise, use the global one.

It will not be destroyed after your test() function since PyQt stores the app somewhere.

If you want to be sure it's handled correctly, just setup a lazily initialized singleton for it.


A QApplication should only be initialized once! It can be used by as many Capture instances as you like, but you should start them in the mainloop. See: https://doc.qt.io/qt-4.8/qapplication.html

You could also try "del app" after "app.exec_", but I am unsure about the results. (Your original code runs fine on my system)

I would use urllib instead of webkit:

import urllib

class Capturer:
    def capture(self, s_url, s_filename):
        s_file_out, httpmessage = urllib.urlretrieve(s_url, s_filename, self.report)

    def report(self, i_count, i_chunk, i_size):
        print('retrived %5d of %5d bytes' % (i_count * i_chunk, i_size))

def test():
    c = Capturer()
    c.capture("http://www.google.com/google.png", "google1.png")
    c.capture("http://www.google.com/google.png", "google2.png")

if __name__ == '__main__':
    test()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜