PyQt 作为 Windows APPCRASH 崩溃 [英] PyQt crashing out as a Windows APPCRASH

查看:54
本文介绍了PyQt 作为 Windows APPCRASH 崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 非常短的 PyQt 程序(nb 这是一个 PythonFiddle 链接 - 这似乎在 Firefox 中严重崩溃,因此代码也在下面发布)将输出打印到 QTextEdit(使用代码 从此SO答案).当我运行代码(在 Windows 上)时,它会产生一个 APPCRASH.一些观察:

I have a very short PyQt program (n.b. that is a PythonFiddle link - this seems to crash horribly in Firefox, so code is also posted below) which prints output to a QTextEdit (using code from this SO answer). When I run the code (on Windows), it results in an APPCRASH. Some observations:

  • 如果我添加一个 time.sleep 调用(即取消注释第 53 行),则程序完成正常
  • 如果我不将输出重定向到 QEdit(即注释掉第 34 行),那么无论 time.sleep 调用是否被注释掉,它都可以工作
  • if I add a time.sleep call (i.e. uncomment out line 53), then the program completes fine
  • if I don’t redirect the output to the QEdit (i.e. comment out line 34) then it works regardless of whether the time.sleep call is commented out or not

我认为这意味着重定向 stdout 的代码以某种方式被破坏了 - 但我正在努力理解它有什么问题导致这种行为 - 感谢收到任何指针!

I assume that this implies that the code redirecting the stdout is broken somehow - but I'm struggling to understand what's wrong with it to result in this behaviour - any pointers gratefully received!

完整的错误信息

问题签名:
问题事件名称:APPCRASH
应用程序名称:pythonw.exe
应用程序版本:0.0.0.0
应用时间戳:5193f3be
故障模块名称:QtGui4.dll
故障模块版本:4.8.5.0
故障模块时间戳:52133a81
异常代码:c00000fd
异常偏移量:00000000005cbdb7
操作系统版本:6.1.7601.2.1.0.256.48
区域设置 ID:2057
附加信息 1:5c9c
附加信息 2:5c9c27bb85eb40149b414993f172d16f
附加信息 3:bc7e
附加信息 4:bc7e721eaea1ec56417325adaec101aa

Problem signature:
Problem Event Name: APPCRASH
Application Name: pythonw.exe
Application Version: 0.0.0.0
Application Timestamp: 5193f3be
Fault Module Name: QtGui4.dll
Fault Module Version: 4.8.5.0
Fault Module Timestamp: 52133a81
Exception Code: c00000fd
Exception Offset: 00000000005cbdb7
OS Version: 6.1.7601.2.1.0.256.48
Locale ID: 2057
Additional Information 1: 5c9c
Additional Information 2: 5c9c27bb85eb40149b414993f172d16f
Additional Information 3: bc7e
Additional Information 4: bc7e721eaea1ec56417325adaec101aa

Pythonfiddle 在 Firefox 上崩溃得很厉害(至少对我来说),所以下面的代码也是:

Pythonfiddle crashes horribly on Firefox (for me at least), so code below too:

import os, sys, time, calendar, math
from PyQt4 import QtCore, QtGui

class EmittingStream(QtCore.QObject): 
  textWritten = QtCore.pyqtSignal(str)

  def write(self, text): self.textWritten.emit(str(text))

class myWrapper(QtGui.QMainWindow):

  def __init__(self):
    super(myWrapper, self).__init__()
    self.toolbar = self.addToolBar("MainMenu")
    self.toolbar.addAction(QtGui.QAction("myProg", self, triggered=self.myProgActions))

  def myProgActions(self): self.setCentralWidget(myWidget())

class myWidget(QtGui.QWidget):

  def __init__(self):
    super(myWidget, self).__init__()

    self.myBtn = QtGui.QPushButton('Run!', self)
    self.myBtn.clicked.connect(self.startTest)
    self.outputViewer = QtGui.QTextEdit()

    self.grid = QtGui.QGridLayout()
    self.grid.addWidget(self.myBtn)
    self.grid.addWidget(self.outputViewer)
    self.setLayout(self.grid)

  def startTest(self):
    self.myLongTask = TaskThread()
    sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
    self.myLongTask.start()

  def normalOutputWritten(self, text):
    cursor = self.outputViewer.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.outputViewer.setTextCursor(cursor)
    self.outputViewer.ensureCursorVisible()
    QtGui.qApp.processEvents()

class TaskThread(QtCore.QThread):
  def __init__(self): super(TaskThread, self).__init__()
  def run(self): myProgClass()

class myProgClass:
  def __init__(self):
    for i in range(0,100):
      print "thread", i+1, " ", math.sqrt(i)
      #time.sleep(0.005)

if __name__ == '__main__':
  app = QtGui.QApplication(sys.argv)
  myApp = myWrapper()
  myApp.show()
  sys.exit(app.exec_())

推荐答案

好的,首先要考虑程序的线程安全性.因为您将 QObject 连接到 stdout,所以对 print 的调用将与此 QObject 交互.但是您应该只与创建它的线程中的 QObject 交互.如果您从 print 调用 print,那么您拥有的实现可能是线程不安全QObject 所在线程以外的线程.

Ok, one thing first about the thread safety of your program. Because you are connecting a QObject to stdout, calls to print will interact with this QObject. But you should only interact with a QObject from the thread it was created in. The implementation you have is potentially thread unsafe if you call print from a thread other than the one the QObject resides in.

在您的情况下,您从 QThread 调用 printEmmittingStream(QObject) 驻留在主线程中.我建议您更改代码以使其成为线程安全的,如下所示:

In your case, you are calling print from a QThread while the EmmittingStream(QObject) resides in the main thread. I suggest you thus change your code to make it threadsafe, like so:

self.myLongTask = TaskThread()
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
sys.stdout.moveToThread(self.myLongTask)
self.myLongTask.start()

请注意,现在从应用程序的 MainThread 调用 print 将导致线程不安全行为.由于您目前没有这样做,因此您现在可以,但要注意!

Note that now calling print from the MainThread of your application will result in thread-unsafe behaviour. Since you aren't doing that at the moment, you are OK for now, but be warned!

我真的建议你阅读 http://qt-project.org/doc/qt-4.8/threads-qobject.html 并了解它所谈论的一切.了解该文档是避免因线程引起的恼人崩溃的关键.

I really suggest you read http://qt-project.org/doc/qt-4.8/threads-qobject.html and get your head around everything it talks about. Understanding that document is the key to avoiding annoying crashes due to threads.

--

现在,崩溃问题显然是由您调用 processEvents() 引起的.我还没有弄清楚为什么(我想它以某种方式与线程有关......),但我可以告诉你,你不需要那条线!因为您正在使用信号/槽,一旦 normalOutputWritten 方法运行,控制权无论如何都会返回到 Qt 事件循环,它将继续照常处理事件.因此无需强制 Qt 处理事件!

Now, The issue with the crash is apparently caused by your call to processEvents(). I haven't worked out why (I imagine it is related to threads somehow...), but I can tell you that you do not need that line! Because you are using signals/slots, once the normalOutputWritten method runs, control returns to the Qt Event Loop anyway, and it will continue to process events as normal. There is thus no need to force Qt to process events!

希望有帮助!

有关如何使 EmittingStream/print 调用线程安全的示例,请参见此处:将 stdout 和 stderr 重定向到 PyQt4 QTextEdit from一个辅助线程

For an example of how to make your EmittingStream/print calls thread-safe, see here: Redirecting stdout and stderr to a PyQt4 QTextEdit from a secondary thread

这篇关于PyQt 作为 Windows APPCRASH 崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆