私は本当にPyQtでスレッドを使用する方法を理解するのに苦労しています。私は自分のUIで何をしたいのか簡単な例を作りました。下のコードでは、株価を入力する(たとえば、 "bby"、 "goog"または "v"を入力することができます)、一定期間にわたり株価をプロットします。物事はUIがより複雑になっているか、プロットが更新されている間にUIがフリーズしています。だから私はプロットを更新して、ある種の信号を受け取ったときにプロットを更新するクラスを作った(Qthread.runをオーバーライドするのは明らかに正しい方法ではないyou're doing it wrong)。私はこの "プロッタ"をメインとは別のスレッドで実行させたいと思っています。Qthreadを使ってMatplotlibの図をPyQtで更新する方法は?
スレッド行のコメントを外すと、プログラムは機能しなくなります。私は新しいスレッドの起動と "接続"を試みましたが、何も動いていません。私はdocumentationを読んでQtのWebサイトの例を見ても、Qthreadがどのように機能するのかよく分かりません。
これを行う方法がわかっている場合は、多くの手助けをします。
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from matplotlib.axes._subplots import Axes
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
from datetime import datetime, timedelta
import time
import quandl
class MyMplCanvas(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
send_fig = pyqtSignal(Axes, str, name="send_fig")
def __init__(self, parent=None):
self.fig = Figure()
self.axes = self.fig.add_subplot(111)
# We want the axes cleared every time plot() is called
self.axes.hold(False)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def update_plot(self, axes):
self.axes = axes
self.draw()
class MainWindow(QMainWindow):
send_fig = pyqtSignal(Axes, str, name="send_fig")
def __init__(self):
super().__init__()
self.main_widget = QWidget(self)
self.myplot = MyMplCanvas(self.main_widget)
self.editor = QLineEdit()
self.display = QLabel("Vide")
self.layout = QGridLayout(self.main_widget)
self.layout.addWidget(self.editor)
self.layout.addWidget(self.display)
self.layout.addWidget(self.myplot)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
self.move(500, 500)
self.show()
self.editor.returnPressed.connect(self.updatePlot)
self.plotter = Plotter()
self.send_fig.connect(self.plotter.replot)
self.plotter.return_fig.connect(self.myplot.update_plot)
def updatePlot(self):
ticker = self.editor.text()
self.editor.clear()
self.display.setText(ticker)
# thread = QThread()
# self.plotter.moveToThread(thread)
self.send_fig.emit(self.myplot.axes, ticker)
# thread.start()
class Plotter(QObject):
return_fig = pyqtSignal(Axes)
@pyqtSlot(Axes, str)
def replot(self, axes, ticker): # A slot takes no params
print(ticker)
d = datetime.today() - timedelta(weeks=52) # data from 1week ago
data = quandl.get("YAHOO/"+ticker+".6", start_date=d.strftime("%d-%m-%Y"), end_date=time.strftime("%d-%m-%Y"))
axes.plot(data)
self.return_fig.emit(axes)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())
コードはスレッドセーフではありません。セカンダリスレッドからmatplotlib(または任意のQt GUI)呼び出しを行うことはできません。スレッド内のデータをフェッチすることはできますが、カスタム信号を出力してプロットするためにメインスレッドに戻す必要があります(今戻っているAxesオブジェクトではなく、プロットのデータを返してください)。 –