john liao
john liao

Reputation: 257

the winfo_height() returns incorrect value in tkinter

The print output of my code is,

master.winfo_width:300,winfo_height:300

frame.winfo_width:300,winfo_height:269

why is frame.winfo_height() 269 rather than 300?

Environment: Windows 10 Home 64 bit edition, python 3.7.4, tkinter verion 8.4

import tkinter as tk
from PIL import Image, ImageTk


class MyFrame(tk.Frame, object):
    def __init__(self, master=None, width=10, height=10):
        super(MyFrame, self).__init__(master)
        self.bind_all('<Key>', self.keyevt)
        
    def keyevt(self, evt):
        print("self.winfo_width:%d,winfo_height:%d"%(self.winfo_width(),self.winfo_height()))


master = tk.Tk()
master.resizable(False, False)
master.geometry("300x300")
lander = ImageTk.PhotoImage(file="./csdn.png")

frame = MyFrame(master, width=300, height=300)
master.update()
canvas = tk.Canvas(frame)
canvas.pack()
frame.pack()
frame.update()
imagelander = canvas.create_image(150, 150, image=lander)
canvas.pack()

print("master.winfo_width:%d,winfo_height:%d"%(master.winfo_width(),master.winfo_height()))
print("frame.winfo_width:%d,winfo_height:%d"%(frame.winfo_width(),frame.winfo_height()))
master.mainloop()

Upvotes: 0

Views: 1964

Answers (1)

furas
furas

Reputation: 142691

Frame changes size to fit to size of its childrens.

Because Canvas has default height 267 so automatically Frame has the same size. If you set

 canvas = tk.Canvas(frame, height=300)

then Frame will have height 300 too.

You can also turn off this and frame will not change its size

 frame.propagate(False)

If you will need to resize Frame when window change size then more useful can be

 frame.pack(expand=True, fill='both')

BTW: To set size in your own frame you have to send size to `super()

super().__init__(master, width=width, height=height) # , bg='red')

Example code.

I added background colors to see size of Canvas (green) and Frame (red).

I also removed image so everyone can easily copy code and run it.

import tkinter as tk

class MyFrame(tk.Frame):
    def __init__(self, master=None, width=10, height=10):
        super().__init__(master, width=width, height=height, bg='red')
        self.bind_all('<Key>', self.keyevt)

    def keyevt(self, evt):
        print("self.winfo_width:%d,winfo_height:%d"%(self.winfo_width(),self.winfo_height()))

def test(event=True):
    print("master: {}, {}".format(master.winfo_width(), master.winfo_height()))
    print("frame : {}, {}".format(frame.winfo_width(), frame.winfo_height()))
    print("canvas: {}, {}".format(canvas.winfo_width(), canvas.winfo_height()))

master = tk.Tk()
master.resizable(False, False)
master.geometry("300x300")

frame = MyFrame(master, width=300, height=300)
frame.propagate(False)
frame.pack()#expand=True, fill='both')

canvas = tk.Canvas(frame, bg='green')#, height=300)
canvas.pack()

print('before update')
test()

master.update()
print('after update')
test()

print('200 ms after starting mainloop')
master.after(200, test)

#print('when window change size')
#master.bind('<Configure>', test)

master.mainloop()

Upvotes: 3

Related Questions