Ich habe wirklich eine harte Zeit zu verstehen, wie Sie Threads in PyQt verwenden. Ich habe ein einfaches Beispiel dafür erstellt, was ich in meiner Benutzeroberfläche tun möchte. In dem Code, den Sie unten sehen können, möchte ich, dass der Benutzer einen Börsenticker eingibt (Sie können z. B. "bby", "goog" oder "v" eingeben) und den Wert des Wertpapiers über einen bestimmten Zeitraum grafisch darstellen. Die Sache ist in komplexeren Ui oder für eine lange Zeit die Benutzeroberfläche eingefroren, während der Plot aktualisiert wird. Also habe ich eine "Plotter" -Klasse erstellt, die das Diagramm aktualisiert, wenn es ein bestimmtes Signal empfängt (das Überschreiben von Qthread.run war anscheinend nicht der richtige Weg you're doing it wrong). Ich möchte diesen "Plotter" in einem anderen Thread als dem Hauptprogramm laufen lassen.Wie verwende ich Qthread, um eine Matplotlib-Figur mit PyQt zu aktualisieren?
Sobald ich die Fadenlinien auskommentiere, hört das Programm auf zu arbeiten. Ich habe versucht, den Start des neuen Threads und auch das "Verbinden" zu verschieben, aber nichts funktioniert. Ich denke, ich verstehe nicht gut, wie Qthread funktioniert, nachdem ich die documentation gelesen und die Beispiele auf der Qt-Website angeschaut habe.
Wenn Sie wissen, wie dies zu tun ist, würde es sehr helfen! (Ich arbeite mit Python 3.5 und 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_())
Ihr Code ist nicht threadsicher. Sie können keine Matplotlib-Aufrufe (oder Qt-GUI-Aufrufe) von einem sekundären Thread ausführen. Sie können die Daten in einem Thread abrufen, aber Sie müssen sie zum Zeichnen an den Hauptthread zurücksenden, indem Sie ein benutzerdefiniertes Signal ausgeben (geben Sie also die Daten zum Plotten und nicht das Achsenobjekt zurück, das Sie gerade zurückgeben). –