Home > Software engineering >  Why is Python Tkinter grid method separating the buttons
Why is Python Tkinter grid method separating the buttons

Time:01-02

I am trying to make a game using python 3.8, where I have 1 canvas/frame and 2 buttons. I want the buttons to be right next to each other but whenever I run the code, there is always white space in between the 2 buttons. I tried using pack() but when you click on the buttons, it makes the buttons go above the canvas/frame instead of to the right of it.

My code:

from tkinter import *

# windows, canvas, and frames
root = Tk()
WatchRun = Canvas(root, bg="green", width=600, height=500)
WatchRun.grid(row=0, column=0, rowspan=25)
Upgrade = Frame(root, bg="yellow", width=600, height=500)
Upgrade.grid_forget()

# button functions
def show_upgrade(widget, widget2):
    global upgradeBtn
    global WatchRunBtn
    widget.grid_forget()
    widget2.grid(row=0, column=0, rowspan=25)


def show_watchrun(widget, widget2):
    global upgradeBtn
    global WatchRunBtn
    widget.grid_forget()
    widget2.grid(row=0, column=0, rowspan=25)
    
# variables and buttons    
distance = 0
started = 0
money = 0
startImage = PhotoImage(file='start.png')
stopImage = PhotoImage(file='stop.png')
upgradeBtn = Button(root, text="Upgrades", width=9, command=lambda: show_upgrade(WatchRun, Upgrade))
upgradeBtn.grid(row=0, column=1)
WatchRunBtn = Button(root, text="Watch run", width=9, command=lambda: show_watchrun(Upgrade, WatchRun))
WatchRunBtn.grid(row=1, column=1)


#loop
root.mainloop()



    

CodePudding user response:

It appears you're trying to use rowspan to try to force the widgets apart. That's not a good solution.

While there are multiple ways to solve the problem of the buttons not being together, the one I recommend in this specific case is to treat your GUI as if it had three rows (or maybe four, depending on what you want to happen when you resize the window).

Row 0 holds the first button, row 1 holds the second, and row 2 takes up the rest of the GUI. Then, the canvas can span all three rows.

So, start by adding a non-zero weight to the third row so that all unallocated space goes to it.

root.grid_rowconfigure(2, weight=1)

Next, add your buttons to rows 0 and 1:

upgradeBtn.grid(row=0, column=1)
WatchRunBtn.grid(row=1, column=1)

And finally, have your canvas span all three rows. It will force the window to grow larger, with all extra space being given to the third row. This allows the first two rows to retain their natural small height.

WatchRun.grid(row=0, column=0, rowspan=3)

An arguably better solution involves using pack and an extra frame or two. The UI seems to clearly have two logical sections to it: a canvas on the left and a column of buttons on the right. So, you can create one frame for the left and one for the right. Then, put the buttons in the right frame and the canvas in the left frame.

CodePudding user response:

See my comments that indicates the changes in the code. If you have questions left on it, let me know. You may find this Q&A helpfull as well. PEP 8

import tkinter as tk #no wildcard imports

#free functions under imports to ensure function is defined
def show_frame(widget, widget2):
    '''common function for upgrade_btn and watchrun_btn
    - packs the appropiated widget in the left_frame'''
    widget.pack_forget()
    widget2.pack()
    
distance = 0
started = 0
money = 0

#variable names lowercase
root = tk.Tk()
#split window in two containers/master/frames
left_frame = tk.Frame(root)
right_frame= tk.Frame(root)
#leftframe content
watchrun = tk.Canvas(left_frame, bg="green", width=600, height=500)
upgrade = tk.Frame(left_frame, bg="yellow", width=600, height=500)
#rightframe content
upgrade_btn = tk.Button(right_frame, text="Upgrades", width=9, command=lambda: show_frame(watchrun, upgrade))
watchrun_btn = tk.Button(right_frame, text="Watch run", width=9, command=lambda: show_frame(upgrade, watchrun))
#geometry management
left_frame.pack(side=tk.LEFT)
right_frame.pack(side=tk.RIGHT,fill=tk.Y)
watchrun.pack()
upgrade_btn.pack()
watchrun_btn.pack()

root.mainloop()
  • Related