我正在尝试将进度条连接到我的项目的功能.
这是我到目前为止,但我很确定它什么都不做:
def main():
pgBar.start()
function1()
function2()
function3()
function4()
pgBar.stop()
Run Code Online (Sandbox Code Playgroud)
以下是我创建进度条的代码,如果有帮助的话:
pgBar = ttk.Progressbar(window, orient = HORIZONTAL, length=300, mode = "determinate")
pgBar.place(x=45, y=130)
Run Code Online (Sandbox Code Playgroud)
我一直在做一些研究,并了解tkinter窗口在运行函数或类似的东西时冻结.有没有办法在主要内部调用的每个函数的末尾"解冻"窗口?
A. *_*das 18
由于tkinter是单线程的,因此您需要另一个线程来执行您的main函数而不会冻结GUI.一种常见的方法是工作线程将消息放入同步对象(如a Queue),GUI部分使用此消息,更新进度条.
以下代码基于ActiveState 的完整详细示例:
import tkinter as tk
from tkinter import ttk
import threading
import queue
import time
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.queue = queue.Queue()
self.listbox = tk.Listbox(self, width=20, height=5)
self.progressbar = ttk.Progressbar(self, orient='horizontal',
length=300, mode='determinate')
self.button = tk.Button(self, text="Start", command=self.spawnthread)
self.listbox.pack(padx=10, pady=10)
self.progressbar.pack(padx=10, pady=10)
self.button.pack(padx=10, pady=10)
def spawnthread(self):
self.button.config(state="disabled")
self.thread = ThreadedClient(self.queue)
self.thread.start()
self.periodiccall()
def periodiccall(self):
self.checkqueue()
if self.thread.is_alive():
self.after(100, self.periodiccall)
else:
self.button.config(state="active")
def checkqueue(self):
while self.queue.qsize():
try:
msg = self.queue.get(0)
self.listbox.insert('end', msg)
self.progressbar.step(25)
except Queue.Empty:
pass
class ThreadedClient(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
for x in range(1, 5):
time.sleep(2)
msg = "Function %s finished..." % x
self.queue.put(msg)
if __name__ == "__main__":
app = App()
app.mainloop()
Run Code Online (Sandbox Code Playgroud)
由于ActiveState上的原始示例有点凌乱IMO(ThreadedClient与之相配GuiPart,并且控制从GUI生成线程的时刻并不像它们那样简单),我已经重构了它并且还添加了一个用于启动新线程的按钮.
Hon*_*Abe 14
要理解你需要理解的"冻结" mainloop().调用此方法将启动tkinter事件循环.主线程负责此循环.因此,当您的工作密集型函数在主线程中运行时,它也会干扰主循环.为防止这种情况,您可以使用辅助Thread功能来运行您的功能.建议不要让辅助线程访问tkinter对象.艾伦B.Taylor,作者mtTkinter,指出:
问题源于_tkinter模块在处理来自其他线程的调用时尝试通过轮询技术获得对主线程的控制.如果成功,一切都很顺利.如果失败(即超时后),应用程序将收到一条异常,并显示以下消息:"RuntimeError:主线程不在主循环中".
您可以将辅助线程放入信息中Queue.然后有一个函数,通过该方法在mainloop中每隔x毫秒检查一次Queue.after()
首先,确定您希望Progressbar的最大选项的值是什么.
这是Progressbar的最大指标值(填充Progressbar需要多少单位).例如,您可以maximum=4在四个函数中的每个函数之后设置然后将适当的指标值放入队列中.然后主线程可以检索这些值(从队列中)以通过a设置进度tkinter.IntVar().(请注意,如果使用progbar.step(),则Progressbar会在结尾处重置为0(空),而不是达到4(完全填充).)
以下是快速了解如何使用tkinter.IntVar()进度条:
int_var = tkinter.IntVar()
pb_instance = ttk.Progressbar(root, maximum=4)
pb_instance['variable'] = int_var
pb_instance.pack()
# completely fill the Progressbar
int_var.set(4)
# get the progress value
x = int_var.get()
Run Code Online (Sandbox Code Playgroud)
这是一个基于您自己的示例(重命名为"main"函数"任意"):
import time
import threading
try: import tkinter
except ImportError:
import Tkinter as tkinter
import ttk
import Queue as queue
else:
from tkinter import ttk
import queue
class GUI_Core(object):
def __init__(self):
self.root = tkinter.Tk()
self.int_var = tkinter.IntVar()
progbar = ttk.Progressbar(self.root, maximum=4)
# associate self.int_var with the progress value
progbar['variable'] = self.int_var
progbar.pack()
self.label = ttk.Label(self.root, text='0/4')
self.label.pack()
self.b_start = ttk.Button(self.root, text='Start')
self.b_start['command'] = self.start_thread
self.b_start.pack()
def start_thread(self):
self.b_start['state'] = 'disable'
self.int_var.set(0) # empty the Progressbar
self.label['text'] = '0/4'
# create then start a secondary thread to run arbitrary()
self.secondary_thread = threading.Thread(target=arbitrary)
self.secondary_thread.start()
# check the Queue in 50ms
self.root.after(50, self.check_que)
def check_que(self):
while True:
try: x = que.get_nowait()
except queue.Empty:
self.root.after(25, self.check_que)
break
else: # continue from the try suite
self.label['text'] = '{}/4'.format(x)
self.int_var.set(x)
if x == 4:
self.b_start['state'] = 'normal'
break
def func_a():
time.sleep(1) # simulate some work
def func_b():
time.sleep(0.3)
def func_c():
time.sleep(0.9)
def func_d():
time.sleep(0.6)
def arbitrary():
func_a()
que.put(1)
func_b()
que.put(2)
func_c()
que.put(3)
func_d()
que.put(4)
que = queue.Queue()
gui = GUI_Core() # see GUI_Core's __init__ method
gui.root.mainloop()
Run Code Online (Sandbox Code Playgroud)
如果你想要的只是向用户表明存在活动的东西,
你可以将进度条的模式选项设置为'indeterminate'.
指示器在此模式下来回反弹(速度与最大选项有关).
然后你可以start()在启动辅助线程之前直接调用Progressbar的方法;
然后stop()在secondary_thread.is_alive()返回False后调用.
这是一个例子:
import time
import threading
try: import tkinter
except ImportError:
import Tkinter as tkinter
import ttk
else: from tkinter import ttk
class GUI_Core(object):
def __init__(self):
self.root = tkinter.Tk()
self.progbar = ttk.Progressbar(self.root)
self.progbar.config(maximum=4, mode='indeterminate')
self.progbar.pack()
self.b_start = ttk.Button(self.root, text='Start')
self.b_start['command'] = self.start_thread
self.b_start.pack()
def start_thread(self):
self.b_start['state'] = 'disable'
self.progbar.start()
self.secondary_thread = threading.Thread(target=arbitrary)
self.secondary_thread.start()
self.root.after(50, self.check_thread)
def check_thread(self):
if self.secondary_thread.is_alive():
self.root.after(50, self.check_thread)
else:
self.progbar.stop()
self.b_start['state'] = 'normal'
def func_a():
time.sleep(1) # simulate some work
def func_b():
time.sleep(0.3)
def func_c():
time.sleep(0.9)
def func_d():
time.sleep(0.6)
def arbitrary():
func_a()
func_b()
func_c()
func_d()
gui = GUI_Core()
gui.root.mainloop()
Run Code Online (Sandbox Code Playgroud)
→ 进度条参考
| 归档时间: |
|
| 查看次数: |
20278 次 |
| 最近记录: |