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.
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()