I have been looking all over the web trying to find an a way to size a TopLevel() window in tkinter. I read the documentation and have been looking at effbot.org's tkinterbook. I see the options but I just can't seem to get them to work.
def test():
top = Toplevel()
top.title("test")
msg = Message(top, text="test")
msg.pack(pady=10, padx=10)
def test1():
top = Toplevel()
top.title("test1")
msg = Message(top, text="test1")
msg.pack(pady=10, padx=10)
I know that there are height and width options and there is also root.geometry. However I just cant seem to get anything with TopLevel to work...
Also, is the best way to create a new window through a definition and toplevel? All I am wanting is a pop-up window with some formatted text in it.
The following creates a root window then sets its size to 400x400, then creates a Toplevel widget and sets its size to 500x100:
>>> import tkinter as tk
>>> root = tk.Tk()
>>> root.geometry('400x400')
''
>>> top = tk.Toplevel()
>>> top.geometry('500x100')
''
Another option is to use a container widget, like a Canvas or Frame, of your desired size into the window you'd like to work with. Then you can place other objects into this container:
>>> top2 = tk.Toplevel()
>>> frame = tk.Frame(top2, width=100, height=100)
>>> frame.pack()
When you pack() the frame, top2 is automatically adjusted to fit frame's size.
Using geometry() to set a size of AxB results in the same size window as placing an AxB widget into a dynamically-sized window - that is, if you put in a widget (or use geometry() to set the window size to) the width of your screen, the window's borders will be just outside the visible area of your screen.
Related
actually I am making a project with the help of tkinter in python so basically I want to shrink my font size of a label according to the width of the frame that it will be put in. I want that just i am giving a string and it will automatically adjust the size of the font according to the width.
For an Example:- Let I am Giving a String that is " Hotel Raj Kundra and Family Resturant", let the width of the Frame/label is 500.
so how it will automatically adjust in this size of window without wrapped the text. just fit in the window size
with .config you can adjust Attributes after you placed it.
Now you can adjust the window size with the len() of your string.
I hope it helps.
import tkinter as tk
def adjust_Window(canvas, text):
canvas.config(width=len(text)*50)
def main():
root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=500)
canvas.pack()
adjust_Window(canvas, "i hope it helps <3")
root.mainloop()
if __name__ == '__main__':
main()
Easier way to do this:
from tkinter import *
from tkinter import ttk
# Create an instance of tkinter frame or window
win=Tk()
# Set the size of the window
win.geometry("700x350")
def update_width():
l.configure(text='Hotel Raj Kundra and Family Resturant', background='blue', foreground='white', font=("Calibri,8,itlaic"))
# Create a frame
frame=Frame(win, background="skyblue3", width=700, height=250)
frame.pack()
# Add a button in the main window
ttk.Button(win, text="Update", command=update_width).pack()
l = ttk.Label(win, background='red', text="so how it will automatically adjust in this size of window without wrapped the text. just fit in the window siz" , font=("Calibri,32,Bold"))
l.pack()
win.mainloop()
Result widest:
Result to shrink:
As the title suggests, I'm wondering if it's possible to get the height of a frame full of widgets before it is packed and displayed.
Here is some example code:
import tkinter as tk
root = tk.Tk()
frame = tk.Frame(root, bg='green')
label = tk.Label(frame, text='hello')
label.pack(side='top')
button = tk.Button(frame, text='Test Button')
button.pack(side='top')
print(frame['height']) # Outputs 0
frame.pack(side='top')
root.mainloop()
I want to be able to do this so that if the frame is taller than a specific threshold, it will instead go inside a scrollable canvas.
Thanks.
As stated in TheLizzard's comment, I can do this by using the following code:
...
frame.update()
print(frame.winfo_reqheight())
frame.pack(side='top')
...
I'm making a GUI and I'm stuck trying to resize a listbox. The listbox is supposed to expand to fill the frame but instead, the frame shrinks to fit the listbox.
Thanks, in advance, for any help.
I have tried many variations of the code, but none seem to work, so I simplified the code (it still does't work) to put it on here.
import tkinter as tk
w = tk.Tk() # New window
f = tk.Frame(w, width=300, height=500, bg='red') # New frame with specific size
f.grid_propagate(0)
f.grid(row=0, column=0)
lb = tk.Listbox(f, bg='blue') # New listbox
lb.pack(fill=tk.BOTH, expand=True)
I ran these sequentially in IDLE and the frame appears (in red) at the correct size, however, when I pack the listbox, the whole window shrinks to the size of the listbox (and turns completely blue, which is expected).
In my experience, turning off geometry propagation is almost never the right solution. With a couple of decades of using tk and tkinter I've done that only two or three times for very specific edge cases.
Tkinter is very good at making the widget the best size based on the set of widgets you're using. Turning off propagation means you are responsible for doing all calculations to get the window to look right, and your calculations may not be correct when your program runs on a machine with different fonts or a different resolution. Tkinter can handle all of that for you.
Unfortunately, with such a small code example and without knowing your end goal it's hard to solve your layout problems. If your goal is to have a window that is 300x500, the best solution is to make the window that size and then have the frame fill the window, which is easier to do with pack than grid:
import tkinter as tk
w = tk.Tk() # New window
w.geometry("300x500")
f = tk.Frame(w, bg='red') # New frame with specific size
f.pack(fill="both", expand=True)
lb = tk.Listbox(f, bg='blue') # New listbox
lb.pack(fill=tk.BOTH, expand=True)
w.mainloop()
Thank you so much to Tls Chris for your answer and explanation. What I didn't realize is that grid_propagate() and pack_propagate() also affect a widget's children.
Therefore, with the help of Tls Chris, I have fixed my code and it now expands the listbox and doesn't shrink the frame.
Fixed code:
import tkinter as tk
w = tk.Tk() # New window
f = tk.Frame(w, width=300, height=500, bg='red') # New frame
f.grid_propagate(False) # Stopping things (that use grid) resizing the frame
f.pack_propagate(False) # Stopping things (that use pack) resizing the frame
f.grid(row=0, column=0)
lb = tk.Listbox(f, bg='blue') # New listbox
lb.pack(fill=tk.BOTH, expand=True) # Packing the listbox and making it expand and fill the frame
Edit: I think you actually want the listbox to expand to fit the frame. Amended the code to do that as an option
I haven't used pack much but I suspect that grid_propagate changes the behaviour of the grid geometry manager but not of the pack manager.
The below lets app() run with or without propagate set. It uses the grid geometry manager throughout.
import tkinter as tk
def app(propagate = False, expand = False ):
w = tk.Tk() # New window
tk.Label( w, text = 'Propagate: {} \nExpand: {}'.format(propagate, expand) ).grid()
f = tk.Frame(w, width=300, height=500, bg='red') # New frame with specific size
f.grid_propagate(propagate)
f.grid( row=1, column=0 )
lb = tk.Listbox(f, bg='blue') # New listbox
if expand:
f.columnconfigure(0, weight = 1 )
f.rowconfigure(0, weight = 1 )
# lb.pack(fill=tk.BOTH, expand=True)
lb.grid( row=0, column=0, sticky = 'nsew' )
# My guess is that grid_propagate has changed the behaviour of grid, not of pack.
lb.insert(tk.END, 'Test 1', 'Test 2', 'Test 3')
w.mainloop()
This changes the listbox geometry manager to grid. Run app() as below.
app(True, True) # propagate and Expand
app(False, True) # no propagate but expand
app(True, False) # propagate without expand
app() # no propagate or expand
I want to ask u guys if there is a way of getting name or some id of widget which is mouse pointer currently on. Is there a way of doing this? Thanks for any response.
Normally you get this information from a binding. However, if you want to poll the system at any point to find out which widget is under the mouse, you can use winfo_pointerxy to get the coordinates of the mouse, and then pass those to winfo_containing to get the widget under those coordinates.
Here's an example program that continuously prints out the widget under the mouse:
import tkinter as tk
def print_widget_under_mouse(root):
x,y = root.winfo_pointerxy()
widget = root.winfo_containing(x,y)
print("widget:", widget)
root.after(1000, print_widget_under_mouse, root)
root = tk.Tk()
label_foo = tk.Label(root, text="Foo", name="label_foo")
label_bar = tk.Label(root, text="Bar", name="label_bar")
button = tk.Button(root, text="Button", name="button")
button.pack(side="bottom")
label_foo.pack(fill="both", expand=True)
label_bar.pack(fill="both", expand=True)
print_widget_under_mouse(root)
root.mainloop()
I'm programming a little game with tkinter and briefly, I'm stuck.
I have a kind od starting menu, in which are two buttons and one label.
If I just create the frame everything is fine, it has the size 500x500 pixels
I want the background not to change when I create the buttons and the labe, but it adapts the size whatever I do. Here is my code:
import tkinter as tk
def startgame():
pass
mw = tk.Tk() #Here I tried (1)
mw.title('The game')
back = tk.Frame(master=mw, width=500, height=500, bg='black')
back.pack()
go = tk.Button(master=back, text='Start Game', bg='black', fg='red',
command=lambda:startgame()).pack()
close = tk.Button(master=back, text='Quit', bg='black', fg='red',
command=lambda:quit()).pack()
info = tk.Label(master=back, text='Made by me!', bg='red',
fg='black').pack()
mw.mainloop()
I've searched around on stackoverflow and didn't get anything useful!
I've found just one question a bit similar to mine but the answer didn't work. I tried this:
(1) mw.resizable(width=False, height=False)
I can't imagine what is the problem, I'm really desperate.
You turn off pack_propagate by setting pack_propagate(0)
Turning off pack_propagate here basically says don't let the widgets inside the frame control it's size. So you've set it's width and height to be 500. Turning off propagate stills allows it to be this size without the widgets changing the size of the frame to fill their respective width / heights which is what would happen normally
To turn off resizing the root window, you can set root.resizable(0, 0), where resizing is allowed in the x and y directions respectively.
To set a maxsize to window, as noted in the other answer you can set the maxsize attribute or minsize although you could just set the geometry of the root window and then turn off resizing. A bit more flexible imo.
Whenever you set grid or pack on a widget it will return None. So, if you want to be able to keep a reference to the widget object you shouldn't be setting a variabe to a widget where you're calling grid or pack on it. You should instead set the variable to be the widget Widget(master, ....) and then call pack or grid on the widget instead.
import tkinter as tk
def startgame():
pass
mw = tk.Tk()
#If you have a large number of widgets, like it looks like you will for your
#game you can specify the attributes for all widgets simply like this.
mw.option_add("*Button.Background", "black")
mw.option_add("*Button.Foreground", "red")
mw.title('The game')
#You can set the geometry attribute to change the root windows size
mw.geometry("500x500") #You want the size of the app to be 500x500
mw.resizable(0, 0) #Don't allow resizing in the x or y direction
back = tk.Frame(master=mw,bg='black')
back.pack_propagate(0) #Don't allow the widgets inside to determine the frame's width / height
back.pack(fill=tk.BOTH, expand=1) #Expand the frame to fill the root window
#Changed variables so you don't have these set to None from .pack()
go = tk.Button(master=back, text='Start Game', command=startgame)
go.pack()
close = tk.Button(master=back, text='Quit', command=mw.destroy)
close.pack()
info = tk.Label(master=back, text='Made by me!', bg='red', fg='black')
info.pack()
mw.mainloop()
If you want a window as a whole to have a specific size, you can just give it the size you want with the geometry command. That's really all you need to do.
For example:
mw.geometry("500x500")
Though, you'll also want to make sure that the widgets inside the window resize properly, so change how you add the frame to this:
back.pack(fill="both", expand=True)
Try parent_window.maxsize(x,x); to set the maximum size. It shouldn't get larger even if you set the background, etc.
Edit: use parent_window.minsize(x,x) also to set it to a constant size!
Here is the most simple way.
import tkinter as tk
root = tk.Tk()
root.geometry('200x200')
root.resizable(width=0, height=0)
root.mainloop()
I don't think there is anything to specify.
It's pretty straight forward.
There are 2 solutions for your problem:
Either you set a fixed size of the Tkinter window; mw.geometry('500x500')
OR
Make the Frame adjust to the size of the window automatically;back.place(x = 0, y = 0, relwidth = 1, relheight = 1)
*The second option should be used in place of back.pack()
from tkinter import *
root = Tk()
width = root.winfo_screenwidth() #get your Windows width size
height = root.winfo_screenheight() #get your Windows height size
root.geometry("%dx%d" % (width, height))
root.resizable(False,False)
root.mainloop()
#full size Tkinter