I am doing a simple UI with TkInter in Python. I want a button at the top left, so I did something like
back = Button(explorer, text="Back")
back.pack(side="top", anchor="w")
where explorer is a frame, and I expected to see the button on top left, but it's stuck in the center. Any suggestions? I already tried to add side=TOP but it didn't work. What's the right way to do that?
As mentioned above, your parent frame should fill the x space.
This is an example of the parent frame not filling x:
import tkinter as tk
root = tk.Tk()
root.geometry('200x200')
element = tk.Frame(root)
element.pack() # No fill
tk.Button(element, text='No Fill').pack(anchor='w')
# To show the fill
tk.Label(root, text='Fill X', bg='green').pack(fill='x')
root.mainloop()
And the result is the button is in the center despite the anchor:
https://i.stack.imgur.com/DAgmH.png
But, make this change:
element.pack(fill='x')
And now your button will be in the top left like here:
https://i.stack.imgur.com/HoGGj.png
Your frame has to occupy all the horizontal space if you want to align its children. Something like (if you imported tkinter elements with from tkinter import *):
explorer.pack(fill=X)
Tkinter has 3 modules to set items:
.pack which puts everything more or less random
.grid where you can define the row and column
.place where you define everything in pixels
so you could use something like
import tkinter as tk
from tkinter import *
root = Tk()
button = Button(text = 'back')
button.grid(row = 1, column = 1)
root.mainloop()
This shows how to use the .grid function. Keep in mind that the size of each grid is defined by its largest content. If you have a long entry field , the column its placed in is going to be as wide as the entry.
you could also use the .place function, but this one requires the most work. For me its always guessing and rerunning until im happy with it.
import tkinter as tk
from tkinter import *
root = Tk()
button = Button(text = 'back')
root.geometry("150x100")
button.place(x=30, y=30)
root.mainloop()
So in summary, use .pack if you dont care, .grid if you want some kind of control and .place if you want to be accurate. And keep in mind to use only ONE at a time.
Related
So I have one Tkinter screen that has a canvas. I want to change the size of the canvas by creating a new window that has entry widgets. So I created a new screen and added 2 entry widgets. I want to get the value from those widgets and based on that...it should change the size of the canvas. I tried to do this for an hour, but no luck. Please assist me.
Here is my code
from tkinter import *
# create root window
root = Tk()
# Create Canvas
canvas = Canvas(root, width=50, height=50)
# Create an additional window (the one that is used to enter the new geometry)
dialog = Toplevel(root)
# Add entry widgets for width and height to the new window
width_entry = tk.Entry(dialog)
height_entry = tk.Entry(dialog)
# Add a button to the new window that applies the given width and height
apply_button = Button(dialog, text = 'Apply geometry', command = lambda: canvas.geometry(width_entry.get()+'x'+height_entry.get()))
# Its not possible to get the geometry of a canvas in tkinter...so how do I change the size.
# display the entry boxes and button
width_entry.pack()
height_entry.pack()
apply_button.pack()
# start the tk mainloop
root.mainloop()
Please Assist me
The command you are looking for is canvas.config
Here, I have adjusted the given code:
import tkinter as tk
# create root window
root = tk.Tk()
# Create Canvas
canvas = tk.Canvas(root, width=50, height=50)
canvas.pack()
# Create an additional window (the one that is used to enter the new geometry)
dialog = tk.Toplevel(root)
# Add entry widgets for width and height to the new window
width_entry = tk.Entry(dialog)
height_entry = tk.Entry(dialog)
# Add a button to the new window that applies the given width and height
apply_button = tk.Button(dialog, text = 'Apply geometry', command = lambda: canvas.config(width=width_entry.get(), height=height_entry.get()))
# display the entry boxes and button
width_entry.pack()
height_entry.pack()
apply_button.pack()
# start the tk mainloop
root.mainloop()
I also changed a couple other things:
You imported * from tkinter, but for some items you still led with tk.; I changed them all to match that and switched the import to match as well. (You could still use *, but then just don't have the leading tk.s.)
The canvas was never packed so you could never see what was going on there.
One more suggestion, that line where you make the button is really long. Maybe make a function that does what the lambda does and assign its command to that function instead of a lambda. You can probably see that a line that long is even hard to read here much less if someone (maybe a future version of yourself) was to try to read your code, and edit it or make sense of it. Generally, try to keep all lines down to 80 characters.
Let us know if you have any more questions etc.
I am using Python 3.7, and I am using tkinter to try and grid a widget in the middle of the screen. I don't want to use pack, because I still need to use grid for other widgets later. Is there a way to to grid the widget in the middle of the window?
This might not be the best solution, but one way is to essentially create an entire grid.
In short, empty grid cells with some minimum width and then place the object in the centre-most grid box.
Something similar to this:
from tkinter import *
win = Tk()
for i in range(5):
win.grid_rowconfigure(i, minsize=100)
win.grid_columnconfigure(i, minsize=100)
lbl = Label(win, text="Test")
lbl.grid(row=2, column=2)
win.mainloop()
One thing to note is with this approach you might have to fidget with other widgets such as setting varying columnspans and rowspans during declaration.
I am trying to create a tkinter window with a button that is stuck at the bottom. I want the button to be used to add new items to the window (separate code, not shown here), but always keep the button at the bottom. Something like the following:
import tkinter as tk
m = tk.Tk(className="My window")
create = tk.Button(m, text="Create new item", width=25)
create.grid(row=inf, padx=40, pady=20)
m.mainloop()
except of course tkinter.grid() doesn;t accept inf as a valid value for row=. My question is how can I ensure that even as I add items to the tkinter window, my button will always remain on the bottom.
You can combine pack and grid.
Your base application could be this
upperframe.pack(side=tk.TOP)
bottomframe.pack(side=tk.BOTTOM)
Within the upperframe use your grid to add buttons and whatever. The bottom frame containing your changing buttons will be stuck there. You can use pack or grid or whatever you like there.
Creating a status bar goes much the same way.
Hi I didn't really understand how furas made the below code work. Why didn't he get an error message about grid and pack on the same root when he added a box? In the addbox function he sets a frame to the root which is pack already and even uses the pack inside the function and then uses the grid.
Can someone please explain to me how this "magic" works?
a link to the his answer:
Creating new entry boxes with button Tkinter
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
frame = Frame(root)
frame.pack()
Label(frame, text='From').grid(row=0, column=0)
ent1 = Entry(frame)
ent1.grid(row=1, column=0)
Label(frame, text='To').grid(row=0, column=1)
ent2 = Entry(frame)
ent2.grid(row=1, column=1)
all_entries.append( (ent1, ent2) )
#------------------------------------
def showEntries():
for number, (ent1, ent2) in enumerate(all_entries):
print number, ent1.get(), ent2.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
Thanks
There's no magic, it's just working as designed. The code uses pack in the root window, and uses grid inside a frame. Each widget that acts as a container for other widgets can use either grid or pack. You just can't use both grid and pack together for widgets that have the same master.
not really an answer but I think you will be helped by the link.
tkinter and it's layout is indeed a bit hard to understand.
I never understood how to deal with it until I stumbled over this presentation which explained the layout particulars in a way where I finally could get the hang of it.
Just putting it out there for others to find as well.
tkinter tutorial by beazley
I think you miss out on what pack and grid actually are. Consider such code:
import tkinter as tk
root = tk.Tk()
myFrame = tk.Frame(root)
myFrame.pack()
myButton1 = tk.Button(myFrame, text='This is button 1')
myButton2 = tk.Button(myFrame, text='This is button 2')
myButton1.grid(row=0, column=0)
myButton2.grid(row=1, column=0)
root.mainloop()
By creating root we create a new window. In this window we will put everything else. Then we create myFrame. Note, that the actual "thing" (in more adequate terms - widget) is created in line myFrame = tk.Frame(root). Note, that we have to specify where we are going to put this widget in brackets and we've written that it is going to be root - our main window. Blank frame probably isn't the best example since you can not see it being placed (not unless you use some more specifications at least), but still. We have created it, but not placed it in our user interface. The we use .pack() to place it. Now you refer to widgets as being used as packs or grids. That is not true though. Pack and grid are just the set of rules, on which the widgets are being placed inside some kind of window. Because of that, if you want to add something more to the root in our case, you will have to use .pack() again. Why? If you will give two sets of rules on how to place things on the screen for your computer - they will most likely conflict with each other. However, if we go one more level down and now want to place something inside our myFrame, we can again choose which set of rules to use. It is because it does not matter, where our frame is going to end up inside root, we now just want to specify where our Buttons 1 and 2 are going to end up inside the frame. Therefore we can again use .pack() or switch to .grid().
To conclude: .pack(), .grid() and .place() are sets of rules on how place widgets inside other widgets. In more general terms though these are rules on how place boxes in other boxes. One boxes in which we arrange other boxes can only have one set of rules.
I hope this example helps.
I am trying to get a label to be center justified between a given width, but it's not working. What am I doing wrong?
from tkinter import *
from tkinter.ttk import *
def main():
root = Tk()
root.geometry("200x100")
root.minsize(0,0)
root.resizable(0,0)
a = Label(master=root, text="Hello World", justify="center", background="red")
a.pack()
a.place(x=0,y=0, width=120)
mainloop()
main()
The text is properly justified in the label. The problem is that you didn't tell the label to stretch to fill the window. To do that, pack it like this:
a.pack(fill="x")
Also, it serves no purpose to call pack and then immediately call place -- only the last one will have any effect. Plus, you should avoid using place unless you have no other choice. Place is fine, but it makes your program harder to maintain, and harder to get it to grow and shrink.