如何在其他函数执行完毕后调用tkinter中的函数?

2024-03-29 07:12:42 发布

您现在位置:Python中文网/ 问答频道 /正文

你好

我知道事件驱动编程与“传统编程”有很大的不同,传统编程是由程序按顺序执行指令。但是,我对它还不熟悉,我不完全理解事件驱动编程是如何工作的,我认为这就是我在这里遇到问题的原因。你知道吗

我根据这篇文章的答案构建了一个例子:tkinter progress bar won't update when called from an other app

在本例中,我希望我的程序在完成对给定路径的扫描后执行一个操作。天真地,我尝试在调用walk之后添加对action例程的调用:

import sys
import os
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.filedialog import askdirectory

class App(ttk.Frame):
    def __init__(self, parent, title):
        #tk.Frame.__init__(self, parent)
        super(App, self).__init__(parent)
        parent.wm_withdraw()
        parent.wm_title(title)
        self.create_ui()
        self.grid(sticky = "news")
        parent.wm_protocol("WM_DELETE_WINDOW", self.on_destroy)
        parent.grid_rowconfigure(0, weight=1)
        parent.grid_columnconfigure(0, weight=1)
        parent.wm_deiconify()

    def create_ui(self):
        textframe = ttk.Frame(self)
        self.text = text = tk.Text(textframe)
        vs = ttk.Scrollbar(textframe, orient=tk.VERTICAL, command=text.yview)
        text.configure(yscrollcommand=vs.set)
        text.grid(row=0, column=0, sticky=tk.NSEW)
        vs.grid(row=0, column=1, sticky=tk.NS)

        textframe.grid_columnconfigure(0, weight=1)
        textframe.grid_rowconfigure(0, weight=1)
        textframe.grid(row=0, column=0, columnspan=2, sticky=tk.NSEW)
        self.progressvar = tk.IntVar()
        self.progress = ttk.Progressbar(self, variable=self.progressvar)
        test_button = ttk.Button(self, text="Walk", command=self.on_walk)
        exit_button = ttk.Button(self, text="Exit", command=self.on_destroy)
        self.progress.grid(row=1, column=0, sticky=tk.NSEW)
        test_button.grid(row=1, column=0, sticky=tk.SE)
        exit_button.grid(row=1, column=1, sticky=tk.SE)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

    def on_destroy(self):
        self.master.destroy()

    def on_walk(self):
        root = askdirectory()
        self.walk(root)
        self.action()

    def walk(self, root=None):
        if root:
            # this is potentially costly, but how to find the number of files to be examined?
            count = sum([len(files) for (root,dirs,files) in os.walk(root)])
            self.text.delete("1.0", "end")
            self.progress.configure(maximum=count)
            self.progressvar.set(0)
            walker = os.walk(root)
            self.after(100, self.do_one, walker)

    def do_one(self, walker):
        try:
            root,dirs,files = next(walker)
            for file in files:
                self.text.insert(tk.END, os.path.join(root, file), "PATH", "\n", "")
                self.text.see(tk.END)
                self.progressvar.set(self.progressvar.get() + 1)
            self.after(10, self.do_one, walker)
        except StopIteration:
            pass

    def action(self):
        print('DO SOMETHING HERE, AFTER WALK HAS FINISHED\n')

这样,在walk调用结束之前调用action函数。你知道吗

我通过在do_one函数中的异常之后调用action找到了一个解决方法:

def do_one(self, walker):
    try:
        root,dirs,files = next(walker)
        for file in files:
            self.text.insert(tk.END, os.path.join(root, file), "PATH", "\n", "")
            self.text.see(tk.END)
            self.progressvar.set(self.progressvar.get() + 1)
        self.after(10, self.do_one, walker)
    except StopIteration:
        self.action()

我想有更好的办法。有没有办法创建一个事件,告诉程序walk执行的任务已经完成了?你知道吗

谢谢


Tags: textselfdefactionrootfilestkgrid