首页 > 解决方案 > 微调器不出现

问题描述

我创建了一个非常简单的 GUI,它有一个按钮和一个绘图。当我点击按钮时,我想在图中看到微调器,当它完成时,我只想看到新的情节。我尝试了一些东西,但不幸的是它不起作用......这是我的代码:

import threading
import time
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
from pyqtspinner.spinner import WaitingSpinner

freqs = np.arange(2, 20, 3)

fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.2)
t = np.arange(0.0, 1.0, 0.001)
s = np.sin(2*np.pi*freqs[0]*t)
l, = plt.plot(t, s, lw=2)


class Index(object):
    ind = 0

    def next(self, event):
        self.ind += 1
        i = self.ind % len(freqs)
        ydata = np.sin(2*np.pi*freqs[i]*t)
        l.set_ydata(ydata)
        plt.draw()


callback = Index()
axnext = plt.axes([0.81, 0.05, 0.1, 0.075])
bnext = Button(axnext, 'Next')

def process():
    spin = WaitingSpinner(
        fig,
        roundness=70.0, opacity=15.0,
        fade=70.0, radius=10.0, lines=12,
        line_length=10.0, line_width=5.0,
        speed=1.0, color=(0, 0, 0)
    )

    def the_proc():
        time.sleep(10)
        callback.next
    

    def animated_loading(self):
        spin.start()

    the_process = threading.Thread(name='process', target=the_proc())
    while the_process.isAlive():
        animated_loading()

bnext.on_clicked(process)

plt.show()

标签: pythonmatplotlibpyqt

解决方案


如果你打算使用 Qt,那么你不应该使用 pyplot,另一方面你应该使用 Qt 信号。考虑到上述情况,解决方案是:

import threading
import time

import numpy as np

from PyQt5 import QtCore, QtWidgets
from pyqtspinner.spinner import WaitingSpinner

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import (
    FigureCanvas,
    NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.widgets import Button


freqs = np.arange(2, 20, 3)
t = np.arange(0.0, 1.0, 0.001)


class Processor(QtCore.QObject):
    started = QtCore.pyqtSignal()
    finished = QtCore.pyqtSignal()
    dataChanged = QtCore.pyqtSignal(np.ndarray)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.ind = 0
        self._is_bussing = False

        self.started.connect(self._on_started)
        self.finished.connect(self._on_finished)

    @property
    def is_bussing(self):
        return self._is_bussing

    def start(self):
        self._is_bussing = True
        thread = threading.Thread(target=self.process, daemon=True)
        thread.start()

    def process(self):
        self.started.emit()
        time.sleep(10)
        self.next()
        self.finished.emit()

    def next(self):
        self.ind += 1
        i = self.ind % len(freqs)
        ydata = np.sin(2 * np.pi * freqs[i] * t)
        self.dataChanged.emit(ydata)

    @QtCore.pyqtSlot()
    def _on_started(self):
        self._is_bussing = True

    @QtCore.pyqtSlot()
    def _on_finished(self):
        self._is_bussing = False


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.canvas = FigureCanvas(Figure(figsize=(5, 5)))
        self.addToolBar(QtCore.Qt.TopToolBarArea, NavigationToolbar(self.canvas, self))

        self.setCentralWidget(self.canvas)

        self.ax = self.canvas.figure.subplots()
        self.canvas.figure.subplots_adjust(bottom=0.2)

        s = np.sin(2 * np.pi * freqs[0] * t)
        (self.l,) = self.ax.plot(t, s, lw=2)

        self.axnext = self.canvas.figure.add_axes([0.81, 0.05, 0.1, 0.075])
        self.bnext = Button(self.axnext, "Next")

        self.processor = Processor()
        self.processor.started.connect(self.on_started)
        self.processor.finished.connect(self.on_finished)
        self.processor.dataChanged.connect(self.on_dataChanged)

        self.bnext.on_clicked(self.on_clicked)

        self.spinner = WaitingSpinner(
            self,
            roundness=70.0,
            opacity=15.0,
            fade=70.0,
            radius=10.0,
            lines=12,
            line_length=10.0,
            line_width=5.0,
            speed=1.0,
            color=(0, 0, 0),
        )

    def on_clicked(self, event):
        if not self.processor.is_bussing:
            self.processor.start()

    @QtCore.pyqtSlot()
    def on_started(self):
        self.spinner.start()

    @QtCore.pyqtSlot()
    def on_finished(self):
        self.spinner.stop()

    @QtCore.pyqtSlot(np.ndarray)
    def on_dataChanged(self, ydata):
        self.l.set_ydata(ydata)
        self.canvas.draw()


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

推荐阅读