Why do I get a small window titled 'Tk' when my code is run?

85 Views Asked by At
from tkinter import *
from tkinter import ttk
import tkinter as tk

style = ttk.Style()

def main():
    global MainMenu
    global style
    MainMenu = Toplevel()
    MainMenu.title('Rubiks Cube Solver')  # Creates a window with the title 'Rubiks Cube Solver' that is 640x480 and with a gray background
    MainMenu.geometry('640x480')
    MainMenu.config(bg='gray')

    style.configure('W.TButton', font=('Consolas', 25), foreground = 'black')  # Style for the buttons

    
    Label(MainMenu, text='Rubiks Cube Solver', font=('Consolas', 40, 'bold'), bg='gray').pack()  # Shows a title 'Rubiks Cube Solver'
    
    timerbtn = ttk.Button(MainMenu, text='Timer', style='W.TButton')
    timerbtn.place(relx=0.5, rely=0.7, anchor=CENTER)   # Creates a button and anchors it to the center
    
    solverbtn = ttk.Button(MainMenu, text='Solver', style='W.TButton')
    solverbtn.place(relx=0.5, rely=0.5, anchor=CENTER)  
    
    databasebtn = ttk.Button(MainMenu, text='Database', style='W.TButton', command=maindatabase)
    databasebtn.place(relx=0.5, rely=0.3, anchor=CENTER)

def maindatabase():
    MainMenu.withdraw()
    DataMenu = Toplevel(MainMenu)
    DataMenu.title('Database Viewer')  # Creates a window with the title 'Database Viewer' that is 640x480 and with a gray background
    DataMenu.geometry('640x480')
    DataMenu.config(bg='gray')

    
    Label(DataMenu, text='Database Viewer', font=('Consolas', 40, 'bold'), bg='gray').pack()  # Shows a title 'Database Viewer'

    
    searchbtn = ttk.Button(DataMenu, text='Search', style='W.TButton')
    searchbtn.place(relx=0.5, rely=0.5, anchor=CENTER)   # Creates a button and anchors it to the center
    
    fullbtn = ttk.Button(DataMenu, text='Full View', style='W.TButton')
    fullbtn.place(relx=0.5, rely=0.6, anchor=CENTER)  
    
    backbtn = ttk.Button(DataMenu, text='Back', command=lambda:[DataMenu.destroy(), MainMenu.deiconify()])
    backbtn.place(relx=0.9, rely=0.3, anchor=CENTER)
    
if __name__ == "__main__":
    main()`

When this code is run, it opens the desired main menu and a small white window called Tk.

When I define MainMenu = Tk() instead of Toplevel(), none of my buttons have any styling. If I put the styling in the main() function, then the second window has no button styling. Where am I going wrong?

2

There are 2 best solutions below

0
On

Apart from the issues mentioned by the other answer, there is another issue that if the user closes the toplevel window using the close button in the title bar, the main window will not be restored. Use .protocol("WM_DELETE_WINDOW", ...) to fix this issue:

from tkinter import ttk
import tkinter as tk


def main():
    # use tk.Tk() instead of tk.Toplevel() for main/root window
    MainMenu = tk.Tk()
    MainMenu.title('Rubiks Cube Solver')  # Creates a window with the title 'Rubiks Cube Solver' that is 640x480 and with a gray background
    MainMenu.geometry('640x480')
    MainMenu.config(bg='gray')

    # create instance of ttk.Style() after creating the main window
    style = ttk.Style()
    style.configure('W.TButton', font=('Consolas', 25), foreground = 'black')  # Style for the buttons

    tk.Label(MainMenu, text='Rubiks Cube Solver', font=('Consolas', 40, 'bold'), bg='gray').pack()  # Shows a title 'Rubiks Cube Solver'

    timerbtn = ttk.Button(MainMenu, text='Timer', style='W.TButton')
    timerbtn.place(relx=0.5, rely=0.7, anchor=tk.CENTER)   # Creates a button and anchors it to the center

    solverbtn = ttk.Button(MainMenu, text='Solver', style='W.TButton')
    solverbtn.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

    databasebtn = ttk.Button(MainMenu, text='Database', style='W.TButton',
                             # pass MainWindow as an argument instead of using global variable
                             command=lambda:maindatabase(MainMenu))
    databasebtn.place(relx=0.5, rely=0.3, anchor=tk.CENTER)

    # need to call mainloop() for a tkinter application
    MainMenu.mainloop()

def maindatabase(MainMenu):
    # function to close the toplevel and
    # show back the main window
    def back():
        DataMenu.destroy()
        MainMenu.deiconify()
        MainMenu.lift()

    MainMenu.withdraw()
    DataMenu = tk.Toplevel(MainMenu)
    DataMenu.title('Database Viewer')  # Creates a window with the title 'Database Viewer' that is 640x480 and with a gray background
    DataMenu.geometry('640x480')
    DataMenu.config(bg='gray')
    # make sure to restore root window when closing the toplevel
    # by any other ways
    DataMenu.protocol("WM_DELETE_WINDOW", back)

    tk.Label(DataMenu, text='Database Viewer', font=('Consolas', 40, 'bold'), bg='gray').pack()  # Shows a title 'Database Viewer'

    searchbtn = ttk.Button(DataMenu, text='Search', style='W.TButton')
    searchbtn.place(relx=0.5, rely=0.5, anchor=tk.CENTER)   # Creates a button and anchors it to the center

    fullbtn = ttk.Button(DataMenu, text='Full View', style='W.TButton')
    fullbtn.place(relx=0.5, rely=0.6, anchor=tk.CENTER)

    backbtn = ttk.Button(DataMenu, text='Back', command=back)
    backbtn.place(relx=0.9, rely=0.3, anchor=tk.CENTER)

if __name__ == "__main__":
    main()
0
On

There are two issues in this code example.

  1. In tkinter, it is a good practice to create one "Main Window" Tk(), and then you can use as many "Dialogs" Toplevel() as you want.

  2. "Style" ttk.Style() component requires the "Main Window" Tk() to already be created, if it's not, like in your case, "Style" ttk.Style() creates its own "Main Window" Tk(), and that is the reason you have two windows in your example.


Quick Solution:

  1. Change this line: MainMenu = Toplevel() to MainMenu = Tk(), and add MainMenu.mainloop() at the end of the main() function
  2. Comment out this line: style = ttk.Style(), and add it to the main() function right after the MainMenu = Tk()

Personal Recommendation: (OOP approach)

from tkinter import *
from tkinter import ttk

#style = ttk.Style()

class RCS():
    def __init__(self):
        self.main()

    def main(self):
        self.MainWindow = Tk()
        self.style = ttk.Style() # Declare the Style here, and you can use it later on Dialogs as well

        self.MainWindow.title('Rubiks Cube Solver')  # Creates a window with the title 'Rubiks Cube Solver' that is 640x480 and with a gray background
        self.MainWindow.geometry('640x480')
        self.MainWindow.config(bg='gray')
        #style.configure('W.TButton', font=('Consolas', 25), foreground = 'black')  # Style for the buttons
        Label(self.MainWindow, text='Rubiks Cube Solver', font=('Consolas', 40, 'bold'), bg='gray').pack()  # Shows a title 'Rubiks Cube Solver'
        timerbtn = ttk.Button(self.MainWindow, text='Timer', style='W.TButton')
        timerbtn.place(relx=0.5, rely=0.7, anchor=CENTER)   # Creates a button and anchors it to the center
        solverbtn = ttk.Button(self.MainWindow, text='Solver', style='W.TButton')
        solverbtn.place(relx=0.5, rely=0.5, anchor=CENTER)  
        databasebtn = ttk.Button(self.MainWindow, text='Database', style='W.TButton', command=self.maindatabase)
        databasebtn.place(relx=0.5, rely=0.3, anchor=CENTER)

        self.MainWindow.mainloop() # Don't forget the mainloop

    def maindatabase(self):
        self.MainWindow.withdraw()
        DataMenu = Toplevel(self.MainWindow)
        DataMenu.title('Database Viewer')  # Creates a window with the title 'Database Viewer' that is 640x480 and with a gray background
        DataMenu.geometry('640x480')
        DataMenu.config(bg='gray')
        Label(DataMenu, text='Database Viewer', font=('Consolas', 40, 'bold'), bg='gray').pack()  # Shows a title 'Database Viewer'
        searchbtn = ttk.Button(DataMenu, text='Search', style='W.TButton')
        searchbtn.place(relx=0.5, rely=0.5, anchor=CENTER)   # Creates a button and anchors it to the center
        fullbtn = ttk.Button(DataMenu, text='Full View', style='W.TButton')
        fullbtn.place(relx=0.5, rely=0.6, anchor=CENTER)  
        backbtn = ttk.Button(DataMenu, text='Back', command=lambda:[DataMenu.destroy(), self.MainWindow.deiconify()])
        backbtn.place(relx=0.9, rely=0.3, anchor=CENTER)
    
if __name__ == "__main__":
    rcs = RCS()