0

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:

enter image description here

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.

enter image description here

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.

6
  • Before you use the .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 be Commented Jun 24 at 16:09
  • 1
    @TheLizzard That is what is being done in print_dimensions(), which is the last method called from __init__(), after creating and placing the widgets. Commented Jun 24 at 16:21
  • 2
    My bad - I didn't see the .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) Commented Jun 24 at 17:40
  • Same "glitch" on Windows 10 Pro. It works with .update() though. Thanks for the sugestion. Commented Jun 24 at 18:35
  • If .update() resolved your problem then maybe you could describe it as answer below. And later you could mark it as accepted answer. Commented Jun 25 at 12:04

1 Answer 1

1

As suggested by @TheLizzard, I changed update_idletasks() for update()and it works.

There seems to be a problem on Windows because @TheLizzard tested the original code on Ubuntu and it worked.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.