我试图与Chaco和pyqt一起绘制实验室硬件的实时数据采集任务。我以前使用matplotlib,但它证明太慢了(我甚至尝试过动画)。当我在pyqt窗口中嵌入一个matplotlib图时,下面的代码工作的很好,但是当使用chaco时,当我从线程内部发出更新信号时没有任何反应。如果您不使用线程进行模拟采集,此代码将起作用。我曾尝试使用qthreads也无济于事(包括这样的事情:Threading and Signals problem in PyQt)。有没有人使用pyqt + chaco +线程来帮助我找到错误的地方,或者发生了什么?Chaco和PyQt发出信号失败
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',会发生什么? – mata
如果我在t.join()之后添加processEvents,则更新将会执行,但只能在线程完成后立即执行。 – hackyday
你应该在'signal.emit'之后添加它以允许gui更新。将它放在'update_display'中是毫无意义的,因为除非事件已经发生,否则不会调用它。 – mata