【问题标题】:Indeterminate Progress bar while function is running功能运行时不确定的进度条
【发布时间】:2018-05-25 09:56:09
【问题描述】:

我有一个 GUI,它有两个按钮和一个堆叠在单列上的进度条。每个按钮调用一个不同的函数,这需要一些时间来执行。我希望进度条在有人单击两个按钮中的任何一个时移动并继续移动(不确定地)直到功能完成然后停止。我知道我需要使用多线程,但我似乎无法正确编写代码!

代码

from tkinter import Tk
import time 
from tkinter import *
from tkinter import Button
from tkinter import Frame
from tkinter import ttk
import threading


def sample_function():
    time.sleep(2)  # SAMPLE FUNCTION BEING CALLED

def prepare_clicked():
    sample_function()  

def social_clicked():

    sample_function()

def anomaly_clicked():
    sample_function()             



window = Toplevel() # Tried using Tk but I am using image to design each buttons through the button config in my actual code and tk throws error
topFrame = Frame(window)
topFrame.pack()

prepare_btn = Button(topFrame, command=prepare_clicked,text='Button1')
anomaly_btn = Button(topFrame,command=anomaly_clicked,text='Button2')
social_btn = Button(topFrame, command=social_clicked,text='Button3')
processing_bar = ttk.Progressbar(topFrame, orient='horizontal', mode='indeterminate')



window.rowconfigure((0,1), weight=1)  # make buttons stretch when
window.columnconfigure((0,3), weight=1)  # when window is resized
prepare_btn.grid(row=0, column=1, columnspan=1, sticky='EWNS')
anomaly_btn.grid(row=1, column=1, columnspan=1, sticky='EWNS')
social_btn.grid(row=2, column=1, columnspan=1, sticky='EWNS')
processing_bar.grid(row=3, column=1, columnspan=1, sticky='EWNS')


window.mainloop()

【问题讨论】:

  • 如果没有看到一些代码很难说,最好是minimal reproducible example(您可以使用调用time.sleep 的“虚拟”函数来模拟需要时间执行的函数)。 Tkinter 和线程的主要内容是 Tkinter 喜欢在主线程中,否则可能无法很好地发挥作用。
  • @PM2Ring 我添加了一个示例代码。请检查您是否可以提供帮助。
  • 我有点担心您在使用图像按钮时遇到问题。 This answer 可能对此有所帮助,但如果没有,那么您应该提出一个新问题(使用它自己的 MCVE)。

标签: python python-3.x tkinter


【解决方案1】:

我已在您的代码中添加了线程。我假设您不希望在功能进行时任何按钮都是可按下的。如果你不需要它,只需去掉 run_function 中的 for 循环,它会更改 btn['state']。我还修复了行和列配置代码,以便在用户调整窗口大小时小部件展开和收缩。我摆脱了evil "star" import

import tkinter as tk
from tkinter import ttk
import time
from threading import Thread

def sample_function():
    time.sleep(2)

def run_function(name, func):
    # Disable all buttons
    for btn in buttons:
        btn['state'] = 'disabled'

    processing_bar.start(interval=10)
    print(name, 'started')
    func()
    processing_bar.stop()
    print(name, 'stopped')

    # Enable all buttons
    for btn in buttons:
        btn['state'] = 'normal'

def run_thread(name, func):
    Thread(target=run_function, args=(name, func)).start()

def prepare_clicked():
    run_thread('prepare', sample_function)

def social_clicked():
    run_thread('social', sample_function)

def anomaly_clicked():
    run_thread('anomaly', sample_function)


window = tk.Tk()
#window = tk.Toplevel()

topFrame = tk.Frame(window)

# Tell the Frame to fill the whole window
topFrame.pack(fill=tk.BOTH, expand=1)

# Make the Frame grid contents expand & contract with the window
topFrame.columnconfigure(0, weight=1)
for i in range(4):
    topFrame.rowconfigure(i, weight=1)

prepare_btn = tk.Button(topFrame, command=prepare_clicked, text='Button1')
anomaly_btn = tk.Button(topFrame,command=anomaly_clicked, text='Button2')
social_btn = tk.Button(topFrame, command=social_clicked, text='Button3')
buttons = [prepare_btn, anomaly_btn, social_btn]

processing_bar = ttk.Progressbar(topFrame, orient='horizontal', mode='indeterminate')

prepare_btn.grid(row=0, column=0, columnspan=1, sticky='EWNS')
anomaly_btn.grid(row=1, column=0, columnspan=1, sticky='EWNS')
social_btn.grid(row=2, column=0, columnspan=1, sticky='EWNS')
processing_bar.grid(row=3, column=0, columnspan=1, sticky='EWNS')

window.mainloop()

更新

这是新的改进版本,带有一个“全部”按钮,可以按顺序运行所有功能。享受吧!

import tkinter as tk
from tkinter import ttk
import time
from threading import Thread

def prepare_func():
    print('prepare started')
    time.sleep(2)
    print('prepare stopped')

def anomaly_func():
    print('anomaly started')
    time.sleep(2)
    print('anomaly stopped')

def social_func():
    print('social started')
    time.sleep(2)
    print('social stopped')

def all_func():
    print('all started')
    show_and_run(prepare_func, buttons['Prepare'])
    show_and_run(anomaly_func, buttons['Anomaly'])
    show_and_run(social_func, buttons['Social'])
    print('all stopped')

def show_and_run(func, btn):
    # Save current button color and change it to green
    oldcolor = btn['bg']
    btn['bg'] = 'green'

    # Call the function
    func()

    # Restore original button color
    btn['bg'] = oldcolor

def run_function(func, btn):
    # Disable all buttons
    for b in buttons.values():
        b['state'] = 'disabled'

    processing_bar.start(interval=10)
    show_and_run(func, btn)
    processing_bar.stop()

    # Enable all buttons
    for b in buttons.values():
        b['state'] = 'normal'

def clicked(func, btn):
    Thread(target=run_function, args=(func, btn)).start()

window = tk.Tk()
#window = tk.Toplevel()

topFrame = tk.Frame(window)

# Tell the Frame to fill the whole window
topFrame.pack(fill=tk.BOTH, expand=1)

# Make the Frame grid contents expand & contract with the window
topFrame.columnconfigure(0, weight=1)
for i in range(4):
    topFrame.rowconfigure(i, weight=1)

button_data = (
    ('Prepare', prepare_func),
    ('Anomaly', anomaly_func),
    ('Social', social_func),
    ('All', all_func),
)

# Make all the buttons and save them in a dict
buttons = {}
for row, (name, func) in enumerate(button_data):
    btn = tk.Button(topFrame, text=name)
    btn.config(command=lambda f=func, b=btn: clicked(f, b))
    btn.grid(row=row, column=0, columnspan=1, sticky='EWNS')
    buttons[name] = btn
row += 1

processing_bar = ttk.Progressbar(topFrame, 
    orient='horizontal', mode='indeterminate')
processing_bar.grid(row=row, column=0, columnspan=1, sticky='EWNS')

window.mainloop()

【讨论】:

  • 谢谢。这就是我一直在寻找的!我还有一个要求。如果我想使用新按钮“CALL ALL”自动调用单个函数,然后它将调用所有其他函数,但按顺序调用,即。在执行下一个按钮之前等待上一个按钮的第一个功能完成,我将如何完成此操作?
  • 是的。但是各个线程必须按按钮顺序排列,而不是同时!谢谢
  • 我想我没有清楚地表达我的要求。我的任务是拥有我制作的 3 个按钮,它们调用一些功能,并且有一个不断移动的进度条。现在,我必须通过一个按钮自动单击上述三个按钮。即上述三个函数的调用应该自动发生,在 GUI 中可以看到“单击每个按钮”。我打算为按钮文本添加颜色以显示单击之前、期间和之后的过程变化。我需要“全部”按钮来实现应用程序本身的“自动演示”。
  • @ALEXMATHEW 我已经用最新版本更新了我的答案。
  • 谢谢!这就是我所需要的。你太棒了!
猜你喜欢
  • 1970-01-01
  • 2013-09-24
  • 1970-01-01
  • 2021-11-21
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
  • 2013-09-22
  • 1970-01-01
相关资源
最近更新 更多