0

I am fairly new to tkinter and I'm using the code from the top comment in this post:Switch between two frames in tkinter with some changes to be able to switch between two frames. The problem is that I can't get my second one to centre or any other frame that isn't the first one when I add it for that matter. Apologises if I'm making any obvious mistakes as I said I'm still getting to know tkinter and python and I don't really understand how the code from this post works. Here is my code:


import tkinter as tk              

class MainView(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)


        container = tk.Frame(self)
        container.pack(expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        self.frames["LoginFrame"] = LoginFrame(parent=container, controller=self)
        self.frames["RegisterFrame"] = RegisterFrame(parent=container, controller=self)

        self.frames["LoginFrame"].grid(row=0, column=0, sticky="NESW")
        self.frames["RegisterFrame"].grid(row=0, column=0, sticky="NESW")


        self.ShowFrame("LoginFrame")

    def ShowFrame(self, PageName):
        frame = self.frames[PageName]
        frame.tkraise()


class LoginFrame(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        WelcomeLabel = tk.Label(self, text="Welcome to Detention Organiser!",font=(None,20) ).grid(columnspan=2)
        UsernameLabel = tk.Label(self, text="Username",font=(None,15) ).grid(row=1, sticky="E")
        PasswordLabel = tk.Label(self, text="Password",font=(None,15) ).grid(row=2, sticky="E")

        UsernameEntry  = tk.Entry(self).grid(row=1, column=1, sticky="W")
        PasswordEntry = tk.Entry(self, show="*").grid(row=2, column=1, sticky="W")

        LoginButton = tk.Button(self, text="Login").grid(columnspan=2)
        RegisterButton = tk.Button(self, text="Sign Up",command=lambda: controller.ShowFrame("RegisterFrame")).grid(columnspan=2)



class RegisterFrame(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        self.Variable = tk.StringVar()
        self.Variable.set("7A")

        RegisterLabel = tk.Label(self, text="Register",font=(None,20)).grid(columnspan=2)
        UsernameLabel = tk.Label(self, text="Username",font=(None,15)).grid(row=1, sticky="E")
        PasswordLabel = tk.Label(self, text="Password",font=(None,15)).grid(row=2, sticky="E")
        FormGroupLabel = tk.Label(self, text="Form Group",font=(None,15) ).grid(row=3, sticky="E")

        UsernameEntry  = tk.Entry(self).grid(row=1, column=1, sticky="W")
        PasswordEntry = tk.Entry(self, show="*").grid(row=2, column=1, sticky="W")
        FormGroupDrop  = tk.OptionMenu(self,self.Variable,"7A","7B","8A","8B").grid(row=3, column=1, sticky="W")

        RegisterButton = tk.Button(self, text="Register",command=lambda: controller.ShowFrame("RegisterFrame"))
        RegisterButton.grid(columnspan=2)
        BackButton = tk.Button(self, text="Back",command=lambda: controller.ShowFrame("LoginFrame")).grid(columnspan=2)



if __name__ == "__main__":
    app = MainView()
    app.geometry("640x360")
    app.mainloop()
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Pathfinder
  • 23
  • 4

1 Answers1

0

First thing, in general in your program, avoid doing something like:

UsernameEntry  = tk.Entry(self).grid(row=1, column=1, sticky="W")

because the variable UsernameEntry is not a tk.Entry as you would expect, and will definitely cause a bug sometimes. Instead, use one of the following:

# If you need the variable later
UsernameEntry  = tk.Entry(self)
UsernameEntry.grid(row=1, column=1, sticky="W")

# Otherwise
tk.Entry(self).grid(row=1, column=1, sticky="W")

Now, back to your problem. What is missing is that you don't tell how the program should allocate the remaining space (The space that is not necessary to contain your widgets). By default, the grid will place your widgets as close as possible to the top/left of the container. To change this behaviour, you will need to use grid_columnconfigure and/or grid_rowconfigure. For example,

self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1)

tells the program that the remaining space should be equally split between column 0 and column 1. The weight can be any non-negative integer value:

self.grid_columnconfigure(0, weight=3)
self.grid_columnconfigure(1, weight=0)
self.grid_columnconfigure(2, weight=1)

This tells the program to allocate 3/4 of remaining space to column 0, None to column 1 and 1/4 to column 2. By default, all weights are 0.

Then, your classes LoginFrame and RegisterFrame might look like

class LoginFrame(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        self.grid_rowconfigure(5, weight=1) # Fills vertical space below the last row
        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)

        tk.Label(self, text="Welcome to Detention Organiser!",font=(None,20) ).grid(columnspan=2)
        tk.Label(self, text="Username",font=(None,15)).grid(row=1, sticky="E")
        tk.Label(self, text="Password",font=(None,15)).grid(row=2, sticky="E")

        tk.Entry(self).grid(row=1, column=1, sticky="W")
        tk.Entry(self, show="*").grid(row=2, column=1, sticky="W")

        tk.Button(self, text="Login").grid(row=3, columnspan=2)
        tk.Button(self, text="Sign Up",command=lambda: controller.ShowFrame("RegisterFrame")).grid(row=4, columnspan=2)


class RegisterFrame(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        self.Variable = tk.StringVar()
        self.Variable.set("7A")

        self.grid_rowconfigure(5, weight=1) # Fills vertical space below the last row
        self.grid_columnconfigure(0, weight=0)
        self.grid_columnconfigure(1, weight=1)

        tk.Label(self, text="Register",font=(None,20)).grid(columnspan=2)
        tk.Label(self, text="Username",font=(None,15)).grid(row=1, sticky="E")
        tk.Label(self, text="Password",font=(None,15)).grid(row=2, sticky="E")
        tk.Label(self, text="Form Group",font=(None,15) ).grid(row=3, sticky="E")

        tk.Entry(self).grid(row=1, column=1, sticky="W")
        tk.Entry(self, show="*").grid(row=2, column=1, sticky="W")
        tk.OptionMenu(self,self.Variable,"7A","7B","8A","8B").grid(row=3, column=1, sticky="W")

        RegisterButton = tk.Button(self, text="Register",command=lambda: controller.ShowFrame("RegisterFrame"))
        RegisterButton.grid(columnspan=2)
        tk.Button(self, text="Back",command=lambda: controller.ShowFrame("LoginFrame")).grid(columnspan=2)

Finally, tkinter has many many different options that you need to test to really understand how they work. As you do some tests, I advise you to extensively use the option bg="COLOR", that will change the background of a widget and tell you precisely its boundaries. For instance,

        tk.Frame.__init__(self, parent, bg="RED")
Tawy
  • 579
  • 3
  • 14