当前位置: 首页 > 知识库问答 >
问题:

如何将进度条连接到函数?

颛孙兴旺
2023-03-14

我正在尝试将进度条连接到我的项目的函数。

到目前为止,这就是我所拥有的,但我很确定它毫无用处:

def main():
    pgBar.start()
    function1()
    function2()
    function3()
    function4()
    pgBar.stop()

下面是我制作进度条的代码,如果有帮助的话:

pgBar = ttk.Progressbar(window, orient = HORIZONTAL, length=300, mode = "determinate")
pgBar.place(x=45, y=130)

我做了一些研究,了解到tkinter窗口在运行函数或类似的东西时会冻结。有没有办法在主函数中调用的每个函数末尾“解冻”窗口?

共有3个答案

袁鸿达
2023-03-14

您必须使用:self。pgBar。步骤(x)其中“x”是progressbar中要增加的金额。要在UI中更新,您必须将self。窗每次self后更新_idletasks()。pgBar。步骤(x)语句

祝宾白
2023-03-14

要理解冻结,您需要了解main循环()。调用此方法将启动tkinter事件循环。主线程负责这个循环。因此,当你的工作密集型函数在主线程中运行时,它也在干扰主循环。为了防止这种情况,你可以使用一个辅助的Thread来运行你的函数。建议不允许次要线程访问tkinter对象。mtTkinter的作者Allen B. Taylor表示:

问题源于这样一个事实,即当处理来自其他线程的调用时,\ u tkinter模块试图通过轮询技术获得对主线程的控制。如果成功了,一切都很好。如果失败(即,在超时之后),应用程序将收到一条异常消息:“RuntimeError:主线程不在主循环中”。

您可以让辅助线程将信息放入Queue中。然后有一个函数,该函数在主循环中每x毫秒检查一次队列,方法是在()之后使用方法。

首先,确定您希望Progressbar的最大选项的值是多少
这是Progressbar的最大指示器值(填充Progressbar需要多少个单位)。例如,您可以设置maximum=4,然后在四个函数中的每个函数之后将适当的指示符值放入队列。然后,主线程可以(从队列中)检索这些值,通过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()

下面是一个基于您自己的示例(将“main”函数重命名为“arbitral”):

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()

如果您想要的是向用户指示有活动的东西,您可以将Progressbar的模式选项设置为“不确定”。
指示器在这种模式下来回跳动(速度与最大选项有关)。

然后可以在启动次线程之前直接调用Progressbar的start()方法
然后在次线程之后调用stop()。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()

→Progressbar参考

翟冷勋
2023-03-14

由于tkinter是单线程的,因此需要另一个线程来执行main函数,而不冻结GUI。一种常见的方法是,工作线程将消息放入一个同步对象(如队列),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()

由于ActiveState上的原始示例在IMO上有点混乱(ThreadedClient与guPart非常耦合,并且像控制从GUI生成线程的时刻这样的事情并不像它们可能的那样简单),我已经重构了它,并添加了一个按钮来启动新线程。

 类似资料:
  • 问题内容: 关于此问题,有什么方法可以将[文件从ASP.NET应用程序直接上传到Amazon S3并具有进度条? -—编辑---- 两天后,仍然没有直接的运气。发现了一件看起来很有前途但又不是免费的东西:http : //www.flajaxian.com/ 使用Flash通过进度条直接上传到S3。 问题答案: 我也在寻找解决方案。也许这会有所帮助, 来自AWS Dev Commnity, 但在许

  • 我正在尝试将 kafka 与 windows 上的 mysql 连接起来。我没有使用汇合。我的 kafka 版本是 2.12 我已经启动了动物园管理员、Kafka、生产者和消费者,这一切都很好用。 我的MysQL版本是8.0.15 我已经在libs文件夹中复制了这3个jar文件 我的源代码quickstart mysql。属性文件代码为 当我运行命令时 我在控制台上收到此错误 请帮助我。 我也试过

  • 问题内容: 我的Java程序出现这些错误。我已经把我的类路径放在里面了。如何解决呢? 代码: 问题答案: 您需要从下载MySQL包:这里并将其放置在库中,我将修改在少数分钟excact步骤 这是连接数据库的正确语法: 希望这可以帮助

  • 我在我的运行系统中有MongoDB和Robomongo,我使用Robomongo作为客户端。 我已将MongoDB安装在另一个系统上,我将其视为服务器,我想将我系统的Robomongo(作为客户端)连接到另一个系统(服务器)上的MongoDB。我应该采取哪些步骤来实现同样的目标? 我使用的是机器名,因为系统的IP地址不是静态的。但即使我使用系统的IP地址,我也会遇到同样的错误: 连接失败,无法连接

  • 我正在尝试将node.js连接到MySQL,但失败了。我已经安装了MySQL和相关库。如何解决此错误?另外,如果我想让数据响应为原生的,我应该如何去做呢? 收到的错误消息:

  • 问题内容: 如何在html / css /javascript中制作进度条。我真的不想使用Flash。在这里可以找到类似的东西 我真正想要的只是一个“进度条”,它可以更改我在PHP中提供的值。您会如何处理?有什么好的教程吗? 问题答案: 您可以通过css控制div的宽度来实现。大致遵循以下原则: 如果您愿意,可以从php发送该宽度值。