dimanche 26 septembre 2021

Showing progress of Downloads inside Tkinter Tree View

I have created a UI which have a tree view and the neccesary components for a downloader. The UI related code is shown below.

from tkinter import Button, Label, LabelFrame, W, E, Entry, Scrollbar
from tkinter import ttk
from tkinter.ttk import Progressbar


def create_label_frame(self):
    labelframe = LabelFrame(self.root, text='SAN G DOWNLOADER', fg='white', bg="#253f59", font=("Monotype Sorts", 15))
    labelframe.grid(row=0, column=1, padx=8, pady=8, sticky='e')
    Label(labelframe, text='Download Type   :', bg="#040d57", fg="white").grid(row=1, column=1, sticky=W, pady=2,
                                                                               padx=15)
    self.download_type_field = Entry(labelframe)
    self.download_type_field.grid(row=1, column=2, sticky=W, padx=5, pady=2)
    Label(labelframe, text='ShutDown yes/no:', bg="#040d57", fg="white").grid(row=2, column=1, sticky=W, pady=2,
                                                                              padx=15)
    self.shutdown_field = Entry(labelframe)
    self.shutdown_field.grid(row=2, column=2, sticky=W, padx=5, pady=2)
    Label(labelframe, text='Download Limit  :', bg="#040d57", fg="white").grid(row=3, column=1, sticky=W, pady=2,
                                                                               padx=15)
    self.limit_field = Entry(labelframe)
    self.limit_field.grid(row=3, column=2, sticky=W, padx=5, pady=2)
    Button(labelframe, text='Add Links', command=self.on_add_links_button_clicked, bg="blue", fg="white").grid(
        row=4, column=2, sticky=E, padx=5, pady=5)
    Button(labelframe, text='   clear   ', command=self.on_clear_links_button_clicked, bg="blue", fg="white").grid(
        row=4, column=1, sticky='e', padx=15, pady=5)


def create_tree_view(self):
    self.tree = ttk.Treeview(height=10, columns=("link", "status"), style='Custom.Treeview')
    self.tree.grid(row=6, column=0, columnspan=3, ipadx=15, ipady=25, sticky='e')
    self.tree.heading('#0', text='Count', anchor='center')
    self.tree.heading("link", text='Download Link', anchor='center')
    self.tree.heading("status", text='Download status', anchor='center')
    self.tree.grid_columnconfigure(1, weight=1)
    self.tree.grid_columnconfigure(2, weight=1)
    style = ttk.Style()
    style.element_create("Custom.Treeheading.border", "from", "default")
    style.layout("Custom.Treeview.Heading", [
        ("Custom.Treeheading.cell", {'sticky': 'nswe'}),
        ("Custom.Treeheading.border", {'sticky': 'nswe', 'children': [
            ("Custom.Treeheading.padding", {'sticky': 'nswe', 'children': [
                ("Custom.Treeheading.image", {'side': 'right', 'sticky': ''}),
                ("Custom.Treeheading.text", {'sticky': 'we'})
            ]})
        ]}),
    ])
    style.configure("Custom.Treeview.Heading",
                    background="blue", foreground="white", relief="flat")
    style.map("Custom.Treeview.Heading",
              relief=[('active', 'groove'), ('pressed', 'sunken')])


def create_scrollbar(self):
    self.scrollbar = Scrollbar(orient='vertical', command=self.tree.yview, bg='blue')
    self.scrollbar.grid(row=6, column=3, rowspan=10, sticky='sn')


def create_progress_bar(self):
    self.progress_bar = Progressbar(orient='horizontal')
    self.progress_bar.grid(row=6, column=3, rowspan=10, sticky='ew')

I have a downloader which follows strategy design pattern for downloading from various media. The code corresponding to the entry point of application is shown below.

from os import path
import sys

sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
from tkinter import Tk

from Downloader.Cateogory.torrent import *
from Downloader.Cateogory.youtube import *
from Downloader.Cateogory.fb import download_fb_videos
from Downloader.Cateogory.insta import download_insta_images
from Downloader.UI.Widgets.widget import *
from Downloader.Utils.regex import torrent_regex, youtube_regex, fb_regex, instagram_regex
from Downloader.Utils.tasks import links_copied_to_clipboard

if os.environ.get('DISPLAY', '') == '':
    print('no display found. Using :0.0')
    os.environ.__setitem__('DISPLAY', ':0.0')


class Downloader:

    def __init__(self, app_root):
        self.root = app_root
        self.create_gui()
        ttk.style = ttk.Style()
        ttk.style.configure("Treeview", font=('helvetica', 10))
        ttk.style.configure("Treeview.Heading", font=('helvetica', 12, 'bold'))
        self.show_links([], '')

    def create_gui(self):
        create_label_frame(self)
        create_tree_view(self)
        create_scrollbar(self)
        # create_progress_bar(self)

    def on_add_links_button_clicked(self):
        stream_type = self.download_type_field.get().lower()
        stream_limit = int(self.limit_field.get())
        shut = self.shutdown_field.get()
        if stream_type in ['youtube', 'utube']:
            self.download_strategy(stream_limit, shut, youtube_regex, download_youtube_videos)
        elif stream_type == 'torrent':
            self.download_strategy(stream_limit, shut, torrent_regex, download_torrents)
        elif stream_type in ['fb', 'facebook']:
            self.download_strategy(stream_limit, shut, fb_regex, download_fb_videos)
        elif stream_type in ['insta', 'instagram']:
            self.download_strategy(stream_limit, shut, instagram_regex, download_insta_images)

    def on_clear_links_button_clicked(self):
        self.show_links([], '')
        self.download_type_field.delete(0, 'end')
        self.limit_field.delete(0, 'end')
        self.shutdown_field.delete(0, 'end')

    def show_links(self, _links, status):
        items = self.tree.get_children()
        count = 0
        for item in items:
            self.tree.delete(item)
        for link in _links:
            count += 1
            self.tree.insert('', 0, text=count, values=(link, status))

    def download_strategy(self, stream_limit, shut, regex_type, download_fn):
        _links = links_copied_to_clipboard(stream_limit, regex_type)
        self.show_links(_links, 'Started')
        self.tree.update_idletasks()
        download_fn(_links, shut)
        self.show_links(_links, 'Finished')
        self.tree.update_idletasks()


if __name__ == '__main__':
    root = Tk()
    root.protocol("WM_DELETE_WINDOW", root.quit)
    root.title('Downloader')
    root.config(bg='sky blue')
    root.geometry("650x450")
    root.resizable(width=False, height=False)
    application = Downloader(root)
    root.mainloop()

PROBLEM

I have defined a progress function for each strategies and the progress I was able to display in the terminal. But the Approach corresponding to updating the progress in the tree view currently was to show the download status after the process finished only. The dynamic update of tree view for the download progress is seemingly impossible.

QUESTION?

Is this design pattern proper to display download progress inside Tree View for a tkinter based application?

Aucun commentaire:

Enregistrer un commentaire