Get height/width of tkinter Canvas
Asked Answered
N

3

6

I am searching for this for ages now. Is it so hard to get the height/width of a Canvas in tkinter? I want to do something like this:

c = Tk.Canvas(self, heigth=12, width=12)
c.create_oval(0, 0, self.height, self.width)

So that I draw a circle with the circumference of the width/height of my canvas.

How come I can't find any attribute like width/height of that canvas? c.winfo_width and c.winfo_height wouldn't work, because that only gives me error.

Can you help me? This is really irritating, since even in the constructor there is the attribute heightand width...

Nolly answered 7/3, 2021 at 12:57 Comment(3)
You have to call <tkinter.Tk>.update before winfo_height.Selfrestraint
Also you said that it gives it wouldn't work, because that only gives me error. What is the error traceback?Selfrestraint
@Selfrestraint Funnily enough when I tried your answers solution, afterwardsc.winfo_width and c.winfo_height also worked. But I'll stick with @hussics answerNolly
Q
6

Use winfo_reqwidth and winfo_reqheight:

root = tk.Tk()
c = tk.Canvas(root, height=120, width=120)
c.create_oval(0, 0, c.winfo_reqheight(), c.winfo_reqwidth())

c.pack()
root.mainloop()
Quarry answered 7/3, 2021 at 13:29 Comment(2)
Perfect! Thank you!Nolly
Just saying that this wouldn't always work. winfo_reqheight gets the heith the widget requires not the real height. To prove this put the canvas inside a frame: tk.Frame(root, width=10, height=10) and call frame.pack_propagate(False)Selfrestraint
S
3

You have to call <tkinter.Tk>.update and <tkinter.Canvas>.pack before the winfo_height like this:

import tkinter as tk

root = tk.Tk()
c = tk.Canvas(root, height=120, width=120)
c.pack()

root.update()
c.create_oval(0, 0, c.winfo_height(), c.winfo_width())

root.mainloop()

Also parts of this code are stolen from @hussic.

<tkinter.Tk>.update makes sure that all tkinter tasks are done. Those tasks can be things like making sure that the geometry manager was reserved the space for the widgets and the widgets are drawn on the screen. Calling <tkinter.Widget>.update where Widget can be any tkinter widget is the same as calling <tkinter.Tk>.update as it will call the same tcl function.

Selfrestraint answered 7/3, 2021 at 13:35 Comment(13)
What does <tkinter.Tk>.update mean? AFAIK, update is a universal method and can be used on any widget, not just Tk().Flybynight
@CoolCloud I will update my answer with an explanationSelfrestraint
What I meant was, the way you said <tkinter.Tk>.update makes it seems update() can only be called on Tk(), was a correction.Flybynight
Thank you! This helped me out! But I'll go with @Quarry s answer.Nolly
@Sunburst275 its fine I am just showing another option that you have. CoolCloud it calls the same tcl function so it doesn't matter and its conventional to call <tkinter.Tk>.updateSelfrestraint
I think that in general is better to use update_idletasks() which has less side effects.Quarry
@Quarry I had only 1 bug caused by calling update instead of update_idletasks which I corrected by moving some code around (still using update). I can't find a proper explanation online for the technical differences between update and update_idletasks so I only use update.Selfrestraint
This is not enough? #29159311Quarry
@Quarry I already read that and didn't help much. Also I in this case update_idletasks doesn't work because you need to update the window so that geometry manager can give the canvas the space it needs so that winfo_width works. Also I disagree with BryanOakley's explanation that you have a mainloop nested inside a mainloop when you use update.Selfrestraint
The main difference, i think, is in the callback: if you bind <Configure> to some function, update() calls the function, update_idletask() does not call it. @SelfrestraintQuarry
Let us continue this discussion in chat.Selfrestraint
I think update() does the work of update_idletasks() and more.Flybynight
@CoolCloud I know that but the question is exactly what does update do that update_idletasks doesn't do. I found this but it's still too vague.Selfrestraint
A
0

The proper way in Python Tk is to use:

canvas_width  = int(canvas.__getitem__('width'))
canvas_height = int(canvas.__getitem__('height'))

Tk stores the attributes as string (Tcl rules!), therefore a cast to int is necessary.

Amarillis answered 11/9, 2024 at 18:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.