I am using Python 3.11 on Windows.
I don't understand the behaviour of winfo_geometry(), winfo_height(), winfo_x(), etc.
Here is my code:
import tkinter as tk
from tkinter import ttk
class Application:
def __init__(self, root):
self.root = root
self.root.title("Window title")
self.root.geometry("800x600")
self.define_styles()
self.place_widgets()
self.print_dimensions()
def define_styles(self):
self.dark = ttk.Style()
self.dark.configure('Dark.TFrame', background='#343434')
self.light_green = ttk.Style()
self.light_green.configure('LightGreen.TFrame', background='#a4edde')
self.light_blue = ttk.Style()
self.light_blue.configure('LightBlue.TFrame', background='#73d9eb')
def place_widgets(self):
self.frame_for_canvas = ttk.Frame(self.root, style='Dark.TFrame', width=500)
self.frm_right_panel = ttk.Frame(self.root, style='LightGreen.TFrame', width=200)
self.btn_1 = ttk.Button(self.frame_for_canvas, text='btn_1', command=self.f_btn1)
self.lbl_1 = ttk.Label(self.frame_for_canvas, text="lbl_1", width=40)
self.btn_1.pack()
self.lbl_1.pack()
self.frame_for_canvas.pack_propagate(0)
self.frame_for_canvas.pack(side='left', fill='both', expand=True)
self.frm_right_panel.pack_propagate(0)
self.frm_right_panel.pack(side='left', fill='both', expand=False)
self.frm_header1 = ttk.Frame(self.frm_right_panel, style='LightBlue.TFrame')
self.btn_2 = ttk.Button(self.frm_header1, text='btn_2', command=self.f_btn2)
self.lbl_2 = ttk.Label(self.frm_header1, text="lbl_2", width=40)
self.btn_2.pack()
self.lbl_2.pack()
self.frm_header1.pack(side='top', fill='x', expand=False)
self.frm_header2 = ttk.Frame(self.frm_right_panel, style='Dark.TFrame')
self.btn_3 = ttk.Button(self.frm_header2, text='btn_3', command=self.f_btn3)
self.lbl_3 = ttk.Label(self.frm_header2, text="lbl_3", width=40)
self.btn_3.pack()
self.lbl_3.pack()
self.frm_header2.pack(side='top', fill='x', expand=False)
def f_btn1(self):
self.lbl_1.config(text=self.frame_for_canvas.winfo_geometry())
self.print_dimensions()
def f_btn2(self):
self.lbl_2.config(text=self.frm_header1.winfo_geometry())
self.print_dimensions()
def f_btn3(self):
self.lbl_3.config(text=self.frm_header2.winfo_geometry())
self.print_dimensions()
def print_dimensions(self):
self.root.update_idletasks()
self.frame_for_canvas.update_idletasks()
self.frm_right_panel.update_idletasks()
self.frm_header1.update_idletasks()
self.frm_header2.update_idletasks()
print('self.root.winfo_geometry()', self.root.winfo_geometry())
print('self.root.winfo_height()', self.root.winfo_height())
print('self.root.winfo_width()', self.root.winfo_width())
print('self.root.winfo_x()', self.root.winfo_x())
print('self.root.winfo_y()', self.root.winfo_y())
print('self.frame_for_canvas.winfo_geometry()', self.frame_for_canvas.winfo_geometry())
print('self.frame_for_canvas.winfo_height()', self.frame_for_canvas.winfo_height())
print('self.frame_for_canvas.winfo_width()', self.frame_for_canvas.winfo_width())
print('self.frame_for_canvas.winfo_x()', self.frame_for_canvas.winfo_x())
print('self.frame_for_canvas.winfo_y()', self.frame_for_canvas.winfo_y())
print('self.frm_right_panel.winfo_geometry()', self.frm_right_panel.winfo_geometry())
print('self.frm_right_panel.winfo_height()', self.frm_right_panel.winfo_height())
print('self.frm_right_panel.winfo_width()', self.frm_right_panel.winfo_width())
print('self.frm_right_panel.winfo_x()', self.frm_right_panel.winfo_x())
print('self.frm_right_panel.winfo_y()', self.frm_right_panel.winfo_y())
print('self.frm_header1.winfo_geometry()', self.frm_header1.winfo_geometry())
print('self.frm_header1.winfo_height()', self.frm_header1.winfo_height())
print('self.frm_header1.winfo_width()', self.frm_header1.winfo_width())
print('self.frm_header1.winfo_x()', self.frm_header1.winfo_x())
print('self.frm_header1.winfo_y()', self.frm_header1.winfo_y())
print('self.frm_header2.winfo_geometry()', self.frm_header2.winfo_geometry())
print('self.frm_header2.winfo_height()', self.frm_header2.winfo_height())
print('self.frm_header2.winfo_width()', self.frm_header2.winfo_width())
print('self.frm_header2.winfo_x()', self.frm_header2.winfo_x())
print('self.frm_header2.winfo_y()', self.frm_header2.winfo_y())
if __name__ == '__main__':
root = tk.Tk()
app = Application(root)
root.mainloop()
The code creates this window:
At the same time, it prints this on my console:
self.root.winfo_geometry() 800x600+208+208
self.root.winfo_height() 600
self.root.winfo_width() 800
self.root.winfo_x() 208
self.root.winfo_y() 208
self.frame_for_canvas.winfo_geometry() 1x1+0+0 <--- weird
self.frame_for_canvas.winfo_height() 1
self.frame_for_canvas.winfo_width() 1
self.frame_for_canvas.winfo_x() 0
self.frame_for_canvas.winfo_y() 0
self.frm_right_panel.winfo_geometry() 1x1+0+0
self.frm_right_panel.winfo_height() 1
self.frm_right_panel.winfo_width() 1
self.frm_right_panel.winfo_x() 0
self.frm_right_panel.winfo_y() 0
self.frm_header1.winfo_geometry() 1x1+0+0 <--- weird
self.frm_header1.winfo_height() 1
self.frm_header1.winfo_width() 1
self.frm_header1.winfo_x() 0
self.frm_header1.winfo_y() 0
self.frm_header2.winfo_geometry() 1x1+0+0 <--- weird
self.frm_header2.winfo_height() 1
self.frm_header2.winfo_width() 1
self.frm_header2.winfo_x() 0
self.frm_header2.winfo_y() 0
Notice how, except for root, the dimensions are incorrect.
However, when I click on any of the 3 buttons, the corresponding labels below them are updated with the correct dimensions of the frames. If I resize the window and click the buttons, they are updated as well.
So if I call self.root.winfo_geometry(), self.root.winfo_width(), etc. after packing and displaying the widgets, the returned dimensions/values are not correct. Only after clicking the buttons and calling f_btn1(), f_btn2(), f_btn3() are these values displayed correctly.
According to the documentation here,
w.winfo_geometry() Returns the geometry string describing the size and on-screen location of w. See Section 5.10, “Geometry strings”.
Warning The geometry is not accurate until the application has updated its idle tasks. In particular, all geometries are initially '1x1+0+0' until the widgets and geometry manager have negotiated their sizes and positions. See the .update_idletasks() method, above, in this section to see how to insure that the widget's geometry is up to date.
That's why I am calling update_idletasks() inside print_dimensions(), but winfo_geometry() still returns 1x1+0+0.
Thanks in advance.


.winfo_methods on widgets, you first have to call.update_idletasks()or.update()so that the widget gets created at the internal GUI level. Alternatively, you can use.winfo_reqwidth()and.winfo_reqheight()but those only tell you the size the widget wants to beprint_dimensions(), which is the last method called from__init__(), after creating and placing the widgets..update_idletasks()in the code. The code you posted, works on Ubuntu using X11 but has the weird glitch on Windows 11. Changing the.update_idletasks()to.update()fixed the problem on Windows (python 3.11).update()though. Thanks for the sugestion..update()resolved your problem then maybe you could describe it as answer below. And later you could mark it as accepted answer.