How to make tk.Button() fill width of window while using .grid()? - python

I've made a program that makes a pie chart using matplotlib.pyplot and it has a GUI which I made using tkinter, and I'm having problems with buttons. They don't fit the width of the window! This is the first time I'm using tkinter, so I don't know how to do that.
Here's the screenshot
Here's the snippet of my code which packs the buttons into the window:
append_btn = tk.Button(
text="Add values to register",
command=append
)
make_chart_btn = tk.Button(
text="Make chart",
command=make_chart
)
clear_btn = tk.Button(
text="Clear all registered values",
command=clear
)
exit_btn = tk.Button(
text="Exit Pie Chart Creator",
command=_exit_
)
append_btn.grid(row=4, column=1, sticky="E")
make_chart_btn.grid(row=4, column=2, sticky="W")
clear_btn.grid(row=5, column=1, sticky="E")
exit_btn.grid(row=5, column=2, sticky="W")

The code you have provided doesn't work. Please strip the unused functions out to make it work.
Nevertheless, the :
sticky="WENS"
flag is what you are looking for probably.
Sticky flag defines how to expand the widget if the resulting cell is larger than the widget itself. In your case you want to fill the cell thus expand it in all directions.
Thus the resulting window might look like this:
import tkinter as tk
append_btn = tk.Button(
text="Add values to register",
)
make_chart_btn = tk.Button(
text="Make chart",
)
clear_btn = tk.Button(
text="Clear all registered values",
)
exit_btn = tk.Button(
text="Exit Pie Chart Creator",
)
fill="WENS"
append_btn.grid(row=4, column=1, sticky=fill)
make_chart_btn.grid(row=4, column=2, sticky=fill)
clear_btn.grid(row=5, column=1, sticky=fill)
exit_btn.grid(row=5, column=2, sticky=fill)
tk.mainloop()

You have to add the width and height option in the button’s constructor:
button = tk.Button(root, text, width=your_size, height=your_size, command)

Related

grid layout just not aligning perfectly, even when following lecturer's code

I'm learning python doing a udemy course so its watching pre-recorded videos.
Following on recording laying out widgets on a screen (using tKinter) and just cannot get one button to align - even though I literally copy the code the lecturer has in the recording.
I am sure I am missing something really simple here. Everything lines up except the "Generate Password" button which is off to the right.
Its just a basic intro right now to GUI in Tkinter - so haven't gone into Frames as yet - just basic layouts.
Code is here - Everything aligns beautifully except the "Generate Password" button which shows up too far to the right - almost as if it is in another column...
from tkinter import *
def generate_pwd():
pass
def add_pwd():
pass
window = Tk()
window.title("Password Manager")
window.config(padx=50, pady=50)
# background canvas
canvas = Canvas(width=200, height=200)
img_lock = PhotoImage(file="logo.png")
canvas.create_image(100, 100, image=img_lock)
canvas.grid(column=1, row=0)
# widgets
lbl_website = Label(text="Website:")
lbl_website.grid(column=0, row=1, sticky=W)
lbl_email = Label(text="Email/UserName:")
lbl_email.grid(column=0, row=2, sticky=W)
lbl_password = Label(text="Password:")
lbl_password.grid(column=0, row=3, sticky=W)
ent_website = Entry(width=42)
ent_website.grid(column=1, row=1, columnspan=2, sticky=W)
ent_email = Entry(width=42)
ent_email.grid(column=1, row=2, columnspan=2, sticky=W)
ent_password = Entry(width=21)
ent_password.grid(column=1, row=3, sticky=W)
btn_generate = Button(text="Generate Password", command=generate_pwd)
btn_generate.grid(column=2, row=3)
btn_add = Button(text="ADD", width=35, command=add_pwd)
btn_add.grid(column=1, row=4, columnspan=2, sticky=W)
window.mainloop()
What I get:
From what I read, the width of a column is by default the width of its widest element; in your case, the culprit is the logo with its width of 100 that makes column 1 wider than it should be.
To fix this, just add a columnspan of 2 in your logo placement (in addition, the logo will be nicely centered):
...
canvas.create_image(100, 100, image=img_lock)
canvas.grid(column=1, row=0, columnspan=2)
...

Aligning entries/buttons with tkinter

I've been trying to align the entries and buttons on this password manager I built for a while now but haven't been able to find a solution that works.
I tried changing the width, columnspan, and coordinates but it doesn't seem to work.
I want the password entry to be aligned just like the other two but with a lower width so that the generate button does not go over. I also want the add button to be aligned equally with the row and column.
window = Tk()
window.title("Password Manager")
window.config(padx=50, pady=50)
canvas = Canvas(width=200, height=200)
my_pass_img = PhotoImage(file="logo.png")
canvas.create_image(100, 100, image=my_pass_img)
canvas.grid(column=1, row=0)
web_label = Label(text="Website:", fg="black")
web_label.grid(row=1, column=0)
user_label = Label(text="Email/Username:", fg="black")
user_label.grid(row=2, column=0)
pass_label = Label(text="Password:", fg="black")
pass_label.grid(row=3, column=0)
web_entry = Entry(width=35)
web_entry.grid(row=1, column=1, columnspan=2)
web_entry.focus()
user_entry = Entry(width=35)
user_entry.grid(row=2, column=1, columnspan=2)
user_entry.insert(0, "-#gmail.com")
pass_entry = Entry(width=30)
pass_entry.grid(row=3, column=1)
generate_button = Button(text="Generate Password", fg="black", command=generate_password)
generate_button.grid(row=3, column=2)
add_button = Button(width=36, text="Add", fg="black", command=save)
add_button.grid(row=4, column=1, columnspan=2)
window.mainloop()
Grid
When using grid to setup your widgets, the entire window is divided into individual cells based on the number of columns and rows you've specified. Although you can control the individual sizes of widgets, the overall size it can take will be limited by your choice of column- and rowwidth, as well as column- and rowspan.
Sticky
You can use the sticky attribute in grid to set the side of the column you want your widgets to 'stick' to.
The stickiness is set by choosing one of the 8 directions on a compass:
N (north): stick to top of cell
S (south): bottom
E (east): right
W (west): left
NW, NE, SW, SE: top-left, top-right, bottom-left, bottom-right corners respectively.
There are also two bonus stickiness options:
NS: stretch your widget from top to bottom of the sell, but keep it centered horizontally
EW: stretch from left to right of the cell, but centered vertically.
Padding
To increase legibility, you can add padding above and below, and to the sides, of your widgets using the padx and pady attributes (measured in pixels).
So if you set stickyness to "W" with a horizontal padding padx=5, the widget position is offset from the cell boundary by 5 pixels.
Combining it in your example
To align the entries, set their sticky attribute to "W", or tk.W, to algin on left side of cell.
If you want to align labels on the right set sticky="E".
You can reduce the columnspan too of the entries, if you don't need them to be extra large. The resulting changes to grid are thus:
canvas.grid(column=1, row=0)
# Label widgets: set sticky to 'East'
web_label.grid(row=1, column=0, sticky='E')
user_label.grid(row=2, column=0, sticky='E')
pass_label.grid(row=3, column=0, sticky='E')
# Entry widgets
web_entry.grid(row=1, column=1, columnspan=1, sticky='WE')
user_entry.grid(row=2, column=1, columnspan=1, sticky=tk.EW) # Note flag is available as tkinter attribute
# Password entry: align on left-hand side
pass_entry.grid(row=3, column=1, sticky='W')
# Align button to right side of 3rd column
generate_button.grid(row=3, column=2,sticky='E')
# Can either align in middle column...
add_button.grid(row=4, column=1, columnspan=1, sticky="WE")
#... or in middle of page
add_button.grid(row=4, column=0, columnspan=3, sticky="WE")
Bonus
Apply padding (or sticky) to all widgets in a frame or window:
for child in window.winfo_children():
child.grid_configure(padx=3, pady=3)
# child.grid_configure(sticky='W')
You can use sticky option to put the widget in a grid cell at "n" (north), "s" (south), "e" (east) and "w" (west). If not specify, it is by default is "" which will put the widget at the center of the cell.
For your case, add sticky="w" to all the labels and entries, and sticky="e" to the "Add" button:
from tkinter import *
def generate_password():
pass
def save():
pass
window = Tk()
window.title("Password Manager")
window.config(padx=50, pady=50)
canvas = Canvas(window, width=200, height=200)
my_pass_img = PhotoImage(file="logo.png")
canvas.create_image(100, 100, image=my_pass_img)
canvas.grid(column=1, row=0)
web_label = Label(window, text="Website:", fg="black")
web_label.grid(row=1, column=0, sticky="w")
user_label = Label(window, text="Email/Username:", fg="black")
user_label.grid(row=2, column=0, sticky="w")
pass_label = Label(window, text="Password:", fg="black")
pass_label.grid(row=3, column=0, sticky="w")
web_entry = Entry(window, width=35)
web_entry.grid(row=1, column=1, columnspan=2, sticky="w")
web_entry.focus()
user_entry = Entry(window, width=35)
user_entry.grid(row=2, column=1, columnspan=2, sticky="w")
user_entry.insert(0, "-#gmail.com")
pass_entry = Entry(window, width=30)
pass_entry.grid(row=3, column=1, sticky="w")
generate_button = Button(window, text="Generate Password", fg="black", command=generate_password)
generate_button.grid(row=3, column=2)
add_button = Button(window, width=36, text="Add", fg="black", command=save)
add_button.grid(row=4, column=1, columnspan=2, sticky="e")
window.mainloop()
Result:
You can play around with different values or combinations of them of the sticky option to see the different effects.
Note also that it is better to specify the parent of those widgets.

How can i attach my scroll bar to my text box on tkinter?

Im trying to use a vertical scrollbar for my text box but am coming across some problems:
I cant get the scroll bar to be directly touching the right side of the text box (so they are connected)
It seems the scroll bar wont affect my text box
I looked through some solutions but none seemed to work.
Heres my code:
from tkinter import *
writtenQ = Tk()
writtenQ.title("Written Response Question")
writtenQ.resizable(0,0)
header = LabelFrame(writtenQ, bg="white")
content = LabelFrame(writtenQ, bg="white")
header.columnconfigure(0, weight=1) # Forces column to expand to fill all available space
homeButton=Button(content,width=50,height=50)
try:
homeIcon=PhotoImage(file="yes.png")
homeButton.config(image=homeIcon)
homeButton.image = homeIcon
except TclError:
print("Home")
homeButton.grid(row=1, sticky="w", padx=15, pady=2)
#the image of the question will be put here
titleHeader = Label(content, text="Question Image here",pady=15, padx=20, bg="white", font=("Ariel",20, "bold"), anchor="w", relief="solid", borderwidth=1)
titleHeader.grid(row=2, column=0, columnspan=3, padx=15, pady=5, ipadx=370, ipady=150)
#this will allow the user to input their written response
answerInput = Text(content, width = 60, borderwidth=5, font=("HelvLight", 18))
answerInput.grid(row=3, column=0, ipady = 10, sticky="w", padx=(20,0), pady=20)
answerScrollBar= Scrollbar(content, command=answerInput.yview, orient="vertical")
answerScrollBar.grid(row=3, column=1, sticky="w")
submitButton = Button(content, borderwidth=1, font=("Ariel", 22), text="Submit", bg="#12a8e3", fg="black", activebackground="#12a8e3", relief="solid")
submitButton.grid(row=3, column=2, ipady=50, ipadx=70, sticky="nw", pady=20)
header.grid(row=0, sticky='NSEW')
content.grid(row=1, sticky='NSEW')
Configuring a scrollbar requires a two-way connection: the scrollbar needs to call the yview or xview method of the widget, and the widget needs to call the set method of the scrollbar.
Usually, this is done in three steps like in the following example:
answerInput = Text(...)
answerScrollBar= Scrollbar(..., command=answerInput.yview)
answerInput.configure(yscrollcommand=answerScrollBar.set)
You are forgetting the final step.
Unrelated to an actual functioning scrollbar, you're going to want to be able to see the scrollbar. You need to use sticky="ns" for the scrollbar so that it stretches in the Y direction. Otherwise it will only be a couple dozen pixels tall.
answerScrollBar.grid(row=3, column=1, sticky="ns")
Have you tried the solution here?
Let's say that the text widget is called text. Your code could be (excluding the setup of the window):
import tkinter
import tkinter.ttk as ttk
scrollb = ttk.Scrollbar(self, command=text.yview)
scrollb.grid(row=0, column=1, sticky='nsew')
text['yscrollcommand'] = scrollb.set
I have picked out what I think will be ueful for you from Honest Abe's answer. Hope it helped. Remember to set up your window before using the code...

Tkinter Python Remove Vertical Spaces

import tkinter as tk
root = tk.Tk()
buttonOK = tk.Button(root, text='B1')
MCC = tk.Button(root, text='B2')
TID = tk.Button(root, text='B3')
CURRENCY = tk.Button(root, text='B4')
COUNTRY = tk.Button(root, text='B5')
RESPONSE = tk.Button(root, text='B6')
B1.grid(row=3, column=0, sticky=tk.E+tk.W)
B2.grid(row=3, column=1, sticky=tk.E+tk.W)
B3.grid(row=3, column=2, sticky=tk.E+tk.W)
B4.grid(row=4, column=0, sticky=tk.E+tk.W)
B5.grid(row=4, column=1, sticky=tk.E+tk.W)
B6.grid(row=4, column=2, sticky=tk.E+tk.W)
label1 = tk.Entry(root, bd =8)
label1.grid(row=2, column=0, rowspan=1, columnspan=3, sticky=tk.E+tk.W)
label=tk.Text(root,background="yellow")
label.insert(index=0.0, chars="Enter values below\nand click search.\n")
label.grid(row=0, column=0,rowspan=1, columnspan=3, sticky=tk.E+tk.W)
root.mainloop()
I am trying to build a GUI in Python using Tkinter but the space for the inserted text label as "Enter values below\nand click search.\n" occupies about 6 blank rows. Please help me remove it. My current result using the code above is the left one, I want to have the right one image.
When you create the text widget, specify the number of lines you want it to display, for example:
label=tk.Text(root,background="yellow", height=3)
Failing to specify means it will default to 24, hence why it is so large in your program.
Ignoring the grid() mistake in your code.
You could correct the sizing issue by providing a weight and starting geometry size.
UPDATE:
If you provide weights to the proper rows and columns give your Text widget a default height of say 3 and tell the grid() on your Text widget to sticky="nsew" you can have your program start out the size you want and be able to resize evenly if you want to.
Take a look at the below code:
import tkinter as tk
root = tk.Tk()
# we want all 3 columns to resize evenly for the buttons so we provide
# a weight of 1 to each. We also want the first row where the text box is
# to resize so there is not unwanted behavior when resizing, so we set its weight to 1.
# keep in mind a weight of zero (default) will tell tkinter to not resize that row or column.
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.rowconfigure(0, weight=1)
buttonOK = tk.Button(root, text='B1')
MCC = tk.Button(root, text='B2')
TID = tk.Button(root, text='B3')
CURRENCY = tk.Button(root, text='B4')
COUNTRY = tk.Button(root, text='B5')
RESPONSE = tk.Button(root, text='B6')
# corrected the variables being assigned a grid location
buttonOK.grid(row=3, column=0, sticky=tk.E+tk.W)
MCC.grid(row=3, column=1, sticky=tk.E+tk.W)
TID.grid(row=3, column=2, sticky=tk.E+tk.W)
CURRENCY.grid(row=4, column=0, sticky=tk.E+tk.W)
COUNTRY.grid(row=4, column=1, sticky=tk.E+tk.W)
RESPONSE.grid(row=4, column=2, sticky=tk.E+tk.W)
label1 = tk.Entry(root, bd =8)
label1.grid(row=2, column=0, rowspan=1, columnspan=3, sticky=tk.E+tk.W)
# added a height of 3 to the Text widget. to reduce its starting height
label=tk.Text(root,background="yellow", height=3)
label.insert(index=0.0, chars="Enter values below\nand click search.\n")
# added stick="nsew" so the text box will resize with the available space in the window.
label.grid(row=0, column=0,rowspan=1, columnspan=3, sticky="nsew")
root.mainloop()

Why do Python Tkinter Radio Buttons align left?

I'm having an alignment issue with radio buttons. I want three columns of form elements. For some reason, when I add radio buttons to the form, they appear to take up space for a new column on the left. I was hoping for a simple grid layout with each cell having equal size. That doesn't appear to be the case. Any suggestions would be greatly appreciated!
Here is part of my code:
self._mode_state = StringVar()
self._mode_radio_timelapse = Radiobutton(self, text="Timelapse", command=self._transition(), value=self._timelapse_mode, variable=self._mode_state)
self._mode_radio_continuous = Radiobutton(self, text="Continuous", command=self._transition(), value=self._continuous_mode, variable=self._mode_state)
self._mode_radio_ramphold = Radiobutton(self, text="Ramp and Hold", command=self._transition(), value=self._ramp_hold_mode, variable=self._mode_state)
self._mode_radio_timelapse.grid(row=0, column=0, pady=10)
self._mode_radio_continuous.grid(row=0, column=1, pady=10)
self._mode_radio_ramphold.grid(row=0, column=2, pady=10)
image_set_label = Label(text="Image Set Type: ")
image_set_label.grid(row=1, column=0, pady=10)
self._image_set_type = Entry()
self._image_set_type.insert(0, "Ramp")
self._image_set_type.grid(row=1, column=1, pady=10, columnspan=2)
The widgets are not all on the same grid. The radio buttons are specifically set with a parent of self, but your Label and Entry widgets are not created with any parent so the parent defaults to the root object.
Here's the fix:
image_set_label = Label(self, text="Image Set Type: ") # made self parent
image_set_label.grid(row=1, column=0, pady=10)
self._image_set_type = Entry(self) # made self parent
self._image_set_type.insert(0, "Ramp")
self._image_set_type.grid(row=1, column=1, pady=10, columnspan=2)

Categories