for 循环中的 Tkinter GUI
Tkinter GUI in for loop
我正在为我的程序做一个 tkinter GUI,我必须显示一些实时数据。我做了一个简单的程序(如下)来在一个简单的案例中演示我的问题。实际上,我在 for 循环的每次迭代中都绘制了一些数据,这样我就可以在程序仍在计算的同时观察数据。请注意,真正的程序 si 计算速度有点慢并且有更多的迭代。
现在我想添加 2 个按钮(一个用于暂停程序,一个用于继续)和一个标签(显示变量 k,以便我知道我的程序在哪里),但我无法这样做。
我已经在这上面浪费了很多时间,所以如果有人有提示或解决方案,我很乐意看到它。
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
from matplotlib import style
def func_A(a, x):
import numpy
data_x = numpy.arange(0, x)
data_y = a * numpy.sin(data_x/5)
return data_x, data_y
a = 1
root = tk.Tk()
root.title("Graph")
root.geometry("800x400")
fig = plt.figure(figsize=(5, 5), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.grid("both")
style.use("ggplot")
for k in range(0, 100):
data_x, data_y = func_A(a, k)
print("iteration", k)
print("data_x", data_x)
print("data_y", data_y)
if k == 0:
ax1 = plt.subplot(111)
line1, = ax1.plot([0], [0])
else:
line1.set_xdata(data_x)
line1.set_ydata(data_y)
ax1.set_ylim([-1, 1])
ax1.set_xlim([0, 100])
plt.grid("both")
canvas.draw()
canvas.flush_events()
root.mainloop()
添加pause/resume功能:
- 创建一个框架来保存进度标签和两个按钮:暂停和恢复
- 创建一个 tkinter
BooleanVar()
来存储 pause/resume 状态
- 将更新绘图代码移到一个函数中,例如
update_plot()
- 使用
.after()
代替for循环周期性调用update_plot()
- 在
update_plot()
里面,检查pause/resume状态来决定是否更新剧情
下面是根据您的代码修改的示例:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
from matplotlib import style
import matplotlib
matplotlib.use("Agg")
root = tk.Tk()
root.title("Graph")
#root.geometry("800x400")
# progress label, pause and resume buttons
frame = tk.Frame(root)
frame.pack(fill="x", side=tk.TOP)
progress = tk.Label(frame)
progress.pack(side="left")
is_paused = tk.BooleanVar() # variable to hold the pause/resume state
tk.Button(frame, text="Pause", command=lambda: is_paused.set(True)).pack(side="right")
tk.Button(frame, text="Resume", command=lambda: is_paused.set(False)).pack(side="right")
# the plot
fig = plt.figure(figsize=(10, 5), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root)
toolbar = NavigationToolbar2Tk(canvas, root)
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.grid("both")
style.use("ggplot")
a = 1
ax1 = plt.subplot(111)
line1, = ax1.plot([0], [0])
def func_A(a, x):
import numpy
data_x = numpy.arange(0, x)
data_y = a * numpy.sin(data_x/5)
return data_x, data_y
# function to update ploat
def update_plot(k=0):
if not is_paused.get():
progress["text"] = f"iteration: {k}"
data_x, data_y = func_A(a, k)
#print("iteration", k)
#print("data_x", data_x)
#print("data_y", data_y)
line1.set_xdata(data_x)
line1.set_ydata(data_y)
ax1.set_ylim([-1, 1])
ax1.set_xlim([0, 100])
plt.grid("both")
canvas.draw()
canvas.flush_events()
k += 1
if k <= 100:
# update plot again after 10ms. You can change the delay to whatever you want
root.after(10, update_plot, k)
update_plot() # start updating plot
root.mainloop()
我正在为我的程序做一个 tkinter GUI,我必须显示一些实时数据。我做了一个简单的程序(如下)来在一个简单的案例中演示我的问题。实际上,我在 for 循环的每次迭代中都绘制了一些数据,这样我就可以在程序仍在计算的同时观察数据。请注意,真正的程序 si 计算速度有点慢并且有更多的迭代。
现在我想添加 2 个按钮(一个用于暂停程序,一个用于继续)和一个标签(显示变量 k,以便我知道我的程序在哪里),但我无法这样做。
我已经在这上面浪费了很多时间,所以如果有人有提示或解决方案,我很乐意看到它。
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
from matplotlib import style
def func_A(a, x):
import numpy
data_x = numpy.arange(0, x)
data_y = a * numpy.sin(data_x/5)
return data_x, data_y
a = 1
root = tk.Tk()
root.title("Graph")
root.geometry("800x400")
fig = plt.figure(figsize=(5, 5), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.grid("both")
style.use("ggplot")
for k in range(0, 100):
data_x, data_y = func_A(a, k)
print("iteration", k)
print("data_x", data_x)
print("data_y", data_y)
if k == 0:
ax1 = plt.subplot(111)
line1, = ax1.plot([0], [0])
else:
line1.set_xdata(data_x)
line1.set_ydata(data_y)
ax1.set_ylim([-1, 1])
ax1.set_xlim([0, 100])
plt.grid("both")
canvas.draw()
canvas.flush_events()
root.mainloop()
添加pause/resume功能:
- 创建一个框架来保存进度标签和两个按钮:暂停和恢复
- 创建一个 tkinter
BooleanVar()
来存储 pause/resume 状态 - 将更新绘图代码移到一个函数中,例如
update_plot()
- 使用
.after()
代替for循环周期性调用update_plot()
- 在
update_plot()
里面,检查pause/resume状态来决定是否更新剧情
下面是根据您的代码修改的示例:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
from matplotlib import style
import matplotlib
matplotlib.use("Agg")
root = tk.Tk()
root.title("Graph")
#root.geometry("800x400")
# progress label, pause and resume buttons
frame = tk.Frame(root)
frame.pack(fill="x", side=tk.TOP)
progress = tk.Label(frame)
progress.pack(side="left")
is_paused = tk.BooleanVar() # variable to hold the pause/resume state
tk.Button(frame, text="Pause", command=lambda: is_paused.set(True)).pack(side="right")
tk.Button(frame, text="Resume", command=lambda: is_paused.set(False)).pack(side="right")
# the plot
fig = plt.figure(figsize=(10, 5), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root)
toolbar = NavigationToolbar2Tk(canvas, root)
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.grid("both")
style.use("ggplot")
a = 1
ax1 = plt.subplot(111)
line1, = ax1.plot([0], [0])
def func_A(a, x):
import numpy
data_x = numpy.arange(0, x)
data_y = a * numpy.sin(data_x/5)
return data_x, data_y
# function to update ploat
def update_plot(k=0):
if not is_paused.get():
progress["text"] = f"iteration: {k}"
data_x, data_y = func_A(a, k)
#print("iteration", k)
#print("data_x", data_x)
#print("data_y", data_y)
line1.set_xdata(data_x)
line1.set_ydata(data_y)
ax1.set_ylim([-1, 1])
ax1.set_xlim([0, 100])
plt.grid("both")
canvas.draw()
canvas.flush_events()
k += 1
if k <= 100:
# update plot again after 10ms. You can change the delay to whatever you want
root.after(10, update_plot, k)
update_plot() # start updating plot
root.mainloop()