5

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...

Vandrey
  • 531
  • 1
  • 8
  • 23
  • You have to call `.update` before `winfo_height`. – TheLizzard Mar 07 '21 at 12:59
  • Also you said that it gives it *wouldn't work, because that only gives me error*. What is the error traceback? – TheLizzard Mar 07 '21 at 13:03
  • @TheLizzard Funnily enough when I tried your answers solution, afterwards`c.winfo_width` and `c.winfo_height` also worked. But I'll stick with @hussics answer – Vandrey Mar 07 '21 at 13:43

2 Answers2

5

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()
hussic
  • 1,816
  • 9
  • 10
  • 1
    Perfect! Thank you! – Vandrey Mar 07 '21 at 13:39
  • 1
    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)` – TheLizzard Mar 07 '21 at 15:00
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.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31
  • What does `.update` mean? AFAIK, `update` is a universal method and can be used on any widget, not just `Tk()`. – Delrius Euphoria Mar 07 '21 at 13:37
  • @CoolCloud I will update my answer with an explanation – TheLizzard Mar 07 '21 at 13:38
  • What I meant was, the way you said `.update` makes it seems `update()` can only be called on `Tk()`, was a correction. – Delrius Euphoria Mar 07 '21 at 13:39
  • Thank you! This helped me out! But I'll go with @hussic s answer. – Vandrey Mar 07 '21 at 13:41
  • 1
    @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 `.update` – TheLizzard Mar 07 '21 at 13:43
  • I think that in general is better to use update_idletasks() which has less side effects. – hussic Mar 07 '21 at 13:45
  • @hussic 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`. – TheLizzard Mar 07 '21 at 13:47
  • This is not enough? https://stackoverflow.com/questions/29158811/whats-the-difference-between-update-and-update-idletasks – hussic Mar 07 '21 at 13:50
  • @hussic 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`. – TheLizzard Mar 07 '21 at 13:56
  • The main difference, i think, is in the callback: if you bind to some function, update() calls the function, update_idletask() does not call it. @TheLizzard – hussic Mar 07 '21 at 13:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/229617/discussion-between-thelizzard-and-hussic). – TheLizzard Mar 07 '21 at 13:58
  • I think `update()` does the work of `update_idletasks()` and more. – Delrius Euphoria Mar 07 '21 at 18:12
  • 1
    @CoolCloud I know that but the question is exactly what does `update` do that `update_idletasks` doesn't do. I found [this](https://www.tcl.tk/man/tcl/TclCmd/update.htm) but it's still too vague. – TheLizzard Mar 07 '21 at 18:23