如何在函数完成前让tk显示某些内容

0 投票
2 回答
1106 浏览
提问于 2025-04-17 22:29

我有一段代码,它可以从网上的列表中下载指定的文件。在下载的过程中,会显示一个加载界面,里面有一个标签告诉用户正在下载哪个文件,还有一个进度条,表示正在进行中。下载的功能运行得很好,但问题是tkinter(一个用来做图形界面的库)在下载完成之前都不显示任何东西,只在最后才显示“下载完成”的标签。我想知道怎么才能让tkinter在函数执行完之前就显示窗口。

我已经尝试过:

  • 把代码拆分成多个函数

  • 添加一个sleep函数,看看减慢速度是否有帮助

为了说明我所说的,我用一些示例替换了原来的代码。有没有人知道怎么让tkinter更积极地更新(在函数完成之前)?

#Imports
import urllib.request as ur
import os
from tkinter import *
import tkinter.ttk as ttk
import time as T

#Globals
tk = None
where = None
progressbar = None
progresstitle = None
progressinfo = None
transfer = None

#Make sure that the download directory exists
def checkdir(filename):
    directory = os.path.dirname(filename)
    try:
        os.stat(directory)
    except:
        os.mkdir(directory)  

#First part (read q to see why I split up)
def part1():
    #Get Globals
    global tk
    global where
    global progressbar
    global progresstitle
    global progressinfo
    global transfer

    #Create Window
    tk = Tk()
    tk.title("Downloading...")

    #Find out the location of the online files to download by reading the online txt file which contains their locations
    where = str(ur.urlopen("http://example.com/whatfilestodownload.txt").read())
    where = where[2:(len(where)-1)]
    where = where.split(";")
    #Create the progress bar
    progressbar = ttk.Progressbar(tk, orient=HORIZONTAL, length=200, mode='indeterminate')
    progressbar.grid(row = 2, column = 0)
    #Create the labels
    progresstitle = Label(tk, text = "Downloading Files!", font = ("Helvetica", 14))
    progresstitle.grid(row = 0, column = 0)
    progressinfo = Label(tk, text = "Starting Download...", font = ("Helvetica", 10))
    progressinfo.grid(row = 1, column = 0)

    #Engage Part Two
    part2()

#Part Two
def part2():
    #Get Globals
    global tk
    global where
    global progressbar
    global progresstitle
    global progressinfo
    global transfer
    #Repeat as many times as files described in the only file describing .txt
    for x in where
        #The online file contains "onlinelocation:offlinelocation" This splits them up
        x1 = x.split(":")[0]
        x2 = x.split(":")[1]

        #Read the online file and update labels
        transfer = None
        progressinfo.config(text = str("Downloading " + x2 + "..."))
        transfer = str(ur.urlopen("http://example.com/" + x1).read())
        progressinfo.config(text = str("Configuring downloaded file..."))
        transfer = transfer [2:(len(transfer)-1)]

        #Fix python turning "\n" to "\\n" by reversing
        transfer = transfer.split("\\n")
        transtemp = ""
        for x in transfer:
            transtemp = transtemp + "\n" + x
        transfer = transtemp[1:len(transtemp)]
        progressinfo.config(text = str("Installing " + x2 + "..."))
        tw = None
        checkdir(str(os.getcwd()+"/Downladed/"+x2))
        tw = open(str(os.getcwd()+"/Downloaded/"+x2), "w")
        tw.write(transfer)
        tw.close()
        #See if waiting helps
        T.sleep(0.5)
    part3()
def part3():
    #Get Globals
    global tk
    global where
    global progressbar
    global progresstitle
    global progressinfo
    global transfer
    #Final Screen
    progressbar.grid_remove()
    progressinfo.grid_remove()
    progresstitle.config(text="You have downloaded\n the required files!")
    progressbar.stop()

part1()

2 个回答

1

这就是为什么Tcl有异步输入输出功能的原因。你需要及时处理窗口系统的事件,所以不能等到文件完全下载完再去做其他事情。相反,你需要分段下载。在Tcl中,我们会使用fileevent命令来设置一个程序,每当从套接字接收到输入时就会调用这个程序。其余时间,我们可以处理其他事件。在Python中,常用的方法是使用Twisted这个包。它允许你注册事件源,让整个应用程序都以事件为导向。你也可以使用线程,在工作线程中进行下载,但这样并不能很好地处理进度通知。将Tkinter和Twisted连接起来需要一些特别的处理——可以查看文档

1

如果在你下载每个文件结束时更新显示就足够了,你可以用 update_idletasks() 方法来替代 T.sleep()。这样做可以让你的界面在进入下一个循环之前刷新一下。

参考链接:http://effbot.org/tkinterbook/widget.htm#Tkinter.Widget.update_idletasks-method

撰写回答