[Python] Python Tkinter: understanding winfo_geometry()

Discussão em 'Python' iniciado por Stack, Junho 24, 2025.

  1. Stack

    Stack Membro Participativo

    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:

    [​IMG]

    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.

    [​IMG]

    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.

    Continue reading...

Compartilhe esta Página