You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何同时加载两个带Matplotlib动画的Tkinter窗口并实现独立运行的计算场景?

如何同时加载两个带Matplotlib动画的Tkinter窗口并实现独立运行的计算场景?

嘿,我来帮你搞定这个问题!要实现两个独立的带Matplotlib动画的Tkinter窗口,核心思路就是把每个场景的参数、计算逻辑、绘图和动画都封装成独立的单元,让它们各玩各的,互不干扰。我把你提供的计算代码改成了可复用的类结构,每个窗口对应一个类实例,完美实现独立运行:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.animation import FuncAnimation
import tkinter as tk
from tkinter import ttk

class ScenarioWindow:
    def __init__(self, root, title, scenario_params):
        # 创建独立的Toplevel窗口,作为主窗口的子窗口
        self.window = tk.Toplevel(root)
        self.window.title(title)
        
        # 存储当前场景的参数
        self.params = scenario_params
        # 初始化计算结果容器
        self.results = []
        self.time_points = []
        
        # 先搭好绘图框架和动画
        self.setup_plot()
        self.animation = FuncAnimation(self.fig, self.update_plot, interval=200, blit=True)
        
        # 加个运行按钮,点击就触发当前场景的计算
        run_btn = ttk.Button(self.window, text="运行场景", command=self.run_model)
        run_btn.pack(pady=10)

    # 单位转换函数,和原来的逻辑一致
    def convert_to_seconds(self, duration):
        return duration * 60  # 分钟转秒

    def convert_to_kg(self, amount):
        return amount / 1000  # 克转千克

    def convert_to_per_second(self, rate):
        return rate / 3600  # 每小时转每秒

    def run_model(self):
        # 清空之前的计算结果,避免和新结果混在一起
        self.results.clear()
        self.time_points.clear()
        
        # 把参数从字典里取出来,方便后续计算
        freq_per_year = self.params["frequency_per_year"]
        exposure_dur = self.params["exposure_duration"]
        product_amount = self.params["product_amount"]
        weight_frac = self.params["weight_fraction_substance"]
        room_vol = self.params["room_volume"]
        vent_rate = self.params["ventilation_rate"]
        inh_rate = self.params["inhalation_rate"]
        body_weight = self.params["body_weight_kg"]
        vapour_press = self.params["vapour_pressure"]
        temp = self.params["application_temperature"]
        mol_weight = self.params["molecular_weight"]
        
        # 执行单位转换
        exposure_dur_sec = self.convert_to_seconds(exposure_dur)
        product_amount_kg = self.convert_to_kg(product_amount)
        vent_rate_per_sec = self.convert_to_per_second(vent_rate)
        inh_rate_per_sec = self.convert_to_per_second(inh_rate)
        
        # 这里是核心计算逻辑,我保留了你的框架,用了一个简单的浓度模拟示例
        # 你可以替换成自己的真实模型
        for t in np.linspace(0, exposure_dur_sec, 100):
            conc = (product_amount_kg * weight_frac * vapour_press) / (room_vol * (1 + vent_rate_per_sec * t))
            self.results.append(conc)
            self.time_points.append(t / 60)  # 把时间转回分钟,方便绘图
        
        # 打印当前场景的结果
        print(f"=== {self.window.title()} 计算结果 ===")
        print(f"最终浓度: {self.results[-1]:.6f} kg/m³")
        print(f"暴露时长: {exposure_dur} 分钟\n")

    def setup_plot(self):
        # 创建Matplotlib的图和轴,每个窗口用自己的实例
        self.fig, self.ax = plt.subplots(figsize=(6, 4))
        self.line, = self.ax.plot([], [], 'b-', linewidth=2)
        
        # 设置图表的标签和样式
        self.ax.set_xlabel("时间 (分钟)")
        self.ax.set_ylabel("浓度 (kg/m³)")
        self.ax.set_title(self.window.title())
        self.ax.set_xlim(0, self.params["exposure_duration"])
        self.ax.set_ylim(0, 0.001)  # 可以根据实际计算结果调整y轴范围
        self.ax.grid(True)
        
        # 把Matplotlib画布嵌入到当前的Tkinter窗口里
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.window)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(pady=10)

    def update_plot(self, frame):
        # 动画更新函数,每次只更新到当前帧的数据
        if self.time_points and self.results:
            self.line.set_data(self.time_points[:frame+1], self.results[:frame+1])
        return self.line,

if __name__ == "__main__":
    # 主Tk窗口,我们把它隐藏起来,只作为事件循环的载体
    root = tk.Tk()
    root.withdraw()
    
    # 定义两个不同场景的参数,你可以随便修改这些值
    scenario1_params = {
        "frequency_per_year": 365,
        "exposure_duration": 240,
        "product_amount": 5,
        "weight_fraction_substance": 0.6,
        "room_volume": 58,
        "ventilation_rate": 0.5,
        "inhalation_rate": 10,
        "body_weight_kg": 65,
        "vapour_pressure": 2,
        "application_temperature": 18,
        "molecular_weight": 100
    }
    
    scenario2_params = {
        "frequency_per_year": 100,
        "exposure_duration": 120,
        "product_amount": 8,
        "weight_fraction_substance": 0.8,
        "room_volume": 30,
        "ventilation_rate": 1.0,
        "inhalation_rate": 12,
        "body_weight_kg": 70,
        "vapour_pressure": 3,
        "application_temperature": 22,
        "molecular_weight": 120
    }
    
    # 创建两个独立的场景窗口,各自用自己的参数
    window1 = ScenarioWindow(root, "场景1: 日常暴露模拟", scenario1_params)
    window2 = ScenarioWindow(root, "场景2: 高浓度作业模拟", scenario2_params)
    
    # 启动Tkinter的主事件循环,两个窗口都会正常运行
    root.mainloop()

关键细节说明:

  • 类封装隔离:每个ScenarioWindow实例都是独立的,参数、计算结果、绘图对象都是自己的,完全不会和另一个窗口冲突
  • 独立窗口载体:用Toplevel创建子窗口,主窗口隐藏,既保证了事件循环的正常运行,又不会多出来一个没用的窗口
  • 动画独立更新:每个窗口的FuncAnimation只绑定自己的画布,动画播放互不影响
  • 可扩展性强:如果要加第三个、第四个场景,直接复制参数字典,创建新的ScenarioWindow实例就行

备注:内容来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 09:54:33