How to spread widgets on screen? - python

Following is my sample code containing three labels and three entry fields:
import tkinter as tk
from tkinter import *
root = Tk()
root.resizable(width=False, height=False)
root.geometry("1200x700")
root.iconbitmap(r'.\autocrest.ico')
root.title('Autocrest Job Card')
root.columnconfigure(0, weight=20)
topRowFrame= Frame(root,relief="ridge", width=1000)
topRowFrame.config(bd=1, relief=tk.SUNKEN)
topRowFrame.columnconfigure(0, weight=1)
topRowFrame.columnconfigure(1, weight=4)
topRowFrame.columnconfigure(2, weight=1)
topRowFrame.columnconfigure(3, weight=4)
topRowFrame.columnconfigure(4, weight=1)
topRowFrame.columnconfigure(5, weight=4)
topRowFrame.grid(column=0,row=0, padx=5, pady=5, sticky=W)
bookingIdLabel=tk.Label(topRowFrame, text="Booking ID")
bookingIdLabel.grid(column=0,columnspan=2, row=0, padx=5, pady=5)
bookingIdEntry=Entry(topRowFrame)
bookingIdEntry.grid(column=2,columnspan=2, row=0, padx=5, pady=5)
noLabel=tk.Label(topRowFrame, text="No")
noLabel.grid(column=4,columnspan=2, row=0, padx=5, pady=5)
noEntry=Entry(topRowFrame)
noEntry.grid(column=6,columnspan=2, row=0, padx=5, pady=5)
dateLabel=tk.Label(topRowFrame, text="Date")
dateLabel.grid(column=8,columnspan=2, row=0, padx=5, pady=5)
dateEntry=Entry(topRowFrame)
dateEntry.grid(column=10,columnspan=2, row=0, padx=5, pady=5)
root.mainloop()
All of widgets in following code occupy space equal to their width only. I want to increase space between them. Columnspan and weight has no impact.

To be able to make widgets resizable as the screen resizes you need to use Grid.rowconfigure(root, index=0, weight=1). Root is the name of window/frame, index is number of the row and weight should be set to 1. You need to copy and paste this line of code and change index for the next row or use a for loop like this:
number_of_rows = 5
for i in range(number_of_rows):
Grid.rowconfigure(root, index=i, weight=1)
and apply the same for columns with Grid.columnconfigure().
Once you have done that put sticky="NSEW" so it sticks to every side of the window and fills it.

Columnspan and weight has no impact.
That is because you told grid to make topRowFrame only sticky to the left side of the window. Therefore it won't stretch to fill the whole column. Your use of root.columnconfigure(0, weight=20) makes the column fill the window, but the widget doesn't fill the column.
Try the value "ew" (east, west) for the sticky attribute if you want topRowFrame to be as wide as the window:
topRowFrame.grid(column=0,row=0, padx=5, pady=5, sticky="ew")

Related

TKinter Python make only one cell larger

I currently have this grid
https://imgur.com/a/ZELwflE
I want to make it like this:
https://imgur.com/a/SnBHW2S
Would it be possible? Heres my code:
import random
from tkinter import *
root = Tk()
root.title("TOMBOLA")
root.resizable(0, 0)
root.config(bg="WHITE")
entry= Entry(root, width= 40)
entry.focus_set()
entry.grid(column=1, row=0, padx=25)
texto=Label(root, text="Introduce el nombre para agregar a la tómbola:", font=("Courier")).grid(column=0, row=0, padx=(10,0))
boton_ok=Button(root, text="OK", width=10, height=2)
boton_ok.grid(row=0, column=3, padx=10, pady=(25,0))
listaindic = Label(root, text="Lista: ")
listaindic.grid(row=1, column=1, sticky=W)
display = Label(root, text="")
display.grid(row=1, column=2, columnspan=1, sticky=E)
boton_sig=Button(root, text="INICIAR TOMBOLA").grid(column=0, row=1, columnspan=1, pady=(0,15))
root.mainloop()
Thank you all so much
I tried making columnspan bigger, but didnt end well.
Tkinter relies on cells and rows to display widgets, without these there is no functionality. This being the case there is really no way of doing what you are asking in the first image. Everything has to be in a cell. So how I would try to fix your problem is by creating a tkinter.Frame and insert it into the cell you are trying to configure (1, 1). This creates another grid inside the frame so we can choose what to do with it. e.g: increasing the weight on the second column to make it seem much bigger.
newFrame = Frame(master=root)
newFrame.grid_rowconfigure(0, weight=1)
newFrame.grid_columnconfigure(0, weight=1)
newFrame.grid_columnconfigure(1, weight=3)
listaindic = Label(newFrame, text="Lista: ")
listaindic.grid(row=0, column=0, sticky=W)
This shows you how to create a basic frame, and putting the Label into the first cell.

GUI breaks on setting custom size of tkinter window?

I am creating a Calculator application with Tkinter, and I've included all the useful buttons there. But the problem is whenever I resize my Tkinter window to a custom size using geometry() method, all buttons don't scale up in the same ratio. To be precise, the buttons in the first column strech a lot leaving other buttons the same size they were. Is there a way to fix all this because it has become harder to include more things in the default size.
Here are some images:
Without custom geometry-
With custom geometry (800x800)-
Here's the useful bit of code:
root = Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.resizable(False, False)
segoe_font = tkFont.Font(family='Segoe UI', size=16)
segoe_font_ac = tkFont.Font(family='Segoe UI', size=8)
entry_text = StringVar()
inout = Entry(root, textvariable=entry_text)
inout.grid(row=0, column=0, columnspan=4, sticky="nsew")
button18 = Button(root, text="AC", command=allclear, font=segoe_font_ac).grid(row=1, column=0, sticky="nsew")
button1 = Button(root, text="C", command=clear, font=segoe_font).grid(row=1, column=1, sticky="nsew")
button2 = Button(root, text="/", command=divide, font=segoe_font).grid(row=1, column=2, sticky="nsew")
button3 = Button(root, text="×", command=multiply, font=segoe_font).grid(row=1, column=3, sticky="nsew")
button5 = Button(root, text="7", command=tsev, font=segoe_font).grid(row=2, column=0, sticky="nsew")
button6 = Button(root, text="8", command=teig, font=segoe_font).grid(row=2, column=1, sticky="nsew")
button7 = Button(root, text="9", command=tnin, font=segoe_font).grid(row=2, column=2, sticky="nsew")
button4 = Button(root, text="-", command=minus, font=segoe_font).grid(row=2, column=3, sticky="nsew")
button9 = Button(root, text="4", command=tfou, font=segoe_font).grid(row=3, column=0, sticky="nsew")
button10 = Button(root, text="5", command=tfiv, font=segoe_font).grid(row=3, column=1, sticky="nsew")
button11 = Button(root, text="6", command=tsix, font=segoe_font).grid(row=3, column=2, sticky="nsew")
button8 = Button(root, text="+", command=plus, font=segoe_font).grid(row=3, column=3, sticky="nsew")
button12 = Button(root, text="1", command=tone, font=segoe_font).grid(row=4, column=0, sticky="nsew")
button13 = Button(root, text="2", command=ttwo, font=segoe_font).grid(row=4, column=1, sticky="nsew")
button14 = Button(root, text="3", command=tthr, font=segoe_font).grid(row=4, column=2, sticky="nsew")
button15 = Button(root, text="=", command=equals, font=segoe_font).grid(row=4, column=3, rowspan=2, sticky="nsew")
button16 = Button(root, text="0", command=tzer, font=segoe_font).grid(row=5, column=0, columnspan=2, sticky="nsew")
button17 = Button(root, text=".", command=decimal, font=segoe_font).grid(row=5, column=2, sticky="nsew")
entry_text.trace("w", lambda *args: character_limit_and_check_entered_value(entry_text))
root.mainloop()
Can anyone help?
When you resize a window, the grid geometry manager will allocate extra space to every row and every column that has a non-zero weight. The weight is proportional, so a column with a weight of 2 will get twice as many of the extra pixels as a column with a weight of 1. By default, all columns have a weight of zero.
If you want every column or row to be given a percentage of extra available space, you need to give them a non-zero weight. If you want the columns or rows to have an identical width or height you can use the uniform option. All rows or columns with the same uniform value will be of a uniform height or width.
Since you explicitly gave a non-zero weight to only the first row and the first column, that row and column is going to be allocated all extra space. This is why the top entry widget grows in width and height, and all of the buttons in the first column grow in width.
In your case I'm guessing you want the top entry widget to stay the same height, while all of the buttons expand equally. To do that, remove your existing calls to rowconfigure and columnconfigure and replace them with the following:
root.grid_rowconfigure((1,2,3,4,5), weight=1, uniform="row")
root.grid_columnconfigure((0,1,2,3), weight=1, uniform="column")
I think this will help you. I made simple example with 6 buttons but I think you will manage to do it for your case. So I think best option is to use Grid.rowconfigure and Grid.columnconfigure funcitons.
Example code:
from tkinter import *
root = Tk()
root.title("resize button")
root.geometry("500x500")
# here you need to put on what do you want to use row configure, index(row) and weight
Grid.rowconfigure(root, 0, weight=1) # we use on root, row=0 weight=1
Grid.columnconfigure(root, 0, weight=1)
#configure 2nd row
Grid.rowconfigure(root, 1, weight=1)
#configure 3rd row
Grid.rowconfigure(root, 2, weight=1)
#configure 2nd column
Grid.columnconfigure(root, 1, weight=1)
button1 = Button(root, text="Button1")
button2 = Button(root, text="Button2")
button3 = Button(root, text="Button3")
button1.grid(row=0, column=0, sticky="nsew")
button2.grid(row=1, column=0, sticky="nsew")
button3.grid(row=2, column=0, sticky="nsew")
button1_1 = Button(root, text="Button1_1")
button2_1 = Button(root, text="Button2_1")
button3_1 = Button(root, text="Button3_1")
button1_1.grid(row=0, column=1, sticky="nsew")
button2_1.grid(row=1, column=1, sticky="nsew")
button3_1.grid(row=2, column=1, sticky="nsew")
root.mainloop()
Now buttons are resizing with canvas.

Put a grid vertical line between columns in the middle of the window in Python Tkinter

It's a little complicated, but I'll try my best to explain:
let's say that for example, I have a grid with 4 labels when I have 2 rows and 2 columns (see image below). I'm trying to make the vertical line between columns 1 and 2 (red line in the image) to be the line that splits the window into two equal halves.
You can see a sample of my initial code below.
Edit: note that the elements are labels just for example, but in my original code they are actually all different (some are frames, some images, some buttons, etc)
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text=1, width=8, height=2, bg="red")
label1.grid(row=0, column=0)
label2 = tk.Label(root, text=2, width=10, height=3, bg="green")
label2.grid(row=0, column=1)
label3 = tk.Label(root, text=3, width=5, height=4, bg="blue")
label3.grid(row=1, column=0)
label4 = tk.Label(root, text=4, width=6, height=2, bg="yellow")
label4.grid(row=1, column=1)
root.mainloop()
This code makes the vertical and horizontal center lines of each label perfect as I wanted, but the vertical line between columns 1 and 2 (red line in image) is nowhere near to be the center of the window.
Then, I have tried adding the grid_columnconfigure function to my code:
import tkinter as tk
root = tk.Tk()
root.grid_columnconfigure(0, weight=1) # the line I've added
label1 = tk.Label(root, text=1, width=8, height=2, bg="red")
label1.grid(row=0, column=0)
label2 = tk.Label(root, text=2, width=10, height=3, bg="green")
label2.grid(row=0, column=1)
label3 = tk.Label(root, text=3, width=5, height=4, bg="blue")
label3.grid(row=1, column=0)
label4 = tk.Label(root, text=4, width=6, height=2, bg="yellow")
label4.grid(row=1, column=1)
root.mainloop()
But now I have a different problem, where the columns don't touch each other.
I've also tried to fix the issue by adding the sticky arguments when I'm placing the elements in the grid, and also tried putting every row and every column in their own frame, but all of the solutions did not work out for me.
How can I get this to work? Hope my explanation was clear, and thanks in advance (;
You could just put the four images/labels together into a Frame (or any other container element) and then have that frame horizontally and vertically centered in your root frame with place.
c = tk.Frame(root, bg='white')
c.place(relx=0.5, rely=0.5, anchor='center')
Don't forget to change the parent of the labels from root to c, i.e. Label(c, ...).
Update: But this does not center the line between the red and the green block to the frame. You could combine this with uniform to make the columns equal width, but then there will be some padding between the center and the thinner column...
for n in (0, 1):
c.grid_columnconfigure(n, uniform="foo")
You can use a ttk.Separator widget.
You should use the following code part:
import tkinter.ttk
import tkinter as tk
root = tk.Tk()
---etc---
---etc---
---etc---
tkinter.ttk.Separator(master, orient=VERTICAL).grid(column=1, row=0, rowspan=2, sticky='ns')
root.mainloop()
You can get the grid info of a widget with "grid_info" method.
row = widget.grid_info()['row'] # Row of the widget
column = widget.grid_info()['column'] # Column of the widget
Since there are 2 columns, root.grid_columnconfigure(0, weight=1) only affects the first column.
Try
for n in range(2):
root.grid_columnconfigure(n, weight=1)
or
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)

Off-set position of tkinter scale using the .grid manager

I am currently writing a simple piece of inventory management software for a school python assessment. My GUI involves listing out all of the items in stock, and giving the user the ability to stock/sell multiple items at once. This was achieved by placing an entry (amount to buy) and a scale widget (amount to sell) next to each item, and utilizing an "apply" button to enact the changes (For context, the scenario is a comic book store):
https://i.imgur.com/7cesQm5.png
This is the code that I have used to create the new widgets from each file (all of which are contained in a dictionary, pulled from a CSV file):
itteration = 2
labels = {}
nameTitle = Label(main, text="Title").grid(row=1, column=1, padx=5)
stockTitle = Label(main, text="Stock").grid(row=1, column=2, padx=5)
buyTitle = Label(main, text="Amount to Buy").grid(row=1, column=3, padx=5)
sellTitle = Label(main, text="Amount to Sell").grid(row=1, column=4, padx=5)
for item in comic_books:
name = item.replace(" ", "")
nameStock = "{}Stock".format(item).replace(" ", "")
nameBuy = "{}Buy".format(item).replace(" ", "")
nameSell = "{}Sell".format(item).replace(" ", "")
labels[name] = Label(main, text=item+":")
labels[name].grid(column=1, row=itteration, padx=5)
labels[nameStock] = Label(main, text=comic_books.get(item))
labels[nameStock].grid(column=2, row=itteration, padx=5)
labels[nameBuy] = Entry(main)
labels[nameBuy].grid(column=3, row=itteration, padx=20)
labels[nameSell] = Scale(main, from_=0, to=comic_books.get(item), orient=HORIZONTAL)
labels[nameSell].grid(column=4, row=itteration, padx=5)
itteration += 1
However, I am not a fan of how the the scales appear to be centering themselves in the row based on both the center of the slider, and the number on top. This makes the slider appear lower than the entry widget next to it.
https://i.imgur.com/9CQTvWS.png
My question is: how would I go about potentially offsetting the position of the scale widgets upwards by a given amount (maybe 5-10px?) from its original position, to push the actual slider in line with the entry widget before it?
Please let me know if you need any extra clarification
Cheers,
-Sean
Using sticky='s' and sticky='n' to stick to bottom (south) and top (north) of cell I got this
I didn't use different values in pady
import tkinter as tk
root = tk.Tk()
l = tk.Label(root, text='Label')
l.grid(column=1, row=0, padx=5, sticky='s', pady=10)
e = tk.Entry(root)
e.grid(column=2, row=0, padx=20, sticky='s', pady=10)
s = tk.Scale(root, from_=0, to=10, orient='horizontal')
s.grid(column=3, row=0, padx=5, sticky='n', pady=10)
root.mainloop()
Using sticky with pady=(0,20) for one widget I got this
import tkinter as tk
root = tk.Tk()
l = tk.Label(root, text='Label')
l.grid(column=1, row=0, padx=5, sticky='s', pady=10)
e = tk.Entry(root)
e.grid(column=2, row=0, padx=20, sticky='s', pady=10)
s = tk.Scale(root, from_=0, to=10, orient='horizontal')
s.grid(column=3, row=0, padx=5, sticky='n', pady=(0,20))
root.mainloop()

Tkinter grid fill empty space

I did search for a lot of examples before posting but still can't properly use the tkinter grid.
What I want:
my code:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
b1 = ttk.Button(root, text='b1')
b1.grid(row=0, column=0, sticky=tk.W)
e1 = ttk.Entry(root)
e1.grid(row=0, column=1, sticky=tk.EW)
t = ttk.Treeview(root)
t.grid(row=1, column=0, sticky=tk.NSEW)
scroll = ttk.Scrollbar(root)
scroll.grid(row=1, column=1, sticky=tk.E+tk.NS)
scroll.configure(command=t.yview)
t.configure(yscrollcommand=scroll.set)
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.rowconfigure(1, weight=1)
root.mainloop()
The quick and simple solution is to define the columnspan of the treeview. This will tell the treeview to spread across 2 columns and allow the entry field to sit next to your button.
On an unrelated note you can use strings for your sticky so you do not have to do things like tk.E+tk.NS. Instead simply use "nse" or whatever directions you need. Make sure thought you are doing them in order of "nsew".
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
b1 = ttk.Button(root, text='b1')
b1.grid(row=0, column=0, sticky="w")
e1 = ttk.Entry(root)
e1.grid(row=0, column=1, sticky="ew")
t = ttk.Treeview(root)
t.grid(row=1, column=0, columnspan=2, sticky="nsew") # columnspan=2 goes here.
scroll = ttk.Scrollbar(root)
scroll.grid(row=1, column=2, sticky="nse") # set this to column=2 so it sits in the correct spot.
scroll.configure(command=t.yview)
t.configure(yscrollcommand=scroll.set)
# root.columnconfigure(0, weight=1) Removing this line fixes the sizing issue with the entry field.
root.columnconfigure(1, weight=1)
root.rowconfigure(1, weight=1)
root.mainloop()
Results:
To fix your issue you mention in the comments you can delete root.columnconfigure(0, weight=1) to get the entry to expand properly.

Categories

Resources