Home > front end >  Python Tkinter grid not working with classes
Python Tkinter grid not working with classes

Time:12-30

how do i change the position of the buttons with the grid system ??

I had it working without classes.

when i run the program it ignores the grid settings...

i want to use the grid system but it doesn't work.

this is how it looks now:

enter image description here

But i want something like this:

enter image description here

thanks in advance

import os
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
from tkinter.filedialog import askdirectory


class Frame(ttk.Frame):
    def __init__(self, container):
        self.options = {'padx': 5, 'pady': 5}
        super().__init__(container)
        self.grid(padx=5, pady=5, sticky=tk.NSEW)


class Button(Frame):
    def __init__(self, container, text, col, row, opt):
        super().__init__(container)
        self.path = tk.StringVar()
        self.button = ttk.Button(self, text=text)
        self.button['command'] = self.selectpath
        # HERE
        self.button.grid(column=col, row=row, sticky=tk.W, **opt)

    def selectpath(self):
        path_ = tk.filedialog.askdirectory()
        self.path.set(path_)


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        tk_width = 330
        tk_height = 150
        self.geometry(str(tk_width)   'x'   str(tk_height))
        x_left = int(self.winfo_screenwidth() / 4 - tk_width / 2)
        y_top = int(self.winfo_screenheight() / 2 - tk_height / 2)
        self.geometry(' {} {}'.format(x_left, y_top))
        self.resizable(False, False)


if __name__ == "__main__":
    app = App()
    window = Frame(app)
    selectbutton = Button(window, 'hello',  2, 0, window.options)
    selectbutton = Button(window, '1hello',  1, 1, window.options)
    app.mainloop()

CodePudding user response:

You use grid with wrong widget. You put every ttk.Button in new Button(Frame) so self.button.grid creates new grid in every Button(Frame) and it puts ttk.Button in this new frame, not in main grid in main Frame. Because there is only one ttk.Button in this grid so it displays it in the same place. Empty rows and columns in grid have no width nor height.

And every Button(Frame) uses self.grid without column= and row= so it put every Button(Frame) in new row in main Frame`.

You would have to use column=, row= with self.grid instead of self.button.grid

        # put `ttk.Button` in current `Button(Frame)`
        self.button.pack()  
        
        # put current `Button(Frame)` in main `Frame`
        self.grid(column=col, row=row, sticky=tk.W, **opt)

Minimal working code:

enter image description here

import os
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
from tkinter.filedialog import askdirectory


class Frame(ttk.Frame):
    def __init__(self, container):
        self.options = {'padx': 5, 'pady': 5}
        super().__init__(container)
        self.grid(padx=5, pady=5, sticky=tk.NSEW)


class Button(Frame):
    def __init__(self, container, text, col, row, opt):
        super().__init__(container)
        self.path = tk.StringVar()
        self.button = ttk.Button(self, text=text)
        self.button['command'] = self.selectpath
        
        # put `ttk.Button` in current `Button(Frame)`
        self.button.pack()  
        
        # put current `Button(Frame)` in main `Frame`
        self.grid(column=col, row=row, sticky=tk.W, **opt)

    def selectpath(self):
        path_ = tk.filedialog.askdirectory()
        self.path.set(path_)


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        tk_width = 330
        tk_height = 150
        self.geometry(str(tk_width)   'x'   str(tk_height))
        x_left = int(self.winfo_screenwidth() / 4 - tk_width / 2)
        y_top = int(self.winfo_screenheight() / 2 - tk_height / 2)
        self.geometry(' {} {}'.format(x_left, y_top))
        self.resizable(False, False)

if __name__ == "__main__":
    app = App()
    window = Frame(app)
    selectbutton = Button(window, 'hello' , 2, 0, window.options)
    selectbutton = Button(window, '1hello', 1, 1, window.options)
    app.mainloop()

EDIT:

Maybe you wouldn't have this problem if you would create Button(ttk.Button) instead of Button(Frame)

class Button(ttk.Button):

    def __init__(self, container, text, col, row, opt):
        super().__init__(container, text=text, command=self.selectpath)
        self.path = tk.StringVar(self)
        self.grid(column=col, row=row, sticky=tk.W, **opt)

    def selectpath(self):
        path = tk.filedialog.askdirectory()
        if path:
            self.path.set(path)

import os
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
from tkinter.filedialog import askdirectory


class Frame(ttk.Frame):
    
    def __init__(self, master):
        super().__init__(master)
        self.options = {'padx': 5, 'pady': 5}
        self.grid(padx=5, pady=5, sticky=tk.NSEW)


class Button(ttk.Button):

    def __init__(self, master, text, col, row, opt):
        super().__init__(master, text=text, command=self.selectpath)
        self.path = tk.StringVar(self)
        self.grid(column=col, row=row, sticky='w', **opt)

    def selectpath(self):
        path = tk.filedialog.askdirectory()
        if path:
            self.path.set(path)


class App(tk.Tk):

    def __init__(self):
        super().__init__()

        tk_width = 330
        tk_height = 150

        x_left = int(self.winfo_screenwidth()  / 4 - tk_width  / 2)
        y_top  = int(self.winfo_screenheight() / 2 - tk_height / 2)

        self.geometry(f'{tk_width}x{tk_height} {x_left} {y_top}')

        self.resizable(False, False)


if __name__ == "__main__":
    app = App()
    window = Frame(app)
    selectbutton = Button(window, 'hello' , 2, 0, window.options)
    selectbutton = Button(window, '1hello', 1, 1, window.options)
    app.mainloop()
  • Related