如何实现SimPy与PyQt交互,实时更新显示仿真运行时间
解决方案
核心思路是用Qt的事件循环驱动SimPy仿真步进,避免SimPy的阻塞run()方法占满主线程导致Qt界面无响应,具体实现如下:
核心修改点
- 不直接调用
env.run(until=xxx)阻塞主线程,改为逐次步进SimPy环境 - 用
QTimer将仿真步进逻辑挂载到Qt的事件队列中,定时触发仿真推进 - 每次步进时先执行完当前时间点的所有SimPy事件,再更新界面,直到达到仿真结束条件
import sys import simpy from PyQt5 import QtWidgets, QtCore class Window(QtWidgets.QWidget): """ 可与SimPy交互的Qt窗口 """ def __init__(self, env, parent=None): super(Window, self).__init__() self.env = env self.init() def init(self) -> None: layout = QtWidgets.QVBoxLayout() self.label = QtWidgets.QLabel('SimPy Time: {}'.format(self.env.now)) layout.addWidget(self.label) self.setLayout(layout) self.show() def update_label(self) -> None: """ 更新标签显示的仿真时间 """ self.label.setText(f"SimPy Time: {self.env.now}") def simpy_generator(env, window): """ SimPy仿真生成器 """ while True: window.update_label() yield env.timeout(1) if __name__ == "__main__": # 仿真结束时间 SIM_END = 25 env = simpy.Environment() app = QtWidgets.QApplication(sys.argv) window = Window(env=env) # 提前注册仿真进程 env.process(simpy_generator(env, window)) # 定义仿真步进槽函数 def step_simpy(): # 未到结束时间就步进1个时间单位 if env.now < SIM_END: env.run(until=env.now + 1) else: # 仿真结束后停止定时器 sim_timer.stop() # 初始化定时器,间隔0.5秒触发一次步进(可根据需求调整间隔) sim_timer = QtCore.QTimer() sim_timer.timeout.connect(step_simpy) sim_timer.start(500) app.exec_()
补充说明
- 如果需要仿真按真实时间比例运行,调整
QTimer的start()参数即可,比如想要仿真1秒对应真实1秒,就设置为start(1000) - 如果仿真逻辑比较复杂,单次步进耗时较高,可以把SimPy仿真放到单独的子线程中运行,通过Qt的信号槽机制把仿真数据传递到主线程更新界面,避免界面卡顿
- 也可以通过
env.peek()获取SimPy下一个事件的触发时间,自动计算步进的时间长度,不需要固定每次走1个单位,适配更复杂的仿真场景
内容的提问来源于stack exchange,提问作者Sav
相关产品推荐
相关产品推荐

