1

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()



    
Jeffrey
  • 35
  • 7
  • Why are you doing `rowspan=25` when you only have widgets in two rows? The other 23 rows will have a height of zero. Are you aware of that? – Bryan Oakley Jan 02 '22 at 00:04
  • yes, but it does help, rowspan=25 gives less white space in between the button than rowspan=2 – Jeffrey Jan 02 '22 at 00:11
  • It may help, but it doesn't actually solve the problem and it will make adding other widgets more difficult and more confusing. – Bryan Oakley Jan 02 '22 at 00:13

2 Answers2

2

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.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
1

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()
Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • @Matiiss still mad? I remeber, you was criticizing me and yes I didnt liked it. But you was right then.. on the newer topic I guess I wasnt on the wrong site. – Thingamabobs Jan 02 '22 at 01:38
  • @Matiiss you are right, its just not inside the PEP8. I was sure it would be there, just because functions needs to be defined before we could us'em. I tried to find a different source but there seems to be none. Updated my answer. – Thingamabobs Jan 02 '22 at 02:14