Tkinter geometry method to only set width or height - python

The following will set a tkinter window width and height.
root.geometry("500x500")
Is it possible to only set width or height?
Where can I find a full list of geometry method variations, for setting only select parameters?
I would like to be able to set select parameters, of the window size and/or position, and let the rest be under tkinter dynamic control.

When looking at the tcl/tk documentation, we can see that we do not have to provide a full "widthxheight±x±y" string to the .geometry() method:
with only "widthxheight", the size of the window will be changed but not its position on the screen.
with only "±x±y", the position will be changed but not the size.
However, it is not possible to set separately the width and height of the window with this method. Nevertheless, you can retrieve the dimension you don't want to change and use it in .geometry() with something like
def set_height(window, height):
window.geometry("{}x{}".format(window.winfo_width(), height))
def set_width(window, height):
window.geometry("{}x{}".format(width, window.winfo_height()))
Note: Using root.config(width/height=...) only works for me if the window has never been resized with the mouse or using .geometry()

Use root.config(width=100) or root.config(height=100)

If you define a frame within your window you can set width and height of this frame separately like this:
myframe = tk.Frame(width=200)
This may create the appearance you wish to achieve.
An example program demonstrates how to use this trick:
import tkinter as tk
window = tk.Tk()
window.title('Frame Demo')
frame = tk.Frame(width=300)
frame_2 = tk.Frame()
label = tk.Label(master=frame_2, text="Frame_2")
label.pack()
frame.pack()
frame_2.pack()
window.mainloop()
The frame by the name frame is used only to widen the window and is invisible. No GUI elements should be placed in it. Its only function is to give the main window the needed size of 300, in this example. frame_2 is the canvas, so to say, for the GUI elements.

Related

How do I change the size of a tkinter canvas through a new window?

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.

Tkinter Widget color does not change

When I put a widget inside the frame, the color of the frame vanishes. If it was 'black' before, then after putting a widget(label) inside the frame, the color again becomes white.
Here's my code:
from tkinter import *
root = Tk()
root.geometry("700x600")
f = Frame(root, height = 400, width = 400, bg = 'black')
f.pack()
id = Label(f, text = "Email:", fg = 'blue', font = ('Kristen ITC', 18))
id.pack()
Your Frame is resizing itself to the Label. You need to set...:
...
f.pack_propagate(False)
f.pack()
...
In order for the Frame to maintain its own dimension without affected by the its children widgets.
By default, widgets shrink or expand to fit their contents. When you add the button, the frame shrinks down to fit.
It appears you want the frame to take up just a part of the root window. Instead of explicitly giving the frame a width and height, it's usually better to let tkinter do that for you. Fill the frame with whatever widgets you want, and let tkinter decide how big the frame should be. Then, use appropriate options for grid or pack to arrange them logically. When tkinter is allowed to make widgets the right size, you'll end up with a much more responsive UI.
For example, if you set the fill and expand options when you call pack on the frame, it will not shrink to fit. If you later need to add more widgets, you won't have to modify other parts of your code to make them fit.
f.pack(fill="both", expad=True)
You can also turn off this "shrink to fit" feature by calling f.pack_propagate(False), but that is rarely the right solution because it forces you to calculate sizes, and your calculations may be wrong if you run the program on a system with different fonts or different resolutions.

pack_propagate(0) equivalent for Grid and place

I am trying to place a button on a frame for an application that am working on...
But the frame disappears when I use pack or grid
from Tkinter import *
root=Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
root.geometry(str(width)+'x'+str(height))
frame=Frame(root,width=500, height=500, bg='black')
but1=Button(frame,text='qwe')
but1.grid()
frame.grid()
root.mainloop()
And if I use place, even worse, both of them disappear...I dont see the Frame and the Button
from Tkinter import *
root=Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
root.geometry(str(width)+'x'+str(height))
frame=Frame(root,width=500, height=500, bg='black')
but1=Button(frame,text='qwe')
but1.place()
frame.place()
root.mainloop()
but when I use pack_propagate(0), I can see them both...
from Tkinter import *
root=Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
root.geometry(str(width)+'x'+str(height))
frame=Frame(root,width=500, height=500, bg='black')
but1=Button(frame,text='qwe')
but1.pack()
frame.pack_propagate(0)
frame.pack()
root.mainloop()
My Questions are,
What does pack_propagate(0) mean ?
Why is the frame behaving weird with and without pack_propagate(0) ?
What is the equivalent of pack_propagate(0) for GRID and PLACE ?
What does pack_propagate(0) mean ?
pack_propagate(0) tells tkinter to let the parent control its own size, rather than letting it's size be determined by the children of the widget when using pack to manage the children.
Why is the frame behaving weird with and without pack_propagate(0)
I don't see any weird behavior. You'll have to be more precise about what you mean by "weird". It's behaving as documented. place will not cause the children to determine the size of the parent. If you don't give the frame a size, it's size will be 1x1 (ie: a single pixel). And, if the frame is invisible, any widgets inside the frame will also be invisible.
When you use pack or grid, the frame will try to shrink to fit its children. It doesn't disappear, you just can see it because its children are on top of it. If you add some padding, you'll see the frame.
For example, in the first block, change where you call grid on but1 to be like the following code and your black frame will appear:
but1.grid(padx=20, pady=20)
This is one of the reasons why place is rarely the right choice. Both pack and grid do a really great job of making sure all widgets are just the right size based on what is inside them.
What is the equivalent of pack_propagate(0) for GRID and PLACE
For grid it's grid_propagate. There's no equivalent for place because that's the defined behavior of place -- it never affects the size of the containing widget.
For the vast majority of cases, you should not use pack_propagate(0), grid_propagate(0), or place. When you use grid and pack properly, your gui will be the right size on every platform you run it on, no matter what the resolution and no matter what fonts the user has loaded.

Tkinter Geometry Return to Normal

I have a tkinter window which I am able to make fullscreen, using geometry(width+height) and overrideredirect(True), but now when I return the window back to a normal size and execute the command overrideredirect(False), I cannot seem to get the window to automatically follow the size of the widgets inside it, as it would do had I not changed the size. Do you know any way which I could return the window to automatically following the size of the widgets again? Thank You in Advance!
Call the geometry with a value of "" to get it to reset itself to its natural size.
Tkinter is based on tk, and the tk docs say this on the matter:
If newGeometry is specified as an empty string then any existing
user-specified geometry for window is cancelled, and the window will
revert to the size requested internally by its widgets.
I believe you're looking for the winfo_reqwidth/reqheight() methods. These return the required width and height for all the widgets that are children of the widget they're called on. Just plug those into the geometry() method the same way you did to go fullscreen on your restore function, like this:
def fullscreen():
root.overrideredirect(True)
root.geometry('{0}x{1}+0+0'.format(root.winfo_screenwidth(), root.winfo_screenheight()))
def restore():
root.overrideredirect(False)
root.geometry('{0}x{1}'.format(root.winfo_reqwidth(), root.winfo_reqheight()))
root = Tk()
Button(root, text='Full Screen', command=fullscreen).pack()
Button(root, text='Restore', command=restore).pack()
root.mainloop()

Why is tkinter not recognizing that this window is being resized?

When I try to detect that a window is resized with tkinter, it works most of the time. However, there is one exception; that is, when resizing it for the first time vertically and making the window larger, nothing is picked up. I see the initial size when the window appears, but nothing after that if I try to immediately make the window larger vertically. However, if I try to make it vertically "taller," after resizing it another way (ie making it smaller or resizing horizontally), then it works fine.
Here's the gist of the code I'm using:
from Tkinter import *
main = Tk()
def resize(event):
print("The new dimensions are:",event.width,"x",event.height)
window.focus_set()
canvas = Canvas(main, width=850, height=400)
window = Frame(main, width=800, height=10)
window.focus_set()
canvas.bind("<Configure>", resize)
canvas.pack()
canvas.update()
window.pack()
main.mainloop()
Am I doing something wrong?
If it matters, I'm using Python 2.7.3 on 64 bit Ubuntu 12.10
EDIT: It seems as though the dimensions are either incorrect (horizontal enlargement) or not showing up at all (vertical enlargement) when the window size is above 852x402. Is this a problem with my window manager (ie, Unity)?
Change canvas = Canvas(main, width=850, height=400) by canvas = Canvas(main, width=850, height=400, bg="red") and see what happens.
Since the canvas is inside the root window, when you make the window vertically larger, you are not changing the canvas size or position. It maintains its maximum height of 400, and the handler is not called. However, in the case of the horizontal enlargement, its position is exactly the middle because of the call to pack(): That's why it moves, and the bound function is called.
The rest of the results when you make the window smaller both horizontally and vertically are as expected.
It's because the canvas is not being resized. You're setting the binding on the canvas, but you haven't configured the canvas to grow and shrink along with the containing window.
Try setting the background of the canvas and frame widgets to something distinctive and you'll see what I mean.
To fix the problem try setting the expand and fill attributes when packing your widgets.

Categories