Мне действительно трудно понять, как использовать Threads в PyQt. Я сделал простой пример того, что я хотел бы сделать в своем интерфейсе. В коде, который вы видите ниже, я хочу, чтобы пользователь вводил тикер акций (например, вы можете ввести «bby», «goog» или «v») и составить график стоимости акций за определенный период. Дело в более сложном Ui или в течение длительного периода времени пользовательский интерфейс замирает, пока сюжет обновляется. Поэтому я создал класс «Plotter», который обновляет график, когда он получает определенный сигнал (переопределение Qthread.run, по-видимому, было неправильным способом you're doing it wrong). Я бы хотел, чтобы этот «Плоттер» работал в другом потоке, кроме основного.Как использовать Qthread для обновления фигуры Matplotlib с помощью PyQt?
Как только я раскомментирую нитки, программа перестает работать. Я попытался переместить запуск нового потока, а также «подключиться», но ничего не работает. Я думаю, что не понимаю, как работает Qthread даже после прочтения documentation и просмотра примеров на веб-сайте Qt.
Если вы знаете, как это сделать, это поможет! (Я работаю с Python 3.5 и PyQt5)
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) вызовы из вторичного потока. Вы можете получить данные в потоке, но вам нужно будет отправить их обратно в основной поток для построения, вызывая собственный сигнал (так что возвращайте данные для построения графика, а не объекта осей, который вы сейчас возвращаете) –