[Solved] Why the secondary GUI opens before the primary GUI?


So there are several red flags right away… (multiple mainloop calls, classes in classes, calling root inside listbox)

It seems like you are missing one of the main concepts of many gui frameworks, and that is that 1 window is not 1 application. In general the “root” of the application is the controller in the background handling events from all windows the program has spawned. The processing of those events happens in the mainloop function. When you define your Notepad class, at the very end you create a class attribute by calling root2 = listbox(), assign it some properties, and then run its mainloop. This happens at the time of definition because it’s not inside a method, and blocks you from ever making it past this line.

I also notice that you are trying to use root as if it’s a global inside listbox.selection. This causes a NameError as you have not used the global keyword. It is far more common to pass “self” to child objects at the time of creation rather than to try to access the parent via inheritance. I think this may also be related to why you defined listbox inside Notebook. This is technically valid, but very uncommon. Putting a class inside another class does not automatically make the inner class inherit anything from the parent class, and only makes it part of the namespace of the parent class. In the example of GUI’s it is more common to separate different parts of a gui by creating separate modules which are imported where needed. This way files are smaller and easier to read for large applications. In this instance, I wouldn’t bother, but I would lake listbox its own class.

Here’s what I would do to fix your situations (please read through comments I made as well):

from tkinter import *
from tkinter import messagebox as msg
from tkinter.filedialog import askopenfilename, asksaveasfilename
from functools import partial
import os

class Notepad(Tk):

    """Class for notepad """
#  Command for menus-

    def newFile(self):
 
        self.crfile = None
        self.txtarea.delete(1.0, END)

    def saveFile(self):

        if self.crfile == None:
            self.crfile = asksaveasfilename(initialfile="Untitled.txt",
                                            defaultextension=".txt", filetypes=[("All Files", "*.*"), ("Text Documents", "*.txt")])
            if self.crfile == "":
                self.crfile = None
            else:
                # Save as new file
                with open(self.crfile, "w") as f:
                    f.write(self.txtarea.get(1.0, END))
                    self.title(os.path.basename(
                        self.crfile + "- Tanish's Notepad"))
        else:
            # Save the file
            with open(self.crfile, "w") as f:
                f.write(self.txtarea.get(1.0, END))
                self.title(os.path.basename(
                    self.crfile + "- Tanish's Notepad"))

    def openFile(self):

        self.crfile = askopenfilename(defaultextension=".txt", filetypes=[
                                      ("All Files", "*.*"), ("Text Documents", "*.txt")])
        if self.crfile == "":
            self.crfile = None
        else:
            self.title(os.path.basename(self.crfile) +
                       "-" + "Tanish's Notepad")
            self.txtarea.delete(1.0, END)
            with open(self.crfile, "r") as f:
                self.txtarea.insert(1.0, f.read())

    # commands for edit menu-

    def copy(self):
        self.txtarea.event_generate(("<<Copy>>"))

    def paste(self):
        self.txtarea.event_generate(("<<Paste>>"))

    def cut(self):
        self.txtarea.event_generate(("<<Cut>>"))

    # commands for help menu-

    def About(self):
        msg.showinfo("Tanish's Notepad -Help",
                     "This is a simple notepad made by Tanish Sarmah")

    def menus(self):

        # TODO Menus
        mainmenu = Menu(self, tearoff="0")
        # file menu
        file = Menu(mainmenu, tearoff=0)
        # Creating new file
        file.add_command(label="New", command=self.newFile)
        # Saving the current file
        file.add_command(label="Save", command=self.saveFile)
        # Opening a Pre-Existing file
        file.add_command(label="Open", command=self.openFile)
        file.add_separator()
        file.add_command(label="Exit", command=self.destroy)  # Exit command
        mainmenu.add_cascade(menu=file, label="File")
        self.config(menu=mainmenu)

        # Edit menu---
        edit = Menu(mainmenu, tearoff=0)
        # To cut any part of the Textarea
        edit.add_command(label="Cut", command=self.cut)
        # To copy any part of the Textarea
        edit.add_command(label="Copy", command=self.copy)
        # To paste any cut or copied Text.
        edit.add_command(label="Paste", command=self.paste)
        mainmenu.add_cascade(menu=edit, label="Edit")
        self.config(menu=mainmenu)

        # Help menu---
        helpm = Menu(mainmenu, tearoff=0)
        # Displays about the notepad
        helpm.add_command(label="About", command=self.About)
        mainmenu.add_cascade(menu=helpm, label="Help")
        self.config(menu=mainmenu)

        # Window menu
        win = Menu(mainmenu, tearoff=0)
        win.add_command(label="Colour", command=partial(listbox, self)) #we'll use a partial functino to bind self as the parent here. listbx is now called in __init__
        mainmenu.add_cascade(menu=win, label="Window")
        self.config(menu=mainmenu)

    def textwid(self):

        # TODO Text widget---

        self.txtarea = Text(self)
        self.crfile = None
        self.txtarea.pack(expand=True, fill=BOTH)
        # TODO Scrollbar---
        self.scbar = Scrollbar(self.txtarea)
        self.txtarea.config(yscrollcommand=self.scbar.set)
        self.scbar.config(command=self.txtarea.yview)
        self.scbar.pack(side=RIGHT, fill=BOTH)

class listbox(Toplevel): 
    #listbox moved to its own class to prevent confusion of inheritance
    #child windows should not inherit from application root, rather from "Toplevel"
    def __init__(self, parent): 
        #moved window setup to __init__ method as we are creating a new window each time we want this menu
        #calling mainloop() is not necessary, as the "mainloop" from if __name__ == "__main__": is now running
        super().__init__()
        self.parent = parent #we need access to the parent so we chan change its color
        self.geometry("300x200")
        self.title("Window-Colour")
        self.listbx()
    
    def listbx(self):
        self.lbx = Listbox(self)
        colours = ["blue", "red", "yellow",
                    "grey", "green", "light blue", "black"]
        for c in colours:
            self.lbx.insert(END, c)
        self.lbx.pack()
        self.lbx.bind("<<ListboxSelect>>", self.selection)

    def selection(self, event):
        """Selection of colour from the  lisbox above to apply changes"""
        colour = self.lbx.get(ANCHOR)
        msgselect = msg.askokcancel(
            "Window-Colour", "Confirm the colour to apply to the window")
        if msgselect == True:
            self.parent.configure(bg=colour) #call the parent without a global because we inherited it earlier
            self.destroy()
        else:
            self.destroy()
        

if __name__ == "__main__":
    # Basic tkinter startup

    root = Notepad()
    root.geometry("800x700")
    root.title("Tanish's Notepad-Untitled-1")
    root.menus()
    root.textwid()
    # root.wm_iconbitmap("noteicon.ico") #I didn't have this file, so I commented it out
     
    root.mainloop()

2

solved Why the secondary GUI opens before the primary GUI?