我目前正在使用一个GUI,用户在其中输入数据并单击一个按钮以运行绘制画布的功能。
绘制画布的功能大约需要1分钟才能运行,在那几秒钟中,GUI会冻结。
因此,在这几秒钟中,我想显示一个页面,要求用户等待(例如带有动画gif的页面)。
这是我正在使用的代码(我已经用一个带有time.sleep的简单案例替换了绘制Graph的代码):
import tkinter as tk
from tkinter import ttk
import threading
from PIL import Image, ImageTk
TITTLE_FONT = ("Verdana", 30)
LARGE_FONT= ("Verdana", 16)
NORM_FONT = ("Helvetica", 10)
SMALL_FONT = ("Helvetica", 8)
style.use("ggplot")
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.shared_data = {
"x1": tk.StringVar(),
"x2": tk.StringVar(),
"x3": tk.StringVar()}
tk.Tk.wm_title(self, "Titre")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
#Menu
menubar = tk.Menu(container)
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label="Exit", command=self.destroy)
menubar.add_cascade(label="File", menu=filemenu)
tk.Tk.config(self, menu=menubar)
self.frames = {}
for F in (StartPage, PageGraph, WaitingPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def get_page(self, page_class):
return self.frames[page_class]
class WaitingPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller=controller
label1 = tk.Label(self, text="Calculs en cours", font=TITTLE_FONT)
label1.pack()
label2 = tk.Label(self, text="Veuillez Patienter", font=LARGE_FONT)
label2.pack()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
self.controller=controller
label = tk.Label(self, text="Page d'acceuil", font=LARGE_FONT)
label.pack(pady=10,padx=10)
#---------- Boutton pour switcher sur la "Page du graph"
button = ttk.Button(self, text="Page du Graph",
command=lambda: controller.show_frame(PageGraph))
button.pack()
label1 = ttk.Label(self, text="X1", font=NORM_FONT)
label1.pack(pady=10,padx=10)
self.entry1 = tk.Entry(self, textvariable=self.controller.shared_data["x1"])
self.entry1.pack(pady=10,padx=10)
label2 = ttk.Label(self, text="X2", font=NORM_FONT)
label2.pack(pady=10,padx=10)
self.entry2 = tk.Entry(self, textvariable=self.controller.shared_data["x2"])
self.entry2.pack(pady=10,padx=10)
label3 = ttk.Label(self, text="X3", font=NORM_FONT)
label3.pack(pady=10,padx=10)
self.entry3 = tk.Entry(self, textvariable=self.controller.shared_data["x3"])
self.entry3.pack(pady=10,padx=10)
button2 = ttk.Button(self, text="Valider", command=self.do_button)
button2.pack()
def do_button(self):
page = self.controller.get_page(PageGraph)
page.Graph()
class PageGraph(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller=controller
label = tk.Label(self, text="Graph Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Back to Home",command=lambda: controller.show_frame(StartPage))
button1.pack()
# ---------- Création du canvas vide
self.f = Figure()
self.a = self.f.add_subplot(111)
self.canvas = FigureCanvasTkAgg(self.f, self)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
self.toolbar = NavigationToolbar2Tk(self.canvas, self)
self.toolbar.update()
self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
def Graph(self):
self.controller.show_frame(WaitingPage)
def real_Graph() :
time.sleep(5)
x1 = float(self.controller.shared_data["x1"].get())
x2 = float(self.controller.shared_data["x2"].get())
x3 = float(self.controller.shared_data["x3"].get())
xAxis = [float(x1),float(x2),float(x3)]
yAxis = [float(x1),float(x2),float(x3)]
return (xAxis , yAxis)
threadGraph = threading.Thread(target=real_Graph)
threadGraph.start()
#############################################
######### Retrieve xAxis and yAxis ?#########
#############################################
self.toolbar.update()
self.a.clear()
self.a.bar(xAxis,yAxis)
self.canvas.draw()
self.controller.show_frame(PageGraph)
app = GUI()
app.geometry("1280x720")
app.mainloop()
在Graph函数中:想法是在另一个线程中运行long计算,然后检索数据以绘制图形。
因此,我的问题是:如何检索在另一个线程中运行的函数返回的内容(此处为xAxis和yAxis)? (此处为real_Graph函数)
答案 0 :(得分:1)
由于无法在其他线程中更新图形,因此可以使用threads
定期检查是否要在主线程中更新图形:
tkinter.after(...)
答案 1 :(得分:0)
我希望这会对您有所帮助。您需要更改此部分:
threadGraph = threading.Thread(target=real_Graph)
threadGraph.start()
要
Threads = []
threadGraph = threading.Thread(target=real_Graph)
Threads.append(threadGraph)
threadGraph.start()
for t in Threads:
print(t.join())
答案 2 :(得分:0)
在real_Graph
函数中完成计算后,为什么不直接绘制图形呢?
def Graph(self):
def real_Graph():
time.sleep(5)
x1 = float(self.controller.shared_data["x1"].get())
x2 = float(self.controller.shared_data["x2"].get())
x3 = float(self.controller.shared_data["x3"].get())
xAxis = [float(x1),float(x2),float(x3)]
yAxis = [float(x1),float(x2),float(x3)]
self.toolbar.update()
self.a.clear()
self.a.bar(xAxis, yAxis)
self.canvas.draw()
self.controller.show_frame(PageGraph)
threadGraph = threading.Thread(target=real_Graph)
threadGraph.start()