Skip to main content
 首页 » 编程设计

python之QApplication (PySide) Django 应用退出问题

2025年05月04日23lyhabc

我有一个 Django 应用程序,用户可以在其中的整个 Web 应用程序的不同位置创建报告。作为一个小功能,我想为这些报告制作一个“以 PDF 格式发送”功能,我快完成了。

我所做的是,在报告通过 Django 作为 HttpResponse 返回之前,我通过一个小的 PySide/QT 片段(如下所示)发送原始 HTML 内容。

问题是我无法让 QApplication 退出。

我尝试过使用标准的 QCoreApplication.exit() 但没有成功。如果我尝试在第一个报告之后立即转换一个新报告,控制台会显示“QApplication 实例已存在”。

我在 OS X 10.7.3(用于测试)上使用 Django 1.2.5、Python 2.7、QT 4.8 和 PySide 1.1。

代码:

def makepdf(response,filename): 
    try: 
        app = QApplication(sys.argv) 
    except: 
        app = QCoreApplication.instance() 
    web = QWebView() 
 
    stylelink = "%s%s" % (media_root,'images/css/reportGenerator.css')  
 
    web.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(stylelink)) 
    web.setHtml(response) 
 
    printer = QPrinter() 
    printer.setPageSize(QPrinter.A4) 
    printer.setOutputFormat(QPrinter.PdfFormat) 
    printer.setOutputFileName(filename) 
 
    def convertToPdf(): 
        web.print_(printer) 
        #webresponse = web.close()         
        #QObject.disconnect() 
        #print QCoreApplication.instance().children()[0].interrupt() 
        #qthread = QCoreApplication.instance().thread()#.cleanup() 
        #qthread.exit() 
        QCoreApplication.exit() 
    QObject.connect(web, SIGNAL("loadFinished(bool)"), convertToPdf()) 

代码注释:

目前我已经制作了一个try/except子句来保持代码运行,通过使用当前的QApplication实例(避免“实例存在错误” ), 但这似乎不对?我的意思是,让 QAppliation 在我的 Apache 服务器期间运行(在生产中就是这种情况)似乎有点不对劲。 PDF转换完成后不是可以退出吗?

除了 QCoreApplication.exit() 之外,我还尝试使用 sys.exit(app.exec_()) 方法,这在示例和片段。然而,这只会导致错误并使 Python 崩溃,并且代码可以在没有它的情况下完美运行。 (它会创建 PDF,但不会退出)。

所有被注释掉的行都是我之前尝试退出 QApplication 的尝试。

简而言之:我不知道它是什么,但就是不会退出。谁能告诉我为什么?

更新:在最新答案之后,我编辑了代码以响应输入。这是最后一部分现在的样子:

def convertToPdf(): 
    web.print_(printer) 
    app.exit() 
web.loadFinished.connect(convertToPdf) 
app.exec_() 

但是,我仍然收到错误:

2012-04-30 00:16:10.791 Python[21241:1803] * Assertion failure in +[NSUndoManager _endTopLevelGroupings], /SourceCache/Foundation/Foundation-833.24/Misc.subproj/NSUndoManager.m:324
Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must reimplement QApplication::notify() and catch all exceptions there.

此错误仅在我执行 app.exec_() 时发生。但是,如果没有 app.exec_(),这又是正常问题,没有退出。

有什么想法吗?

更新2:这是最新的代码,根据matas的最新建议修复:

app = QApplication(sys.argv) 
web = QWebView() 
printer = QPrinter() 
printer.setPageSize(QPrinter.A4) 
printer.setOutputFormat(QPrinter.PdfFormat) 
printer.setOutputFileName(filename) 
def convertToPdf(): 
    web.print_(printer) 
    app.exit() 
web.loadFinished.connect(convertToPdf) 
web.setHtml(response) 

我还是遇到了同样的问题。

请您参考如下方法:

我能说的是:

QObject.connect(web, SIGNAL("loadFinished(bool)"), convertToPdf()) 

这里调用convertToPdf(),如果要连接信号,省略括号!

您还可以使用更清晰的语法:

web.loadFinished.connect(convertToPdf) 

您可能还想向 convertToPdf 添加一个参数,因为它使用 bool 值调用,指示加载是否成功。

并且使用 app.exit() 应该就足够了。

哦,当您使用 Gui-Components 时,您需要使用 QApplication。 QCoreApplication 不行!

编辑:在连接loadFinished 信号后调用web.setHtml 很重要!否则如果加载已经完成,你的函数将永远不会被执行!

编辑:这对我来说没有任何问题:

#!/usr/bin/env python 
from PySide.QtGui import * 
from PySide.QtWebKit import * 
import sys 
from subprocess import Popen, PIPE 
 
 
def createPdf(html, filename): 
    app = QApplication(sys.argv) 
    web = QWebView() 
    printer = QPrinter() 
    printer.setPageSize(QPrinter.A4) 
    printer.setOutputFormat(QPrinter.PdfFormat) 
    printer.setOutputFileName(filename) 
    def convertToPdf(): 
        web.print_(printer) 
        app.exit() 
        app.deleteLater() 
    web.loadFinished.connect(convertToPdf) 
    web.setHtml(html) 
    app.processEvents() 
 
def createPdfInSubprocess(html, filename): 
       p = Popen(["python", __file__, filename],  
                stdin=PIPE, stdout=PIPE, stderr=PIPE) 
       out, err = p.communicate(html) 
       return (p.returncode, out, err) 
 
if __name__ == '__main__': 
    if len(sys.argv) > 1: 
        # read html from stdin, filename from cmdline 
        html = "\n".join(sys.stdin.readlines()) 
        createPdf(html, sys.argv[1]) 
        # print("done") 
    else: 
        # test if it's working 
        ret = createPdfInSubprocess( 
                "<html><h1>test</h1>it's working...</html>", "test.pdf") 
        print(ret) 

即使没有对 app.exit()、app.deleteLater()、app.processEvents() 的所有调用,它仍然有用……但拥有它也没什么坏处。

还有一件重要的事情:QApplications 必须从主线程创建!因此,如果它在 Django 应用程序中运行,它可能无法正常工作,这就是我添加子进程内容的原因...