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')
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!
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()
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.
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')
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!
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()
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.