我正在使用PyQt5设计应用程序。有很多图,我使用Matplotlib来管理它们。
当前,我正在尝试使用Qthread
,以便Main Loop
不会冻结太长时间。
我使用了This exemple: How to use a Qthread to update a Matplotlib figure with PyQt?。
但是,正如导师所提到的,在第一个解决方案中,我创建的线程永远不会停止。
我的问题是:在replot
对象中完成Plotter()
功能后,如何停止它?
我不喜欢在此代码中使用Terminate()
。
而且QThread
完成的事实将使我能够使用PushButton
之类的连接来再次设置self.thread.finished.connect(my_function)
能力。
这是我的代码的一些简化部分:
创建图的类图
# Figures
class My_figure(FigureCanvas):
send_fig = QtCore.pyqtSignal(Axes, name="send_fig")
def __init__(self, fig_size, fig_move, parent=None):
self.fig = Figure(figsize=fig_size)
self.axes = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
self.move(fig_move[0], fig_move[1])
def update_plot(self, axes):
self.axes = axes
self.draw()
主对话框中的功能
# graphs creation
def new_graph(self, name):
setattr(self, name + '_my_fig', [])
# créer les graphs, axes, canvas, etc.
graph_cat = ['bar_', 'pie_','line_']
graph_element = ['_figure', '_canvas', '_axes', '_plotter', '_thread']
fig_dim = [[0, (6.8, 4.3), (6, 3.5)],[0, 0, 30]]
compt = 0
for g_c in graph_cat:
getattr(self, name + '_my_fig').append([])
setattr(self, g_c + name + '_my_fig', My_figure((3,3),[0,0], parent = getattr(self, g_c + name)))
getattr(self, name + '_my_fig')[-1].append(getattr(self, g_c + name + '_my_fig'))
# Couple thread / worker
setattr(self, g_c + name + graph_element[3], None)
setattr(self, g_c + name + graph_element[4], None)
getattr(self, name + '_my_fig')[-1].append(getattr(self, g_c + name + graph_element[3]))
getattr(self, name + '_my_fig')[-1].append(getattr(self, g_c + name + graph_element[4]))
compt += 1
# thread and worker creation + start
for my_fig in self.tot_my_fig:
print(my_fig)
# if there is already a thread running, kill it first
if my_fig[1] != None and my_fig[1].isRunning():
print('termiante')
my_fig [1].terminate()
my_fig[1] = QtCore.QThread()
my_fig[2] = Plotter()
self.send_fig.connect(my_fig[2].replot)
my_fig[2].return_fig.connect(my_fig[0].update_plot)
my_fig[1].finished.connect(self.ppp)
#move to thread and start
my_fig[2].moveToThread(my_fig[1])
my_fig[1].start()
# start the plotting
self.send_fig.emit(my_fig[0].axes)
工人阶级
# Worker
class Plotter(QtCore.QObject):
return_fig = QtCore.pyqtSignal(Axes)
@QtCore.pyqtSlot(Axes)
def replot(self, axes): # A slot takes no params
axes.clear()
# do some random task
data = np.random.rand(1000,1000)
axes.plot(data.mean(axis=1))
self.return_fig.emit(axes)
我要做的是创建一个绘图线程,然后将要绘制的图形和轴传递到该线程上。当您在一个线程完成之前再次绘图时,两个线程可以同时运行,并且两个线程都完成了,但是最新的线程是显示的。
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
import random
import time
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
class MplFigure(object):
def __init__(self,parent):
self.figure=plt.figure(facecolor=(.195,.195,.195))
self.canvas=FigureCanvas(self.figure)
class plotThread(QThread):
finished=pyqtSignal()
def __init__(self,main_figure,ax1,x,y=[]):
super(plotThread, self).__init__()
self.main_figure=main_figure
self.ax1=ax1
self.x=x
self.y=y
def run(self):
self.ax1.clear()
line,=self.ax1.plot(self.x)
#line.set_ydata(self.y)
self.ax1.draw_artist(line)
self.main_figure.canvas.draw()
time.sleep(2)
self.finished.emit()
WINDOW_SIZE=900,600
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300,300,*WINDOW_SIZE)
layout=QVBoxLayout()
view=QGraphicsView()
view.setLayout(layout)
self.main_figure=MplFigure(self)
layout.addWidget(self.main_figure.canvas)
self.setCentralWidget(view)
self.ax1=self.main_figure.figure.add_subplot(1,1,1)
self.btn=QPushButton('Plot Random')
layout.addWidget(self.btn)
self.btn.clicked.connect(self.plot_threaded)
self.show()
def plot_threaded(self):
#self.btn.setEnabled(False)
rand=random.sample(range(1,20),10)
self.worker=plotThread(self.main_figure,self.ax1,rand)
self.worker.finished.connect(self.enable_button)
self.worker.start()
def enable_button(self):
#self.btn.setEnabled(True)
print('Thread finished')
if __name__=='__main__':
app=QApplication([])
window=MainWindow()
app.exec_()
sys.exit()