I am familiarizing myself with Tkinter, and I am attempting to write a very simple program, which displays a button in a window, using the pack geometry manager.
I was experimenting with various configuration options for pack(), such as expand, fill, and side, and I've run into a peculiar problem. I have written the following code:
from Tkinter import *
root = Tk()
widget = Button(root, text='text')
widget.pack(expand=YES, fill=BOTH)
root.mainloop()
The problem is that the button expands to fill the window in the horizontal direction, but not the vertical direction. This is the same result that I get if instead of specifying fill=BOTH I use fill=X. In addition, if I specify instead fill=Y the button does not expand in either direction. Something seems to be going wrong with the fill in the vertical direction, and I cannot figure out what it might be.
I attempted to Google this problem and surprisingly found no mention of this happening to anyone else. I am using a Mac with OS X Yosemite and running python 2.7.5. I also attempted to compile with python 3.4.1 and saw no change.
Edit:
Based off of the answer and comments below, it is clear that there is nothing wrong with my code, because it seems to work on other machines. If not an error in the code, does anyone know what could possibly be causing the button to not stretch vertically when I run the above code?
This is a feature of native buttons on OSX. Buttons on OSX will be a fixed height and will not expand vertically. There is nothing you can do, short of using a different widget such as a label.
try running this code to see the behavior of fill and expand
from Tkinter import *
root = Tk()
root.geometry("500x500")
widget = Button(root, text='text1')
widget.pack(fill=X, expand=1)
widget = Button(root, text='text2')
widget.pack(fill=Y, expand=1)
widget = Button(root, text='text3')
widget.pack(fill=BOTH, expand=1)
root.mainloop()
Argument fill does fill in vertical direction as well
I am also beginner, defining geometry for fill was missing in your code as given below:
from Tkinter import *
root = Tk()
root.geometry("600x400")
widget = Button(root, text='text')
widget.pack(expand=YES, fill=BOTH)
root.mainloop()
Related
Advice: i'm working on Windows 8.1, with Python and Tkinter at last version; i wrote from tkinter import * to post less code here, i know that it is a bad practice, use for example import tkinter as tk instead.
I'm coding my first text editor, and i have a problem when i resize the main windows. When i run the program it display on screen a window with dimension 750x500 pixel. So far, all ok, i can write text without problem (note that menu_bar and other features are work-in progress, but we dont care about them). Problem is with Text widget when user tries to resize window with cursor. The content of the text practically adapts to the size of the window (the length of each string is reduced or increased based on the width of the window). But i don't want that this happen. I want that Text widget changes his width automatically in base of window size, but the content mustn't be adapted. I hope that you understand my question, if not, i will try to explain better.
I have searched on online reference if there's a parameter to set this option, but i haven't found anything.
How to solve the problems concerning the Text widget and resizing the window?
from tkinter import *
root = Tk()
root.geometry("750x500")
content_text = Text(root, wrap=WORD, bg="grey25", undo=True, cursor="",
insertbackground="red", foreground="white", font="courier 12")
content_text.pack(fill=BOTH, expand=True)
scroll_bar = Scrollbar(content_text)
content_text.configure(yscrollcommand=scroll_bar.set, selectbackground="dodgerblue")
scroll_bar.configure(command=content_text.yview)
scroll_bar.pack(side=RIGHT, fill=Y)
if __name__ == '__main__':
root.mainloop()
You can't do what you want. If you have wrapping turned on, text will always wrap at the edge of the window. When you change the width of the window, the text will re-wrap to the new width. There is no configuration option to tell the widget to wrap at any other place.
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'm having a bizarre issue with the code below. If a user runs this code, and the very first thing they do (before even clicking in the window) is resize the window by the bottom-right corner, the scrollbar will automatically move down, instead of staying in place as you'd normally expect.
import tkinter as tk
def onResize(event):
"""Prints the scrollbar's position on window resize."""
print(str(myScrollbar.get()))
root = tk.Tk()
myFrame = tk.Frame(root)
mySecondaryFrame = tk.Frame(root)
myCanvas = tk.Canvas(myFrame)
myScrollbar = tk.Scrollbar(myFrame, orient='vertical', command=myCanvas.yview)
myCanvas.config(yscrollcommand=myScrollbar.set)
for i in range(0,100):
print(i)
button = tk.Button(mySecondaryFrame, text=i)
button.pack(fill='y',expand=True)
myCanvas.configure(scrollregion=(0, 0, 0, 3000))
myFrame.pack(fill='both',expand=True)
myScrollbar.pack(side="right",fill='y')
myCanvas.pack(side='right', fill='both', expand=True)
button_window = myCanvas.create_window(0, 0, anchor='nw', window=mySecondaryFrame)
myCanvas.bind('<Configure>', onResize)
tk.mainloop()
In the time I've spent on here looking for a solution to this without having to make a post, I came across the .get() method for scrollbars, and wondered if this would help me pinpoint the issue, hence its place in the code. Strangely enough, when the glitch occurs, I noticed from the print statements that the scrollbar is making tiny horizontal movements. Why is that, considering that the scrollbar is set to the canvas' y view? I'm not sure if this is a case of correlation != causation, but I thought it would be worth mentioning. Any help that could be given would be greatly appreciated. Thank you!
Well, this is embarrassing - the comment section prompted me to test this issue on Mac's Notes system - the same exact thing happens there. Seems it's just an oddity of Mac's scrollbar system, which Tkinter pulled its scrollbar from. Thanks to the users above! Hopefully this question can help anyone else who finds this behavior odd in the future.
I am redesigning the GUI of a program that uses tkinter in python. I used ttk widgets for this program, but I think, even on W10, the interface is way too old so I decided to update the visual interface for the program using METRO interface or W10 alike UI.
The first thing that come in mind, is that W10 have a left-side "tabs" that are very beautiful and useful, and the question is if is that a way to using the ttk.notebook widget, change the position of the tabs?
Otherwise, I could do buttons placed on the side and load frame widgets on every button clicked, but I think this could overload so much the program loading constantly frames and widgets, and I am trying to avoid this way.
Thanks to everyone.
It is possible to change the position of the tabs by configuring the tabposition option of the TNotebook style.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
style = ttk.Style(root)
style.configure('lefttab.TNotebook', tabposition='ws')
notebook = ttk.Notebook(root, style='lefttab.TNotebook')
f1 = tk.Frame(notebook, bg='red', width=200, height=200)
f2 = tk.Frame(notebook, bg='blue', width=200, height=200)
notebook.add(f1, text='Frame 1')
notebook.add(f2, text='Frame 2')
notebook.pack()
root.mainloop()
This is how it looks like with the default theme on linux:
However, the text inside the tabs is always horizontal. I don't have Windows, so I don't know exactly how the W10 UI looks like, but I guess that you would like to rotate the tabs, not just change there position and I don't know how to do that.
What is the equal function of PyQt setGeometry() in tkinter? Or Is there any function works like that? I searched a bit but couldn't find, all of examples looks like tkinter works on a specific widget and we just can set width-height.
EDIT:
The setGeometry() does two things. It locates the window on the
screen and sets its size. The first two parameters are the x and y
positions of the window. The third is the width and the fourth is the
height of the window.
The nearest thing tkinter has is probably the place geometry manager. With it you can set the x,y coordinates (either absolute or relative) and the width and height attributes (also absolute or relative).
For example, to place a label at 100,100 and with a width and height 50% of its parent you would do something like this:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Hello, world")
label.place(x=100, y=100, relwidth=.5, relheight=.5)
root.mainloop()
However, place is very rarely the right choice. Tkinter is very smart about picking the right size for widgets, and for laying them out. Without knowing the actual problem you're trying to solve it's hard to give good recommendations, but almost certainly, pack or grid will work better.
You can also do something similar to #BryanOakley's answer by the grid geometry manager:
from tkinter import *
root = Tk()
label = Label(root, bg='cyan')
label.grid(ipadx=100, ipady=50, padx=50, pady=50)
UPDATE: Please feedback why you think this answer is not useful.