我正在使用PyQt开发GUI,以对某些实验期间收集的数据进行可视化分析。 GUI要求用户指出要分析的数据所在的目录:
class ExperimentAnalyzer(QtGui.QMainWindow):
## other stuff here
def loadExperiment(self):
directory = QtGui.QFileDialog.getExistingDirectory(self,
"Select Directory")
## load data from directory here
GUI提供 播放 功能,用户可以通过该功能查看实验数据随时间的变化情况。这是通过 QTimer :
实现的 def playOrPause(self):
## play
if self.appStatus.timer is None:
self.appStatus.timer = QtCore.QTimer(self)
self.appStatus.timer.connect(self.appStatus.timer,
QtCore.SIGNAL("timeout()"),
self.nextFrame)
self.appStatus.timer.start(40)
## pause
else:
self.appStatus.timer.stop()
self.appStatus.timer = None
如果我 播放 数据的时间顺序,则 暂停 ,然后尝试将目录更改为加载来自新实验的数据,我遇到分段错误。
使用一些调试打印,我发现当我调用
时应用程序崩溃了 QtGui.QFileDialog.getExistingDirectory(self, "Select Directory")
loadExperiment 方法。
我对Qt很新,我认为我没有正确处理计时器 我在Ubuntu 10.04上使用PyQt 4.9,Python 2.7.3。
在卢克的回答之后,我回到了我的代码 这是 nextFrame 方法,每次定时器发出 超时 信号时都会调用此方法。它更新GUI中包含的QGraphicsScene元素:
def nextFrame(self):
image = Image.open("<some jpg>")
w, h = image.size
imageQt = ImageQt.ImageQt(image)
pixMap = QtGui.QPixmap.fromImage(imageQt)
self.scene.clear()
self.scene.addPixmap(pixMap)
self.view.fitInView(QtCore.QRectF(0, 0, w, h),
QtCore.Qt.KeepAspectRatio)
其中self.scene和self.view对象先前已在GUI构造函数中实例化为
self.view = QtGui.QGraphicsView(self)
self.scene = QtGui.QGraphicsScene()
self.view.setScene(self.scene)
我发现评论这一行:
# self.scene.addPixmap(pixMap)
并重复上面报告的相同操作序列,不再发生分段错误。
使用gdb(使用python-dbg)运行应用程序,结果发现在调用QPainter :: drawPixmap之后发生了分段错误。
(gdb) bt
#0 0xb6861f1d in ?? () from /usr/lib/i386-linux-gnu/libQtGui.so.4
#1 0xb685d491 in ?? () from /usr/lib/i386-linux-gnu/libQtGui.so.4
#2 0xb693bcd3 in ?? () from /usr/lib/i386-linux-gnu/libQtGui.so.4
#3 0xb69390bc in ?? () from /usr/lib/i386-linux-gnu/libQtGui.so.4
#4 0xb6945c77 in ?? () from /usr/lib/i386-linux-gnu/libQtGui.so.4
#5 0xb68bd424 in QPainter::drawPixmap(QPointF const&, QPixmap const&) () from /usr/lib/i386-linux-gnu/libQtGui.so.4
因此,正如我在第一时间所认为的那样,这不是与计时器处理相关的问题 发生分段错误是因为我对pixMap做错了。
答案 0 :(得分:0)
抱歉,我无法重现您所看到的段错误。这是我尝试使用(Qt 4.8.1,PyQt 4.9.1,Python 2.7.3,Kubuntu Precise)重现崩溃的应用程序的完整源代码:
#!/usr/bin/env python
import sys
from PyQt4 import QtCore, QtGui
class AppStatus(object):
def __init__(self):
self.timer = None
class ExperimentAnalyzer(QtGui.QMainWindow):
def __init__(self, parent=None):
super(ExperimentAnalyzer, self).__init__(parent)
elayout = QtGui.QVBoxLayout()
self.count = 0
self.appStatus = AppStatus()
everything = QtGui.QWidget(self)
everything.setLayout(elayout)
button = QtGui.QPushButton("Start/stop timer", self)
self.connect(button, QtCore.SIGNAL("clicked()"), self.playOrPause)
elayout.addWidget(button)
button = QtGui.QPushButton("Load experiment", self)
self.connect(button, QtCore.SIGNAL("clicked()"), self.loadExperiment)
elayout.addWidget(button)
self.setCentralWidget(everything)
def loadExperiment(self):
directory = QtGui.QFileDialog.getExistingDirectory(self, "Select Directory")
def nextFrame(self):
self.count += 1
print self.count
def playOrPause(self):
if self.appStatus.timer is None:
self.appStatus.timer = QtCore.QTimer(self)
self.appStatus.timer.connect(self.appStatus.timer,
QtCore.SIGNAL("timeout()"),
self.nextFrame)
self.appStatus.timer.start(40)
else:
self.appStatus.timer.stop()
self.appStatus.timer = None
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mainwin = ExperimentAnalyzer(None)
mainwin.show()
app.exec_()
如果此测试应用程序没有为您崩溃,则问题出在您未向我们展示的代码中。
答案 1 :(得分:0)
好的,我最终发现了问题所在。
我修改了 nextFrame 方法,以便保留对 ImageQt 对象的引用,即:< / p>
def nextFrame(self):
## load the image from file
self.appStatus.imageQt = ImageQt.ImageQt(image)
pixMap = QtGui.QPixmap.fromImage(self.appStatus.imageQt)
## update the QGraphicsView
并且分段错误消失了。
我对此的解释如下: Qt mantains,内部,指向 ImageQt 对象的指针,每次使用时都会使用触发 paintEvent (因此,必须重新绘制pixMap)。
不保留对 ImageQt 对象的引用,允许Python的GC收集它。因此, Qt 将尝试从已释放的内存区域读取,从而产生分段错误。