Python3 tkinter canvas, setting relative width and height

Question:

I am trying to set the width of some canvas to the width of master (fullscreen) and the height to 1/5, 3/10 and 1/2 of master. Window is correctly shown, but canvas doesn’t appear. I unsuccessfully tried place() instead of pack() with relwidth = 1 and relheight = 0.2.
I just want my three canvas stacked and horizontally filling the window.

master = Tk()
master.attributes('-zoomed', True)

w = master.winfo_width()
h = master.winfo_height()
hu = int(h/10)
h1 = hu*2
h2 = hu*3
h3 = hu*5

c1 = Canvas(master, bg='grey', width = w, height = h1)
c1.pack()
c2 = Canvas(master, bg='blue', width = w, height = h2)
c2.pack()
c3 = Canvas(master, bg='red', width = w, height = h3)
c3.pack()

Edit: my working code is now:

c1 = Canvas(master)
c1.place(rely = 0, relheight = 0.2, relwidth = 1)
c2 = Canvas(master)
c2.place(rely = 0.2, relheight = 0.3, relwidth = 1)
c3 = Canvas(master)
c3.place(rely = 0.5, relheight = 0.5, relwidth = 1)

but I am having a side effect, I can’t align at the center a text:

c1.create_text(0, 0, text = 'text', fill = 'red', font = ('olivier', 30, 'bold'))
c1.update()

that I solved in this unelegnat way:

master.update_idletasks()
w = master.winfo_width()
h = master.winfo_height()
ww = int(w/2)
hh = int(h/10)
c1.create_text(ww, hh, text = 'text', fill = 'red')
Asked By: druido82

||

Answers:

You need to use the .place() geometry manager.

.place() has two main parameters which I think you will need.

The first one is relheight. True to its name, it sets the height of any widget relative to it’s parent widget.

So, if relheight was 0.5, then the height would be 0.5(height), or 50% of the parent widgets height.

The same applies to relwidth, which works the same way but applies to the width instead.

Read more about .place() here.

Also, if you want your code:

master = Tk()
master.attributes('-zoomed', True)

c1 = Canvas(master, bg='grey')
c1.place(x = 0, rely = 0, relheight = 0.2, relwidth = 1)
c2 = Canvas(master, bg='blue')
c2.pack(x = 0, rely = 0.25, relheight = 0.3, relwidth = 1)
c3 = Canvas(master, bg='red')
c3.pack(x = 0, rely = 0.5, relheight = 0.5, relwidth = 1)

Hope this helps!

Edit: .place() doesn’t work for canvas elements. For that, you need to take the legnth and width of the canvas, and then divide both by two(if you want the middle).

For example:

height = 100
width = 100
c = Canvas(master, bg = "blue", height = height, width = width, highlighthickness = 0)
c.place(x = 0, rely = 0.5, relheight = 0.2, relwidth = 1)
text = c.create_text(height/2, width/2, text = "text")

This will place the text text in the center of your canvas.

Hope this helps!

Answered By: 10 Rep

At the first time you use master.winfo_width() and master.winfo_height(),it will be zero.(If you use print(w,h),you will find all of them are zero.)

Just add master.update_idletasks() before master.winfo_xxxx.

All the code could be:

from tkinter import *
master = Tk()
master.state('zoomed')

# add here 
master.update_idletasks()
w = master.winfo_width()
h = master.winfo_height()
hu = int(h/10)
h1 = hu*2
h2 = hu*3
h3 = hu*5

c1 = Canvas(master, bg='grey', width = w, height = h1)
c1.pack()
c2 = Canvas(master, bg='blue', width = w, height = h2)
c2.pack()
c3 = Canvas(master, bg='red', width = w, height = h3)
c3.pack()
master.mainloop()
Answered By: jizhihaoSAMA

c1.bind("<Configure>", lambda event: TextPositionChange(c1, TextId)):
On C1(Canvas) Size Change(c1 size will change by window size changing)

canvas.bbox(TextId):
→ x1, y1, x2, y2 of TextId(Item of canvas)

canvas.create_text(text_center_x, text_center_y, options…)

c1.moveto(TextId, c1.winfo_width()/2-xOffSet, c1.winfo_height()/2-yOffSet):
→ canvas.moveto(item, left_top_x, left_top_y)
→ item move to its new_left_top_position

from tkinter import *
master = Tk()
master.state('zoomed')

def TextPositionChange(canvas, TextId):
    x1, y1, x2, y2 = canvas.bbox(TextId)
    xOffSet, yOffSet = (x2-x1)/2, (y2-y1)/2
    canvas.moveto(TextId, canvas.winfo_width()/2-xOffSet, canvas.winfo_height()/2-yOffSet)

c1 = Canvas(master, bg="#111111")
c1.place(rely = 0, relheight = 0.2, relwidth = 1)
c2 = Canvas(master, bg="#222222")
c2.place(rely = 0.2, relheight = 0.3, relwidth = 1)
c3 = Canvas(master, bg="#333333")
c3.place(rely = 0.5, relheight = 0.5, relwidth = 1)

TextId = c1.create_text(0, 0, text = "text", fill = "red", font = ("olivier", 30, "bold"))
c1.bind("<Configure>", lambda event: TextPositionChange(c1, TextId))

master.mainloop()

You can also see:
https://tcl.tk/man/tcl8.6/TkCmd/canvas.htm#M60

Hope it can help you.

Answered By: 謝咏辰