Python编程实例-Tkinter GUI编程-线程更新进度条

本教程介绍了如何在Tkinter应用中利用线程和进度条实现实时下载和显示unsplash.com上的随机图片。首先,创建PictureDownload线程类用于下载图片并保存。然后,定义App类,包含两个帧,一个用于显示进度条,一个用于显示图片。用户点击'NextPicture'按钮时,启动下载线程,并通过监控线程状态更新进度条。下载完成后,显示图片。
摘要由CSDN通过智能技术生成

线程更新进度条

在本文中,将介绍在 Tkinter 应用程序中运行线程时显示进度条。

本教程假设您知道如何使用 after() 方法并了解线程在 Python 中是如何工作的。 此外,您应该知道如何使用 tkraise() 方法在帧之间切换。

在本文中,将构建一个网络图片查看器,使用其 API 显示来自 unsplash.com 的随机图片。

HTTP 请求URL如下:

https://source.unsplash.com/random/640x480

将会得到一个随机的640x480图片

在这里插入图片描述

当您单击 Next Picture 按钮时,程序会从 unsplash.com 调用 API 以下载随机图片并将其显示在窗口上。

在图片下载过程中还会显示一个进度条,表示正在下载:

在这里插入图片描述

第一步,应用程序使用到request模块,因此需要安装:

pip install request

第二步,定义一个继承自 Thread 类的新类:

class PictureDownload(Thread):
    def __init__(self, url):
        super().__init__()

        self.picture_file = None
        self.url = url

    def run(self):
        """ download a picture and save it to a file """
        # download the picture
        response = requests.get(self.url, proxies=proxyDict)
        picture_name = self.url.split('/')[-1]
        picture_file = f'./assets/{picture_name}.jpg'

        # save the picture to a file
        with open(picture_file, 'wb') as f:
            f.write(response.content)

        self.picture_file = picture_file

在此 PictureDownload 类中,run() 方法使用 requests 模块调用 API。

run() 方法下载图片并将其保存到 /assets/ 文件夹。 此外,它将下载图片的路径分配给图片文件实例属性。

第三步,定义一个继承Tk类的App类。 App 类代表根窗口。

根窗口有两个Frame,一个用于显示进度条,另一个用于显示保存下载图片的 Canvas:

def __init__(self, canvas_width, canvas_height):
    super().__init__()
    self.resizable(0, 0)
    self.title('Image Viewer')

    # Progress frame
    self.progress_frame = ttk.Frame(self)

    # configrue the grid to place the progress bar is at the center
    self.progress_frame.columnconfigure(0, weight=1)
    self.progress_frame.rowconfigure(0, weight=1)

    # progressbar
    self.pb = ttk.Progressbar(
        self.progress_frame, orient=tk.HORIZONTAL, mode='indeterminate')
    self.pb.grid(row=0, column=0, sticky=tk.EW, padx=10, pady=10)

    # place the progress frame
    self.progress_frame.grid(row=0, column=0, sticky=tk.NSEW)

    # Picture frame
    self.picture_frame = ttk.Frame(self)

    # canvas width & height
    self.canvas_width = canvas_width
    self.canvas_height = canvas_height

    # canvas
    self.canvas = tk.Canvas(
        self.picture_frame,
        width=self.canvas_width,
        height=self.canvas_height)
    self.canvas.grid(row=0, column=0)

    self.picture_frame.grid(row=0, column=0)

当单击 Next Picture 按钮时,handle_download() 方法将执行:

def handle_download(self):
    """ Download a random photo from unsplash """
    self.start_downloading()

    url = 'https://source.unsplash.com/random/640x480'
    download_thread = PictureDownload(url)
    download_thread.start()

    self.monitor(download_thread)

handle_download() 方法通过调用 start_downloading() 方法显示进度Frame并启动进度条:

def start_downloading(self):
    self.progress_frame.tkraise()
    self.pb.start(20)

它还创建了一个新的线程,下载随机图片并调用monitor()方法来监控线程的状态。下面为 monitor() 方法:

def monitor(self, download_thread):
    """ Monitor the download thread """
    if download_thread.is_alive():
        self.after(100, lambda: self.monitor(download_thread))
    else:
        self.stop_downloading()
        self.set_picture(download_thread.picture_file)

monitor() 方法检查线程的状态。 如果线程正在运行,它会在 100 毫秒后安排另一次检查。

否则,monitor() 方法调用 stop_downloading() 方法停止进度条,显示相框,显示图像。

下面为stop_downloading() 方法:

def stop_downloading(self):
    self.picture_frame.tkraise()
    self.pb.stop()   

整完代码如下:

import requests
import tkinter as tk
from threading import Thread
from PIL import Image, ImageTk
from tkinter import ttk

class PictureDownload(Thread):
    def __init__(self, url):
        super().__init__()

        self.picture_file = None
        self.url = url

    def run(self):
        """ download a picture and save it to a file """
        # download the picture
        response = requests.get(self.url)
        picture_name = self.url.split('/')[-1]
        picture_file = f'./assets/{picture_name}.jpg'

        # save the picture to a file
        with open(picture_file, 'wb') as f:
            f.write(response.content)

        self.picture_file = picture_file


class App(tk.Tk):
    def __init__(self, canvas_width, canvas_height):
        super().__init__()
        self.resizable(0, 0)
        self.title('Image Viewer')

        # Progress frame
        self.progress_frame = ttk.Frame(self)

        # configrue the grid to place the progress bar is at the center
        self.progress_frame.columnconfigure(0, weight=1)
        self.progress_frame.rowconfigure(0, weight=1)

        # progressbar
        self.pb = ttk.Progressbar(
            self.progress_frame, orient=tk.HORIZONTAL, mode='indeterminate')
        self.pb.grid(row=0, column=0, sticky=tk.EW, padx=10, pady=10)

        # place the progress frame
        self.progress_frame.grid(row=0, column=0, sticky=tk.NSEW)

        # Picture frame
        self.picture_frame = ttk.Frame(self)

        # canvas width & height
        self.canvas_width = canvas_width
        self.canvas_height = canvas_height

        # canvas
        self.canvas = tk.Canvas(
            self.picture_frame,
            width=self.canvas_width,
            height=self.canvas_height)
        self.canvas.grid(row=0, column=0)

        self.picture_frame.grid(row=0, column=0)

        # Button
        btn = ttk.Button(self, text='Next Picture')
        btn['command'] = self.handle_download
        btn.grid(row=1, column=0)

    def start_downloading(self):
        self.progress_frame.tkraise()
        self.pb.start(20)

    def stop_downloading(self):
        self.picture_frame.tkraise()
        self.pb.stop()

    def set_picture(self, file_path):
        """ Set the picture to the canvas """
        pil_img = Image.open(file_path)

        # resize the picture
        resized_img = pil_img.resize(
            (self.canvas_width, self.canvas_height),
            Image.ANTIALIAS)

        self.img = ImageTk.PhotoImage(resized_img)

        # set background image
        self.bg = self.canvas.create_image(
            0,
            0,
            anchor=tk.NW,
            image=self.img)

    def handle_download(self):
        """ Download a random photo from unsplash """
        self.start_downloading()

        url = 'http://cn.naturewallpaperfree.com/mobile/hai\'an/ziran-bizhi-640x480-434-e5a14488.jpg'
        download_thread = PictureDownload(url)
        download_thread.start()

        self.monitor(download_thread)

    def monitor(self, download_thread):
        """ Monitor the download thread """
        if download_thread.is_alive():
            self.after(100, lambda: self.monitor(download_thread))
        else:
            self.stop_downloading()
            self.set_picture(download_thread.picture_file)


if __name__ == '__main__':
    app = App(640, 480)
    app.mainloop()

运行结果如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

视觉&物联智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值