import sys import time import numpy as np from matplotlib.backends.qt_compat import QtCore, QtWidgets from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar) from matplotlib.figure import Figure from protocol.Celery.MBTCPMaster import app as MBTCPMApp from celery.result import AsyncResult from model.ProjectModel.VarManage import ModbusVarManage from utils import Globals class ActualTrend(QtWidgets.QMainWindow): def __init__(self, parent=None, varName = None): super(ActualTrend, self).__init__(parent) self.varName = varName self.protocolManage = Globals.getValue('protocolManage') _main = QtWidgets.QWidget() self.setCentralWidget(_main) layout = QtWidgets.QVBoxLayout(_main) dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3))) layout.addWidget(dynamic_canvas) self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(dynamic_canvas, self)) self.x = [] # 建立空的x轴数组和y轴数组 self.y = [] self.maxPoints = 200 self._dynamic_ax = dynamic_canvas.figure.subplots() self._timer = dynamic_canvas.new_timer( 500, [(self._update_canvas, (), {})]) self._timer.start() def _update_canvas(self): # 防止canvas已被销毁时报错 if not hasattr(self, '_dynamic_ax') or not hasattr(self._dynamic_ax, 'figure') or not hasattr(self._dynamic_ax.figure, 'canvas'): return varName = self.varName if not varName or not self.protocolManage: return # 获取实时值 yValue = self.protocolManage.readVariableValue(varName) acttime = time.strftime('%H:%M:%S', time.localtime(time.time())) if yValue is not None: self.x.append(acttime) self.y.append(yValue) # 只保留最新maxPoints个点 if len(self.x) > self.maxPoints: self.x = self.x[-self.maxPoints:] self.y = self.y[-self.maxPoints:] self._dynamic_ax.clear() pos_list = np.arange(len(self.x)) self._dynamic_ax.set_xticks(pos_list) # 限制最多显示16个主刻度,自动旋转,字体更大更明显 import matplotlib.ticker as ticker max_xticks = 12 if len(self.x) > max_xticks: step = max(1, len(self.x) // max_xticks) display_labels = [label if i % step == 0 else '' for i, label in enumerate(self.x)] else: display_labels = self.x self._dynamic_ax.set_xticklabels(display_labels, rotation=30, fontsize=13, fontweight='bold') self._dynamic_ax.plot(pos_list, self.y, 'bo-', linewidth=2) if self.y: minY = min(self.y) - 5 maxY = max(self.y) + 5 self._dynamic_ax.set_ylim(minY, maxY) from matplotlib.ticker import MaxNLocator self._dynamic_ax.yaxis.set_major_locator(MaxNLocator(nbins=12, prune=None)) self._dynamic_ax.figure.canvas.draw() def closeEvent(self, event): # 停止定时器,防止回调访问已销毁的canvas if hasattr(self, '_timer'): self._timer.stop() super().closeEvent(event) self.hide() def showEvent(self, event): self._timer.start() if __name__ == "__main__": qapp = QtWidgets.QApplication(sys.argv) app = ActualTrend() app.show() qapp.exec_()