Is it a tkinter problem? The progress bar is not shown when other GUI windows are open

39 Views Asked by At

Below is the general structure of my code. I have a main GUI window (w0), and some top level windows e.g. w3 which are used for image processing. Besides, I have also created a top level window as “progress window” to show the process information during processing. If I keep the w0 window opened, the green process bar is not shown, but if the w0 is destroyed somewhere in the beginning of the “auto_classic_i_method”
function, the green process bar appears. What is the reason? How can I keep both the w0 and the process bar at the same time? Also, I have tested some other options such as withdrawing and iconifying w0 at the beginning and end of the auto_classic_i_method, but it was not helpful.

To run the simplified version of the code, please place several images in the input path and run the code:

from tkinter import *
from tkinter import ttk
import tkinter.filedialog
import cv2
import skimage.color
import skimage.io
import skimage.measure
import skimage.morphology
import os.path
import tkinter
import os
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from tqdm import tqdm
import time


class EasyQuadrat:
    def __init__(self, w0):
        self.w0 = w0
        w0.geometry("350x300")
        w0.title("Easy Quadrat")
        w0.configure(bg='light gray')
        w0.resizable(width=False, height=False)  # Disables window resizing

        # Create a new frame for the rest of the widgets
        self.main_frame = Frame(w0, bg='light gray', padx=0, pady=70)

        class FolderSelect(Frame):
            def __init__(self, parent=None, folderDescription="", **kw):
                Frame.__init__(self, master=parent, **kw)
                self.folderPath = StringVar()
                self.lblName = Label(self, text=folderDescription, fg='dark blue', bg='light gray',
                                     font=('label_font', 10, 'bold'))
                self.lblName.grid(row=1, column=0, padx=0, pady=0, rowspan=2, sticky=NSEW)
                self.entPath = Entry(self, borderwidth=3, width=18, textvariable=self.folderPath)
                self.entPath.grid(row=1, column=1, padx=0, pady=0, ipadx=0, ipady=0, sticky=NSEW)
                self.btnFind = ttk.Button(self, text="Browse", command=self.setFolderPath)
                self.btnFind.grid(row=1, column=2, padx=0, pady=0, ipadx=0, ipady=0, sticky=NSEW)

            def setFolderPath(self):
                folder_selected = filedialog.askdirectory()
                self.folderPath.set(folder_selected)

            @property
            def folder_path(self):
                return self.folderPath.get()

        self.directory1Select = FolderSelect(self.main_frame, "Input path")
        self.directory1Select.grid(row=0, column=0, columnspan=1, padx=10, pady=3, sticky=E)

        self.directory2Select = FolderSelect(self.main_frame, "Output path")
        self.directory2Select.grid(row=1, column=0, columnspan=1, rowspan=1, padx=10, pady=3, sticky=E)

        # Create a new frame for cropping method and radio buttons
        self.cropping_frame = Frame(self.main_frame, bg='light gray')
        self.cropping_frame.grid(row=2, column=0, columnspan=2, rowspan=2, padx=25, pady=50, sticky=W)

        self.Cropping_method = Label(self.cropping_frame, text='Cropping Method', font='label_font 11 bold',
                                     fg="dark green",
                                     bg='light gray')
        self.Cropping_method.grid(row=0, column=0, columnspan=2, rowspan=2, padx=0, pady=5, sticky=W)

        self.Button3 = Button(self.cropping_frame, text='Auto (Classic I)', command=self.auto_classic_i_method,
                              bg='light gray', width=16, height=2)
        self.Button3.grid(row=6, column=0, columnspan=2, rowspan=2, padx=15, pady=5, sticky=tk.W)
        self.buttons_frame = Frame(self.main_frame, bg='light gray')
        self.buttons_frame.grid(row=10, column=0, columnspan=2, padx=65, pady=5, sticky=W)

        # Pack the frames
        self.main_frame.grid(row=0, column=0, columnspan=2, rowspan=11, padx=10, pady=5, sticky=NSEW)
        self.folderPath = StringVar()

    def validate_entries(self):
        global w0, in_path, out_path
        in_path = self.directory1Select.folder_path
        out_path = self.directory2Select.folder_path

        if in_path == '':
            tkinter.messagebox.showwarning(title='Error!', message='Please select the input path')
            return False
        else:
            if out_path == '':
                tkinter.messagebox.showwarning(title='Error!', message='Please select the output path')
                return False
            else:
                return True



    # ----------------------

    # Method: Auto (Classic I)

    # ----------------------

    def auto_classic_i_method(self):

        if self.validate_entries():
            class ProgressWindow(tk.Toplevel):
                def __init__(self, parent, total, title="Progress"):
                    super().__init__(parent)
                    self.title(title)
                    self.geometry("400x150")

                    # Center the window on the screen
                    window_width = 400
                    window_height = 120
                    screen_width = self.winfo_screenwidth()
                    screen_height = self.winfo_screenheight()
                    x_coordinate = int((screen_width - window_width) / 2)
                    y_coordinate = int((screen_height - window_height) / 2)
                    self.geometry(f"+{x_coordinate}+{y_coordinate}")

                    # Show an "Initializing..." message
                    self.init_label = Label(self, text="Initializing... Please wait!", font=('default', 10, 'bold'))
                    self.init_label.pack(pady=25)

                    self.status_label = Label(self, text="", font=('default', 10, 'bold'))
                    self.status_label.pack(pady=25)

                    self.progress_var = IntVar()
                    # Adjusted length of the progress bar
                    self.progress_bar = ttk.Progressbar(self, variable=self.progress_var, maximum=total, length=300)
                    self.progress_bar.pack(pady=10)  # Adjusted padding
                    self.resizable(width=False, height=False)  # Disables window resizing

                    self.update()

                def update_progress(self, value, current_file):
                    if hasattr(self, 'init_label'):
                        self.init_label.destroy()
                        del self.init_label

                    percentage = int((value / self.progress_bar["maximum"]) * 100)
                    status_text = f"Processing image {value} / {self.progress_bar['maximum']}: {current_file} ({percentage}%)"
                    self.status_label.config(text=status_text)
                    self.progress_var.set(value)
                    self.update()

            class ClassicI:
                def __init__(self, w3):
                    self.w3 = w3
                    self.w3.geometry("340x260")
                    self.w3.title(" Easy Quadrat _ Classic I")
                    self.w3.resizable(width=False, height=False)  # Disables window resizing
                    self.lblw3 = Label(self.w3, text="This is a test...:", font=('default', 10, 'bold'))
                    self.lblw3.grid(row=1, column=1, padx=40, pady=15, sticky="w")


                    self.w3OK = ttk.Button(self.w3, text="OK", command=self.entw3)
                    self.w3OK.grid(row=9, column=1, padx=15, pady=20, sticky="s")

                    self.w3Cancel = ttk.Button(self.w3, text="Cancel", command=self.w3.destroy)
                    self.w3Cancel.grid(row=9, column=2, padx=0, pady=20, sticky="w")



                def entw3(self):


                    self.w3.withdraw()  # Hide the main window

                    progress_window = ProgressWindow(self.w3, total=len(os.listdir(in_path)),
                                                     title="Processing Images")


                    try:
                        self.Cropped_images = os.path.join(out_path, 'Cropped images')

                        os.makedirs(self.Cropped_images)
                    except FileExistsError:
                        pass

                    # Process images
                    file_list = os.listdir(in_path)
                    total_images = len(file_list)

                    for i, file in enumerate(
                            tqdm(file_list, desc="Processing Images", unit="image", leave=False, disable=True)):
                        try:
                            f_img = os.path.join(in_path, file)
                            image_rgb = skimage.io.imread(f_img)

                            time.sleep(2)

                            _, extension = os.path.splitext(file)
                            f_out2 = os.path.join(self.Cropped_images, "C_" + file)
                            cv2.imwrite(f_out2, cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR))

                        except Exception as e:
                            pass

                        # Update the progress window
                        progress_window.update_progress(i + 1, file)

                    # Destroy the progress window after processing is complete
                    progress_window.destroy()
                    self.w3.destroy()
                    messagebox.showinfo("Easy Quadrat", "Processing completed!")

            w3 = tk.Tk()
            w3.resizable(width=False, height=False)  # Disables window resizing
            app = ClassicI(w3)
            w3.update_idletasks()  # Ensure the window is fully created before centering
            w3.eval('tk::PlaceWindow . center')
            w3.mainloop()


if __name__ == "__main__":
    w0 = tk.Tk()
    app = EasyQuadrat(w0)

    # Configure grid row and column weights
    w0.grid_rowconfigure(0, weight=1)
    w0.grid_columnconfigure(0, weight=1)

    # Center the window
    w0.eval('tk::PlaceWindow . center')

    # Start the main event loop
    w0.mainloop()

Processing bar is not shown:

Processing bar is not shown

Processing bar appears if the w0 has been destroyed before image processing:

Processing bar appears if the w0 has been destroyed before image processing

I want to keep the w0 window and the progress bar at the same time. After processing the images, I will come back to the w0.

0

There are 0 best solutions below