Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python PyQt作为Windows应用程序崩溃崩溃_Python_Pyqt - Fatal编程技术网

Python PyQt作为Windows应用程序崩溃崩溃

Python PyQt作为Windows应用程序崩溃崩溃,python,pyqt,Python,Pyqt,我有一个(注意,这是一个pythonfidle链接——在Firefox中似乎崩溃得很厉害,所以下面也发布了代码),它将输出打印到一个QTextEdit(使用代码)。当我(在Windows上)运行代码时,它会导致应用程序崩溃。一些意见: 如果我添加一个time.sleep调用(即取消对第53行的注释),则程序可以正常完成 如果我没有将输出重定向到QEdit(即注释掉第34行),那么无论time.sleep调用是否注释掉,它都会工作 我假设这意味着重定向标准输出的代码以某种方式被破坏了-但我正在

我有一个(注意,这是一个pythonfidle链接——在Firefox中似乎崩溃得很厉害,所以下面也发布了代码),它将输出打印到一个
QTextEdit
(使用代码)。当我(在Windows上)运行代码时,它会导致应用程序崩溃。一些意见:

  • 如果我添加一个
    time.sleep
    调用(即取消对第53行的注释),则程序可以正常完成
  • 如果我没有将输出重定向到QEdit(即注释掉第34行),那么无论
    time.sleep
    调用是否注释掉,它都会工作
我假设这意味着重定向
标准输出的代码以某种方式被破坏了-但我正在努力理解它的错误是什么导致了这种行为-感激地收到了任何指针


完整错误消息

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


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

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
进行交互。如果从
QObject
所在线程以外的线程调用
print
,则您拥有的实现可能是线程不安全的

在您的情况下,您正在从
QThread
调用
print
,而
EmmittingStream(QObject)
位于主线程中。因此,我建议您更改代码以使其线程安全,如下所示:

self.myLongTask = TaskThread()
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
sys.stdout.moveToThread(self.myLongTask)
self.myLongTask.start()
请注意,现在从应用程序的主线程调用
print
,将导致线程不安全行为。既然你现在没有这样做,你现在还可以,但是要小心

我真的建议你读一下,把它说的每一件事都想清楚。理解该文档是避免因线程而导致恼人的崩溃的关键

--

现在,崩溃问题显然是由调用
processEvents()
引起的。我还没有弄清楚为什么(我想这与线程有关…),但我可以告诉你,你不需要那一行!因为您使用的是信号/插槽,所以一旦
normaloutputWrite
方法运行,控件仍将返回到Qt事件循环,并将继续正常处理事件。因此,没有必要强制Qt处理事件

希望有帮助


编辑:有关如何使
emittengstream
/
print
调用线程安全的示例,请参见此处:

非常感谢您的帮助-我假设这是一个线程安全问题,但不知道从何开始。您最初的建议是有效的,但程序似乎要等到完成后才将输出打印到QTextEdit。。。我会用你的另一个答案重写它(我很感谢你花时间在一个答案上,同时他也有类似的问题!)@ChrisW啊,我最初的建议可能不起作用,因为你需要用
@QtCore.pyqtSlot(str)
来修饰
normaloutputWrited
方法。这可能与下面的链接存在相同的问题,但我没有看到它,因为我没有看到显式调用
connect
(我假设
QObject
中的一些魔法是根据传递给
EmittingStream
)的关键字参数自动连接信号和插槽,坏消息是,添加decorator并没有改变任何事情-我真的很不了解这个项目,但是这个项目太远了,我无法停止!啊,好吧,我已经仔细研究过了。至少在我的系统上,它在结束之前更新了QTextEdit,但它似乎是分块进行的。这是意料之中的,因为您基本上正在从线程向主线程触发许多事件,但是程序没有足够频繁地切换回主线程来处理它们。我觉得这很奇怪!一种解决方案是将线程与主线程同步,这样它只会在QTextEdit更新后继续下一次迭代。这样行吗?这将有助于了解您在线程中最终要做什么嗯,顺便说一下,我不知道如何将从线程同步回主线程,然后转到Google。我的代码是如何组织的,更大的图景是我有一个主GUI包装(
mainWrapper.py
,它继承了
QMainWindow
)、一个
QWidget
(在
myWidget.py
)和一个模块(
myProg.py
),在那里我设置了从
QThread
)。填写表单(设置参数)并按下
QWidget
上的按钮后,将执行
myWidget
中的代码(使用这些参数)。然后我尝试在
QWidget