Search code examples
pythontkintergrid

TKinter Grid Pattern


I like to have all buttons on the right, spreade on a grid pattern, but no matter how .grid method I'm using, all of them keep steady in the middle of some widget frames.

What I should change?

I have deleted the code for radio buttons and the tree on the left side. Bottom of question: how do I modify existing classes (or create new ones) to get what I like?

current status

class MyApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        main_frame = tk.Frame(self, bg="#84CEEB", height=600, width=1024)
        main_frame.pack_propagate(0)
        main_frame.pack(fill="both", expand="true")
        main_frame.grid_rowconfigure(0, weight=1)
        main_frame.grid_columnconfigure(0, weight=1)
        # self.resizable(0, 0) prevents the app from being resized
        # self.geometry("1024x600") fixes the applications size
        self.frames = {}
        pages = (Some_Widgets, PageOne, PageTwo, PageThree, PageFour)
        for F in pages:
            frame = F(main_frame, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(Some_Widgets)
        menubar = MenuBar(self)
        tk.Tk.config(self, menu=menubar)

    def show_frame(self, name):
        frame = self.frames[name]
        frame.tkraise()

    def OpenNewWindow(self):
        OpenNewWindow()

    def Quit_application(self):
        self.destroy()


class GUI(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.main_frame = tk.Frame(self, bg="#BEB2A7", height=600, width=1024)
        # self.main_frame.pack_propagate(0)
        self.main_frame.pack(fill="both", expand="true")
        self.main_frame.grid_rowconfigure(0, weight=1)
        self.main_frame.grid_columnconfigure(0, weight=1)


class Some_Widgets(GUI):  # inherits from the GUI class
    def __init__(self, parent, controller):
        GUI.__init__(self, parent)

        frame1 = tk.LabelFrame(self, frame_styles, text="This is a LabelFrame containing a Treeview")
        frame1.place(rely=0.05, relx=0.02, height=400, width=400)

        frame2 = tk.LabelFrame(self, frame_styles, text="Some widgets")
        frame2.place(rely=0.05, relx=0.45, height=500, width=500)

        button1 = tk.Button(frame2, text="tk button", command=lambda: Refresh_data())
        button1.pack()
        button2 = ttk.Button(frame2, text="ttk button", command=lambda: Refresh_data())
        button2.pack()


Solution

  • If you want the buttons on the left to be on a grid with 4 columns, you could modify the Some_Widgets class:

    class Some_Widgets(GUI):  # inherits from the GUI class
        def __init__(self, parent, controller):
            GUI.__init__(self, parent)
    
            frame1 = tk.LabelFrame(self, frame_styles, text="This is a LabelFrame containing a Treeview")
            frame1.place(rely=0.05, relx=0.02, height=400, width=400)
    
            frame2 = tk.LabelFrame(self, frame_styles, text="Some widgets")
            frame2.place(rely=0.05, relx=0.45, height=500, width=500)
    
            # Create a frame to hold the buttons
            button_frame = tk.Frame(frame2)
            button_frame.pack(pady=10)
    
            # List of button details (text and command)
            buttons = [
                ("Button 1", lambda: print("Button 1 clicked")),
                ("Button 2", lambda: print("Button 2 clicked")),
                ("Button 3", lambda: print("Button 3 clicked")),
                ("Button 4", lambda: print("Button 4 clicked")),
                ("Button 5", lambda: print("Button 5 clicked")),
                # Add more buttons here as needed
            ]
    
            # Create and place buttons in a grid
            for index, (text, command) in enumerate(buttons):
                row = index // 4
                col = index % 4
                button = tk.Button(button_frame, text=text, command=command)
                button.grid(row=row, column=col, padx=5, pady=5)
    

    If you wanted a different number of columns, you could adjust the loop that places the buttons.

    The full code, including dummy implementations of classes that you access but did not implement:

    import tkinter as tk
    
    class MyApp(tk.Tk):
        def __init__(self, *args, **kwargs):
            tk.Tk.__init__(self, *args, **kwargs)
            main_frame = tk.Frame(self, bg="#84CEEB", height=600, width=1024)
            main_frame.pack_propagate(0)
            main_frame.pack(fill="both", expand="true")
            main_frame.grid_rowconfigure(0, weight=1)
            main_frame.grid_columnconfigure(0, weight=1)
            # self.resizable(0, 0) prevents the app from being resized
            # self.geometry("1024x600") fixes the applications size
            self.frames = {}
            pages = (Some_Widgets, PageOne, PageTwo, PageThree, PageFour)
            for F in pages:
                frame = F(main_frame, self)
                self.frames[F] = frame
                frame.grid(row=0, column=0, sticky="nsew")
            self.show_frame(Some_Widgets)
            menubar = MenuBar(self)
            tk.Tk.config(self, menu=menubar)
    
        def show_frame(self, name):
            frame = self.frames[name]
            frame.tkraise()
    
        def OpenNewWindow(self):
            OpenNewWindow()
    
        def Quit_application(self):
            self.destroy()
    
    
    class GUI(tk.Frame):
        def __init__(self, parent):
            tk.Frame.__init__(self, parent)
            self.main_frame = tk.Frame(self, bg="#BEB2A7", height=600, width=1024)
            # self.main_frame.pack_propagate(0)
            self.main_frame.pack(fill="both", expand="true")
            self.main_frame.grid_rowconfigure(0, weight=1)
            self.main_frame.grid_columnconfigure(0, weight=1)
    
    
    class Some_Widgets(GUI):  # inherits from the GUI class
        def __init__(self, parent, controller):
            GUI.__init__(self, parent)
    
            frame1 = tk.LabelFrame(self, frame_styles, text="This is a LabelFrame containing a Treeview")
            frame1.place(rely=0.05, relx=0.02, height=400, width=400)
    
            frame2 = tk.LabelFrame(self, frame_styles, text="Some widgets")
            frame2.place(rely=0.05, relx=0.45, height=500, width=500)
    
            # Create a frame to hold the buttons
            button_frame = tk.Frame(frame2)
            button_frame.pack(pady=10)
    
            # List of button details (text and command)
            buttons = [
                ("Button 1", lambda: print("Button 1 clicked")),
                ("Button 2", lambda: print("Button 2 clicked")),
                ("Button 3", lambda: print("Button 3 clicked")),
                ("Button 4", lambda: print("Button 4 clicked")),
                ("Button 5", lambda: print("Button 5 clicked")),
                # Add more buttons here as needed
            ]
    
            # Create and place buttons in a grid
            for index, (text, command) in enumerate(buttons):
                row = index // 4
                col = index % 4
                button = tk.Button(button_frame, text=text, command=command)
                button.grid(row=row, column=col, padx=5, pady=5)
    
    class MenuBar(tk.Menu):
           def __init__(self, parent):
               tk.Menu.__init__(self, parent)
    
    class PageOne(GUI):
        def __init__(self, parent, controller):
            GUI.__init__(self, parent)
    
    class PageTwo(GUI):
        def __init__(self, parent, controller):
            GUI.__init__(self, parent)
    
    class PageThree(GUI):
        def __init__(self, parent, controller):
            GUI.__init__(self, parent)
    
    class PageFour(GUI):
        def __init__(self, parent, controller):
            GUI.__init__(self, parent)
    
    frame_styles = {"relief": "groove",
                    "bd": 3, "bg": "#BEB2A7",
                    "fg": "#073bb3", "font": ("Arial", 9, "bold")}
    
    def Refresh_data():
        print("Data refreshed")
    
    if __name__ == "__main__":
        app = MyApp()
        app.mainloop()