Tkinter Geometry Return to Normal - python

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()

Related

Tkinter geometry method to only set width or height

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.

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.

How to wrap the text in a tkinter label dynamically?

The text in a label in tkinter can be wrapped into multiple lines when exceeding the limit given in the parameter wraplength.
However, this is a number of pixels, but instead, I'd like to use the full window width for this, and the wrap lenght should change whenever the user is changing the window size.
One approach could be to update the parameter manually with something like this:
def update_wraplength(id, root):
id.configure(wraplength=root.winfo_width())
root.after(10, lambda: update_wraplength(id,root))
Is there another way of doing this, maybe a parameter I do not know about?
You would have to update the wraplength every time the window size changes. You can detect when the window size changes with the "<Configure>" event.
my_label.bind('<Configure>', update_wraplength)
Remember it only works if you have the Label set up to expand to all available space.
Lets see if you can make sense of this code:
import Tkinter as tk
class WrappingLabel(tk.Label):
'''a type of Label that automatically adjusts the wrap to the size'''
def __init__(self, master=None, **kwargs):
tk.Label.__init__(self, master, **kwargs)
self.bind('<Configure>', lambda e: self.config(wraplength=self.winfo_width()))
def main():
root = tk.Tk()
root.geometry('200x200')
win = WrappingLabel(root, text="As in, you have a line of text in a Tkinter window, a Label. As the user drags the window narrower, the text remains unchanged until the window width means that the text gets cut off, at which point the text should wrap.")
win.pack(expand=True, fill=tk.X)
root.mainloop()
if __name__ == '__main__':
main()

Python tkinter placing a button in a grid inside a frame freezes on execution

I have created two frames using Tkinter. In one of the frames I am trying to add a button using a grid. When I run the program, there is no output. Instead it just freezes and I have to kill the process.
Here is the code:
from Tkinter import *
window=Tk()
window.title("calculator")
window.geometry("500x500")
window.resizable(0,0)
input_field=StringVar()
display_frame=Frame(window).pack(side="top")
button_frame=Frame(window).pack(side="bottom")
text=Entry(display_frame,font=('arial',20,'bold'),textvariable=input_field,justify="right").pack(fill="x",ipady=10)
clear_button=Button(button_frame,text="C").grid(row=0)
window.mainloop()
However, if I change the clear_button variable as
clear_button=Button(button_frame,text="C").pack()
I get an output. What am I missing here?
You cannot mix grid and pack inside the same container (a Frame/Window).
That said you should realize that your display_frame and button_frame variables are actually None! Why, because Frame(Window) will return a Frame object, but you have applied the pack() function just after that whose return value is None.
So basically the Entry and the Button widgets that you created have master=None and that means they are not inside the Frames that you defined, but actually part of the main Window.
Now you can easily see why clear_button=Button(button_frame,text="C").pack() was working as now the main window has only one geometry manager namely pack.
Here is the working code.
from tkinter import * # "Tkinter" on python 2
window=Tk()
window.title("calculator")
window.geometry("500x500")
window.resizable(0,0)
input_field=StringVar()
display_frame=Frame(window)
display_frame.pack(side="top")
button_frame=Frame(window)
button_frame.pack(side="bottom")
Entry(display_frame,font=('arial',20,'bold'),textvariable=input_field,justify="right").pack(fill="x",ipady=10)
Button(button_frame, text="C").grid(row=0)
window.mainloop()
You cannot use both grid and pack method on widgets having same master.
Here, follow the below thread for a detailed understanding :
python pack() and grid() methods together

Toplevel widgets in Tkinter

I have a Toplevel widget I'd like it so that it would never appear within the confines of the main Tk window. Basically so that when the Toplevel appears it doesn't cover up any of the main Tk window.
You want to use wm_geometry and a tiny bit of math to calculate and set a suitable starting position for the second toplevel.
You could just set up a separate toplevel, cf:
self.newwindow = Toplevel(self)
self.newwindow.title('New Window')
and then embed the widget in the separate toplevel.

Categories