我用 Tkinter 制作了一個 GUI Python 程式。我使用“from tkinter.ttk import Progressbar”制作了一個進度條。當我按下一個按鈕時,我會應用一個函式來做某事并回傳一個布林值。我需要進度條一直運行到該函式結束行程,然后它會停止。
from tkinter.ttk import Progressbar
import time
import threading
wheel_flag = False
root = tk.Tk()
wheel = Progressbar(row,orient=HORIZONTAL,length=100,mode="indeterminate")
def btn_function()
loading_function = threading.Thread(target=start_loading)
loading_function.start()
boolean_wheel = threading.Thread(target=some_function, args = (x,y)) #"some_function" returns a boolean value
boolean_wheel.start()
while True:
if not boolean_wheel.is_alive():
break
wheel_flag = True
def start_loading():
while True:
global wheel_flag
wheel['value'] = 10
root.update_idletasks()
time.sleep(0.5)
if wheel_flag:
break
這里我沒有得到 boolean_wheel 值,但我想檢查它是真還是假,如果函式成功與否,發送給用戶訊息。
我希望當應用“btn_function”時,進度條將開始加載,直到“some_function”完成運行。現在我得到的結果是加載僅在“some_function”完成后開始,并且在我關閉程式之前一直運行。
uj5u.com熱心網友回復:
我會使用root.after(millisecond, function)而不是while True-loop 來運行progressbar每隔幾秒更新一次的函式。我會直接boolean_wheel.is_alive()在這個函式中使用來停止更新。
import tkinter as tk
from tkinter import ttk
import time
import threading
# --- functions ---
def some_function(x, y):
time.sleep(10)
def btn_function():
x = 100
y = 100
boolean_wheel = threading.Thread(target=some_function, args=(x,y))
boolean_wheel.start()
# block button
button['state'] = 'disabled'
# show progressbar
wheel.grid(row=0, column=1)
# start updating progressbar
update_progressbar(boolean_wheel) # send thread as parameter - so it doesn't need `global`
def update_progressbar(thread):
if thread.is_alive():
# update progressbar
wheel['value'] = 10
# check again after 250ms (0.25s)
root.after(250, update_progressbar, thread)
else:
# hide progressbar
wheel.grid_forget()
# unblock button
button['state'] = 'normal'
# --- main ---
root = tk.Tk()
wheel = ttk.Progressbar(root, orient='horizontal', length=100, mode="indeterminate")
#wheel.grid(row=0, column=1) # don't show
button = tk.Button(root, text='Start', command=btn_function)
button.grid(row=0, column=0)
root.mainloop()
編輯:
如果您將小部件作為引數發送到函式,那么您可以為許多進度條運行它
import tkinter as tk
from tkinter import ttk
import time
import threading
# --- functions ---
def some_function(x, y):
time.sleep(10)
def btn_function(row, button, progressbar):
x = 100
y = 100
boolean_wheel = threading.Thread(target=some_function, args=(x,y))
boolean_wheel.start()
start_loading(row, button, progressbar, boolean_wheel)
def start_loading(row, button, progressbar, thread):
# block button
button['state'] = 'disabled'
# show progressbar
progressbar.grid(row=row, column=1)
# start updating progressbar
update_progressbar(button, progressbar, thread) # send thread as parameter - so it doesn't need `global`
def update_progressbar(button, progressbar, thread):
if thread.is_alive():
# update progressbar
progressbar['value'] = 10
# check again after 250ms (0.25s)
root.after(250, update_progressbar, button, progressbar, thread)
else:
end_loading(button, progressbar)
def end_loading(button, progressbar):
# hide progressbar
progressbar.grid_forget()
# unblock button
button['state'] = 'normal'
# --- main ---
root = tk.Tk()
# ---
wheel1 = ttk.Progressbar(root, orient='horizontal', length=100, mode="indeterminate")
#wheel.grid(row=1, column=1) # don't show
button1 = tk.Button(root, text='Start')
button1.grid(row=1, column=0)
button1['command'] = lambda:btn_function(1, button1, wheel1) # need to assign after creating button - to send button to function
# ---
wheel2 = ttk.Progressbar(root, orient='horizontal', length=100, mode="indeterminate")
#wheel2.grid(row=2, column=1) # don't show
button2 = tk.Button(root, text='Start')
button2.grid(row=2, column=0)
button2['command'] = lambda:btn_function(2, button2, wheel2) # need to assign after creating button - to send button to function
# ---
root.mainloop()

我什至會將它放入Frame并創建自己的小部件以使用-loopclass MyProgress(tk.Frame)創建許多小部件for

import tkinter as tk
from tkinter import ttk
import time
import threading
# --- classes ---
class MyProgrees(tk.Frame):
def __init__(self, master, target_function, target_args, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.target_function = target_function
self.target_args = target_args
self.progressbar = ttk.Progressbar(self, orient='horizontal', length=100, mode="indeterminate")
#self.progressbar.grid(row=0, column=1) # don't show
self.button = tk.Button(self, text='Start', command=self.on_press_button)
self.button.grid(row=0, column=0)
def on_press_button(self):
self.thread = threading.Thread(target=self.target_function, args=self.target_args)
self.thread.start()
self.start_loading()
def start_loading(self):
# block button
self.button['state'] = 'disabled'
# show progressbar
self.progressbar.grid(row=0, column=1)
# start updating progressbar
self.update_progressbar()
def update_progressbar(self):
if self.thread.is_alive():
# update progressbar
self.progressbar['value'] = 10
# check again after 250ms (0.25s)
self.after(250, self.update_progressbar)
else:
self.end_loading()
def end_loading(self):
# hide progressbar
self.progressbar.grid_forget()
# unblock button
self.button['state'] = 'normal'
# --- functions ---
def some_function(x, y):
time.sleep(10)
# --- main ---
root = tk.Tk()
# ---
x = 100
y = 100
for _ in range(10):
widget = MyProgrees(root, some_function, (x, y))
widget.pack(fill='x', expand=True)
# ---
root.mainloop()
uj5u.com熱心網友回復:
正確的解決方案是洗掉回圈,btn_function而是在完成后some_function設定wheel_flag。
def some_function_wrapper(*args,**kwargs):
global wheel_flag
some_function(*args,**kwargs)
wheel_flag = True
并呼叫它而不是some_function在你的執行緒中。
btn_function現在另一種解決方案是在另一個執行緒中運行整個程序,方法是添加
command= lambda : threading.Thread(target=btn_function).start()
在您的按鈕定義中,但嵌套執行緒有時變得難以跟蹤。
編輯:它有效。我檢查了該函式內的函式值
def some_function_wrapper(*args,**kwargs):
global wheel_flag
check = some_function(*args,**kwargs)
if check:
print("works")
else:
print("don't work")
wheel_flag = True
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/520167.html
標籤:Python用户界面tkinterpython-多线程
上一篇:根據ID將表中的資料提取到輸入框
