I'm trying to create a Tkinter layout that has labels and entry fields vertically aligned across multiple LabelFrame boxes.
Here's some simplified code:
#!/usr/bin/python
from Tkinter import *
win = Frame()
win.grid(sticky=N+S+E+W)
frame_a = LabelFrame(win, text='Top frame', padx=5, pady=5)
frame_b = LabelFrame(win, text='Bottom frame', padx=5, pady=5)
frame_a.grid(sticky=E+W)
frame_b.grid(sticky=E+W)
for frame in frame_a, frame_b:
for col in 0, 1, 2:
frame.columnconfigure(col, weight=1)
Label(win, text='Hi').grid(in_=frame_a, sticky=W)
Label(win, text='Longer label, shorter box').grid(in_=frame_b, sticky=W)
Entry(win).grid(in_=frame_a, row=0, column=1, sticky=W)
Entry(win, width=5).grid(in_=frame_b, row=0, column=1, sticky=W)
win.mainloop()
The above code produces a window that looks like the below:
Whereas I'm looking to find some way of aligning the fields so the window looks more like this (with thanks to MS Paint):
I've played around with in_ arguments to grid(), but not achieved very much, and I can't think of anything else to experiment with.
The short answer is: you can't do what you want. grid does not manage its rows and columns across multiple containers.
However, there are at least a couple ways to achieve the effect you are wanting. One way is to give the first column in each container an explicit, identical width. To do that you can use the grid_columnconfigure method to give each column a minimum width.
Another solution is to give each label an identical width, which effectively will set the width of the first column to be the same (assuming all columns in each container have the same weight).
The easiest way I know to do what you want, is to change the make the Label text variables, and then, check the len(txt1) against len(txt2), and, set the width variable of both to the longest one. The following code is close. My knowledge is too limited to figure out where the extra space is coming from.
txt1 = StringVar()
txt2 = StringVar()
lblWidth = IntVar()
txt1 = "Hi"
txt2 = "Longer label, shorter box"
if (len(txt1) > len(txt2)):
lblWidth = len(txt1)
else:
lblWidth = len(txt2)
Label(win, text=txt1, width=lblWidth, anchor=W).grid(in_=frame_a)
Label(win, text=txt2, width=lblWidth, anchor=W).grid(in_=frame_b, sticky=W)
Related
I want to make a 'maze' game with tkinter, and I wanted to display some things under the grid(game area), and this happend:
Because I wanted to put the text in the last line and the first column of the grid.
frame = tk.Frame(window)
frame.grid(row=line+1, column=0)
label = tk.Label(master=frame, text="Dashing:")
label.pack()
Any ideas, how can I fix this?
Make the frame span all of the columns:
frame.grid(row=line+1, column=0, columnspan=17)
label = tk.Label(window, text="Guess a number that can be anything from '10' to '50', you have 5 chances !!!", fg="black", bg="white", font=("Arial Bold", 25))
label.grid(row=0)
inp = tk.Entry(window)
inp.grid(row=1)
Output Should Be Something Like this:
Guess a number that can be anything from '10' to '50'...
Input Field
but its:
Input field is away from the centre, why?
Use Sticky
import tkinter as tk
window =tk.Tk()
label = tk.Label(window, text="Guess a number that can be anything from '10' to '50', you have 5 chances !!!", fg="black", bg="white", font=("Arial Bold", 25))
label.grid(row=0)
inp = tk.Entry(window)
inp.grid(row=1,sticky="w")
window.mainloop()
Column zero has a very wide label in it which forces the column to be as wide as the label. The entry widget is in that same very wide column, and by default grid centers items in the column.
If you want the entry widget aligned to the left, you can use the sticky option to force the widget to "stick" to the west (left) side of the column.
inp.grid(row=1,sticky="w")
If these are the only two widgets in the UI, this is probably the right solution. If you plan to have other widgets aligned with either the label or the entry widget, you may need to do something else. Without knowing more about the final product it's hard to say for sure.
Another solution would be to configure the label to span two columns, and have the second column be given all of the extra space. That will cause the first column to be as small as necessary.
label.grid(row=0, columnspan=2)
window.grid_columnconfigure(1, weight=1)
The choice depends a bit on what else you plan to do with the window. If you're only going to have these two widgets and nothing else, the first solution requires one less line of code. The second solution makes it easier to add other widgets on the same row as the entry widget.
AANTAL = [(1,"1"),(2,"2"),(3,"3"),(4,"4"),(5,"5"),(6,"6"),]
v= StringVar()
v.set("1")
for text, mode in AANTAL:
but = Radiobutton(Main,padx=20, pady=10,font=('arial', 20, "bold"), bd=4, text=text, variable=v, value=mode, indicatoron=0)
but.grid()
The above code shows some radiobuttons numbered 1 to 6. However, it displays them vertically instead of horizontally. Does anyone know how I could fix this?
I already tried putting row=0 in the grid command but this only stacks the buttons on top of each other instead of spreading them out over a row.
grid has two options for placing a widget. row and column. You need to specify both.
buttons = []
vars = []
for idx, (text, mode) in enumerate(AANTAL):
vars.append(StringVar(value="1"))
buttons.append(Radiobutton(Main,padx=20, pady=10,font=('arial', 20, "bold"), bd=4, text=text, variable=vars[-1], value=mode, indicatoron=0))
buttons[-1].grid(row=0, column=idx)
Also, when using loops to create widgets, it is much better to store them in a list because you can access them later in your program.
I'm trying to create the some sample application.
Which first row is One label then input entry box then submit button.
Then second row has the another entry box.
My problem is when I increase width of the entry box in second row it affect the first row style. I don't know what is the problem.
import Tkinter
tk_obj = Tkinter.Tk()
tk_geo = tk_obj.geometry("1200x800")
Tkinter.Label(tk_obj, text='Enter query ').grid(row=1,column=1)
def callback():
print "hi"
E1 = Tkinter.Entry(tk_obj,bd=3,width=120)
E1.grid(row=1, column=2,ipady=3)
b = Tkinter.Button(tk_obj, text="Check", command=callback)
b.grid(row=1,column=3)
E2 = Tkinter.Entry(tk_obj,bd=3,width=100)
E2.grid(row=2,column=1,ipady=100)
tk_obj.mainloop()
The grid method places widgets in the center of the cell they inhabit. When you have two widgets of different sizes sharing a row or column, this means that there will be blank space around the smaller widget. To make the second Entry widget span the first two columns, use columnspan=2 when you grid() it. To left-align it within those two columns, use sticky='W':
E2.grid(row=2,column=1,ipady=100, columnspan=2, sticky='W')
You can then adjust that Entry widget's width attribute until it looks the way you want it to.
I built an application with Tkinter that displays statistics to labels based on what team is entered in a textbox. The application works, but my code is 600 lines long, most of which is initializing the labels. The majority of labels share the same format (create a label variable, create a label, position the label with grid), so I figured there should be a way that I can make a constructor class that will return me a new variable with a few parameters. Unfortunately I've so far been unsuccessful due mostly to the fact that I have little OOP design experience. What would be the best way to go about this? The following are the two main sections of code I'd like to replace:
self.team2RecordlabelVariable = Tkinter.StringVar()
team2Recordlabel = Tkinter.Label(self,textvariable=self.team2RecordlabelVariable,anchor='e', fg='white', bg="black")
team2Recordlabel.grid(column = rColLStart, row = 1, columnspan = colRSpan, padx=(2,10), pady=(1,20), sticky = 'E')
and
team2RL = Tkinter.Label(self,text="Record: ",anchor='e', fg='white', bg="black")
team2RL.grid(column = rColStart, row = 1, columnspan = colLSpan, padx=(2,0), pady=(1,20), sticky = 'W')
You can use a class if you just want to create a custom label, but IMO if you also want to call grid it's better to use a function. IMHO a widget should never call grid, pack or place on itself, since that limits how you use it.
Since you want to create the label and call grid at the same time, a simple helper function is all you need. In my example I'm also assuming you don't really need a StringVar for each label since you don't show any code that requires it.
def create_label(parent, text, row, column, colspan):
label = Tkinter.Label(parent, text=text, anchor='e', fg='white', bg="black")
label.grid(column = column, row = row, columnspan = colspan, padx=(2,10), pady=(1,20), sticky = 'E')
return label
...
self.team2Recordlabel = create_label(self, "", 1, rColLStart, colRSpan)