grid_forget() not working with classes acting as Frames

Question:

Right so, I have been making this goofy clock app in order to further my skills in programming, especially by adding an object oriented approach. I have defined a main menu of which is under main() but I use classes to act as Frames for the different features of the app. To switch between those, I kind of had a clunky system but it worked- nearly.

"""
Goofy agh clock app to get me back into programming.
To make it harder, I limited it to only Object-Oriented programming and also uses ttkboostrap to at least make it
remotely look good.

Features:
Clock, timer (with included sounds), stop watch.
"""

from PIL import Image, ImageTk

import ttkbootstrap as ttb
from ttkbootstrap.constants import *
from datetime import *


class TimeFrame(ttb.Frame):
    current_frame = True

    def __init__(self, master):
        self.selector = ttb.Frame(master)
        # self.time_frame.grid(row=1, column=1)

        now_time = datetime.now()
        string_time = now_time.strftime("%H : %M : %S")

        self.time_label = ttb.Label(self.selector, text=string_time,
                                    font=("Arial Greek", 32, "bold"), bootstyle=INFO)
        self.time_label.grid(row=1, column=0, padx=100)

        self.update_time()

    def update_time(self):
        new_time = datetime.now()
        new_string_time = new_time.strftime("%H: %M: %S")

        self.time_label.config(text=new_string_time)
        self.selector.after(1000, self.update_time)


class TimerFrame(ttb.Frame):
    current_frame = False

    def __init__(self, master):
        self.selector = ttb.Frame(master)
        self.timer_entry_frame = ttb.Frame(self.selector)

        self.hour_increase = ttb.Button(self.timer_entry_frame, text="↑", bootstyle=OUTLINE)
        self.minute_increase = ttb.Button(self.timer_entry_frame, text="↑", bootstyle=OUTLINE)
        self.second_increase = ttb.Button(self.timer_entry_frame, text="↑", bootstyle=OUTLINE)

        self.hours_entry = ttb.Entry(self.timer_entry_frame, style=PRIMARY, width=10)
        self.minutes_entry = ttb.Entry(self.timer_entry_frame, style=PRIMARY, width=10)
        self.seconds_entry = ttb.Entry(self.timer_entry_frame, style=PRIMARY, width=10)

        self.hour_decrease = ttb.Button(self.timer_entry_frame, text="↓", bootstyle=OUTLINE)
        self.minute_decrease = ttb.Button(self.timer_entry_frame, text="↓", bootstyle=OUTLINE)
        self.second_decrease = ttb.Button(self.timer_entry_frame, text="↓", bootstyle=OUTLINE)

        self.hour_increase.grid(row=0, column=0, padx=15, pady=5)
        self.minute_increase.grid(row=0, column=1, padx=15, pady=5)
        self.second_increase.grid(row=0, column=2, padx=15, pady=5)

        self.hours_entry.grid(row=1, column=0, padx=15)
        self.minutes_entry.grid(row=1, column=1, padx=15)
        self.seconds_entry.grid(row=1, column=2, padx=15)

        self.hour_decrease.grid(row=2, column=0, padx=15, pady=5)
        self.minute_decrease.grid(row=2, column=1, padx=15, pady=5)
        self.second_decrease.grid(row=2, column=2, padx=15, pady=5)

        self.timer_entry_frame.grid(row=0, column=0, padx=50)

        self.start_timer_btn = ttb.Button(self.selector, text="START", bootstyle=(SUCCESS, OUTLINE))
        self.start_timer_btn.grid(row=2, column=0, padx=50, pady=50)
        # ↑↓


def main():
    def change_frames(new_frame):
        if TimeFrame.current_frame is True:
            print("First if statement responded")
            TimeFrame(root).selector.grid_forget()
            TimeFrame.current_frame = False
        elif TimerFrame.current_frame is True:
            print("Second if statement responded")

            # for widget in TimerFrame(root).selector.winfo_children():
            #     widget.grid_forget()

            TimerFrame.current_frame = False

        new_frame(root).selector.grid(row=1, column=1)
        new_frame.current_frame = True

        print("Timer frame state", TimerFrame.current_frame, "nNew frame calling", new_frame.current_frame)

    root = ttb.Window(themename="darkly")
    root.title("Clock")
    root.geometry("500x500")
    root.resizable(False, False)
    root.iconphoto(False, ImageTk.PhotoImage(file="clock_icon.png"))

    side_panel = ttb.Frame(root, width=75, height=500, bootstyle="info")
    side_panel.grid(rowspan=4, column=0)

    clock_image = Image.open("clock_icon.png")
    resized_clock = clock_image.resize((50, 50))
    timer_image = Image.open("timer_icon.png")
    resized_timer = timer_image.resize((50, 50))

    used_clock_image = ImageTk.PhotoImage(resized_clock)
    used_timer_image = ImageTk.PhotoImage(resized_timer)

    clock_button = ttb.Button(root, image=used_clock_image, bootstyle=INFO, command=lambda: change_frames(TimeFrame))
    clock_button.image = used_clock_image
    clock_button.grid(row=0, column=0)

    timer_button = ttb.Button(root, image=used_timer_image, bootstyle=INFO, command=lambda: change_frames(TimerFrame))
    timer_button.image = used_timer_image
    timer_button.grid(row=1, column=0)

    # Testing button
    # destroybtn = ttb.Button(root, text="delete", command=lambda: TimeFrame(root).selector.grid_forget())
    # destroybtn.grid(row=2, column=0)

    TimeFrame(root).selector.grid(row=1, column=1)

    root.mainloop()


if __name__ == '__main__':
    main()

I had a common class attribute which dictates the state of the previous frame of which I use a function in main() to manage the frames based on what I clicked on the side menu and it checks over which frames are existing. It works for when I need to move from the time to the timer menu, but when I go back, the .grid_forget() does not remove the timer widgets and so both of them are just clunked together in the same window.

I did try to use wgetinfo_children, using a loop to go over it with a looping variable of widget, doing the .grid_forget() function on each widget, but it still did not work!

Also, is there a better way of managing frames than this? I am fairly sure this is clunky but I don’t have a solid idea on where I could research for scenarios similar to this.

Thank you in advance.

Answers:

solved, I set all the specified objects under a variable name and called that variable instead of calling potential new instances of the object.

Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.