0

I'm new to programming in general and currently programming a little bit in python. I'm trying to read a lot about programming, but unfortunately i'm still having trouble grasping the concepts of classes and threading. So i would be quite happy about some help. I'm trying to write a program where a main gui is created and calls a function in another module. That function is creating a gui with progress bar and executing a long background task.

First i did this using after(), but the gui window wasn't responsive and didn't work anymore after minimizing. So i read in several sources that for something like this threading should be used. As i was calling two separate functions, that both needed access to the same gui elements (one for creating the window, the other for updating the progress bar and adding the finish-button afterward), i also found that i should use a class for this. I tried to help myself with this tutorial: intro psthon threading.

Doing it like this worked:

import tkinter as tk
from tkinter import ttk
import threading
import time

class ProgressManager:
    def __init__(self):
        self.progressbar = None
        self.complete_button = None

    def programming_xyz_pair(self):
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(5)
        self.progressbar.update_idletasks()

        self.complete_button.pack()

    def progress_bar(self):

        progress_gui = tk.Toplevel()
        progress_gui.title("xyz")

        window_width = 800
        window_height = 200
        screen_width = progress_gui.winfo_screenwidth()
        screen_height = progress_gui.winfo_screenheight()
        x_position = (screen_width - window_width) // 2
        y_position = (screen_height - window_height) // 4
        progress_gui.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")

        # text
        label_font = ('Calibri', 13)
        label = tk.Label(progress_gui,
                         text="xyz-Pärchen wird konfiguriert und gepaart, bitte warten...",
                         font=label_font)
        label.pack(padx=30, pady=30)

        frame = tk.Frame(progress_gui)
        frame.pack(padx=50, pady=30)

        # Create and place the progress bar inside the Frame
        self.progressbar = ttk.Progressbar(frame, length=450)
        self.progressbar.pack(expand=True, fill=tk.X)

        def continue_button_click():
            progress_gui.quit()

        self.complete_button = tk.Button(progress_gui, text="Continue", command=continue_button_click)
        self.complete_button.pack_forget()

        # progress_gui.after(100, self.programming_ZA1739_B_pair)

        progress_gui.mainloop()
        progress_gui.destroy()


progress_manager = ProgressManager()

# Create a thread for programming_ZA1739_B_pair
programming_thread = threading.Thread(target=progress_manager.programming_xyz_pair)

# Create a thread for progress_bar
progress_bar_thread = threading.Thread(target=progress_manager.progress_bar)

# Start both threads
programming_thread.start()
progress_bar_thread.start()

# Wait for both threads to finish
programming_thread.join()
progress_bar_thread.join()

print('finished')

But as i need to call this part from a different modul, i tried to implement it like this:

main:

import further_threading_test
import tkinter as tk
from tkinter import ttk

def on_start_button_click():
    root.withdraw()
    further_threading_test.progress_bar(root)
    print('Startfenster wird wieder aufgerufen')
    root.deiconify()

root = tk.Tk()
def create_main_window():
    root.title("xyz Programmier-Tool")
    root.configure(background='#E5E5E5')

    start_button = ttk.Button(root, text="\nStart\n", command=on_start_button_click)
    start_button.pack()

    root.mainloop()


create_main_window()

further_threading_test

import tkinter as tk
from tkinter import ttk
import threading
import time

class ProgressManager:
    def __init__(self, root):
        self.root = root
        self.progressbar = None
        self.complete_button = None
        self.progress_ready_event = threading.Event()

    def programming_xyz_pair(self):
        self.progress_ready_event.wait()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(3.8)
        self.progressbar.update_idletasks()
        time.sleep(1)
        self.progressbar.step(5)
        self.progressbar.update_idletasks()

        self.complete_button.pack()

    def progress_bar_gui(self):

        progress_gui = tk.Toplevel(self.root)
        progress_gui.title("ZA1739-B")

        window_width = 800
        window_height = 200
        screen_width = progress_gui.winfo_screenwidth()
        screen_height = progress_gui.winfo_screenheight()
        x_position = (screen_width - window_width) // 2
        y_position = (screen_height - window_height) // 4
        progress_gui.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")

        # text
        label_font = ('Calibri', 13)
        label = tk.Label(progress_gui,
                         text="ZA1739B-Pärchen wird konfiguriert und gepaart, bitte warten...",
                         font=label_font)
        label.pack(padx=30, pady=30)

        frame = tk.Frame(progress_gui)
        frame.pack(padx=50, pady=30)

        # Create and place the progress bar inside the Frame
        self.progressbar = ttk.Progressbar(frame, length=450)
        self.progressbar.pack(expand=True, fill=tk.X)

        def continue_button_click():
            progress_gui.quit()

        self.complete_button = tk.Button(progress_gui, text="Continue", command=continue_button_click)
        self.complete_button.pack_forget()

        self.progress_ready_event.set()

        # progress_gui.after(100, self.programming_ZA1739_B_pair)

        progress_gui.mainloop()
        progress_gui.destroy()


def progress_bar(root):
    progress_manager = ProgressManager(root)

    programming_thread = threading.Thread(target=progress_manager.programming_xyz_pair)
    progress_bar_thread = threading.Thread(target=progress_manager.progress_bar_gui)

    programming_thread.start()
    progress_bar_thread.start()

    programming_thread.join()
    progress_bar_thread.join()

    return

I found out in the meantime, that i shouldn't be opening new windows and using frames instead, but i still don't understand why the first one is working and the second not. Bevore i added self.progress_ready_event = threading.Event() i had the problem that step wasn't known as attribute for progressbar, so i added this to make sure that progressbar is finished bevore i update it. But now after pressing start nothing happens. I think i don't understand a overlaying concept here. Any help or explanation what exactly i'm doing wrong here or misunderstanding would be greatly appreciated. Thanks in advance!

Edit: I now also found this answer from @TheLizzard where it says: # Don't use a tk.Toplevel here. Can this have to do something with this? If yes, why?

1 Answer 1

0

In the meanwhile i came up with a "work-around" so in case anyone else needs this i will answer it here, but im'm still happy if anyone has a better solution as this is not answering the original question, but just a way to do this without threading (but also not in a nice way).

With help of this i came to a solution where i don't need threading, but the gui-window gets updated after each step. So again, it's no ice solution if one of the steps takes some longer, but it's at least better than the window not working until the beackground code is completely executed. To do this i changed the module further_threading_test to the following:

import tkinter as tk
from tkinter import ttk
import time

def programming_xyz_pair(root, progressbar):
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(3.8)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()
    time.sleep(1)
    progressbar.step(4.9)
    progressbar.update_idletasks()
    root.update_idletasks()
    root.update()



def progress_bar(root):

    progress_gui = tk.Toplevel(root)
    progress_gui.title("xyz")

    window_width = 800
    window_height = 200
    screen_width = progress_gui.winfo_screenwidth()
    screen_height = progress_gui.winfo_screenheight()
    x_position = (screen_width - window_width) // 2
    y_position = (screen_height - window_height) // 4
    progress_gui.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")

    # text
    label_font = ('Calibri', 13)
    label = tk.Label(progress_gui,
                     text="xyz-Pärchen wird konfiguriert und gepaart, bitte warten...",
                     font=label_font)
    label.pack(padx=30, pady=30)

    frame = tk.Frame(progress_gui)
    frame.pack(padx=50, pady=30)

    # Create and place the progress bar inside the Frame
    progressbar = ttk.Progressbar(frame, length=450)
    progressbar.pack(expand=True, fill=tk.X)

    def continue_button_click():
        progress_gui.quit()

    complete_button = tk.Button(progress_gui, text="Continue", command=continue_button_click)
    complete_button.pack_forget()

    root.update_idletasks()
    root.update()

    programming_xyz_pair(root, progressbar)

    complete_button.pack(ipadx=250)

    progress_gui.mainloop()
    progress_gui.destroy()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.