【发布时间】:2013-08-24 12:50:54
【问题描述】:
我正在尝试与 Chaco 和 pyqt 合作,为实验室硬件绘制实时数据采集任务。我以前使用过 matplotlib,但事实证明它太慢了(我什至尝试过动画)。当我在 pyqt 窗口中嵌入 matplotlib 图时,以下代码工作正常,但是使用 chaco,当我从线程内部发出更新信号时,什么也没有发生。如果您不使用线程进行模拟采集,此代码将起作用。我也试过使用 qthreads 也无济于事(包括这样的东西:Threading and Signals problem in PyQt)。有没有人使用过 pyqt + chaco + threading 可以帮助我找到哪里出错了,或者发生了什么?
import sys
import threading, time
import numpy as np
from enthought.etsconfig.etsconfig import ETSConfig
ETSConfig.toolkit = "qt4"
from enthought.enable.api import Window
from enthought.chaco.api import ArrayPlotData, Plot
from PyQt4 import QtGui, QtCore
class Signals(QtCore.QObject):
done_collecting = QtCore.pyqtSignal(np.ndarray, np.ndarray)
class PlotWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
x = np.linspace(0,2*np.pi,200)
y = np.sin(x)
plotdata = ArrayPlotData(x=x, y=y)
plot = Plot(plotdata, padding=50, border_visible=True)
plot.plot(('x', 'y'))
window = Window(self,-1, component=plot)
self.setCentralWidget(window.control)
self.resize(500,500)
self.pd = plotdata
def update_display(self, x, y):
print 'updating'
self.pd.set_data('x', x)
self.pd.set_data('y', y)
def run_collection(signal):
# this is where I would start and stop my hardware,
# but I will just call the read function myself here
for i in range(1,10):
every_n_collected(i, signal)
time.sleep(0.5)
def every_n_collected(frequency, signal):
# dummy data to take place of device read
x = np.linspace(0,2*np.pi,200)
y = np.sin(x*frequency)
print 'emitting'
signal.emit(x, y)
QtGui.QApplication.processEvents()
def main():
plt = PlotWindow()
plt.show()
QtGui.QApplication.processEvents()
signals = Signals()
signals.done_collecting.connect(plt.update_display)
t = threading.Thread(target=run_collection, args=(signals.done_collecting,))
t.start()
t.join()
QtGui.QApplication.processEvents()
# it works without threads though...
# run_collection(signals.done_collecting)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main()
【问题讨论】:
-
你永远不会启动一个事件循环,也不要在信号发出后调用
processEvents(除了在连接到信号的槽内)。所以信号没有被传递也就不足为奇了。如果在t.join()之后添加processEvents会发生什么? -
如果我在 t.join() 之后添加 processEvents,更新将执行,但只有在线程完成后才会执行。
-
您应该在
signal.emit之后添加它以允许 gui 更新。将它放在update_display中是没有意义的,因为除非事件处理已经发生,否则不会调用它。 -
保存行为,我还更新了 sn-p 以反映更改。我在信号发出后有
processEvents,因为我认为我必须调用它才能使绘图更改生效(这是我对matplotlib所做的),而不是让信号发出,所以很高兴知道。
标签: python multithreading pyqt pyqt4 chaco