Home > Software engineering >  Dynamically change scale of widgets in Canvas - Python
Dynamically change scale of widgets in Canvas - Python

Time:12-02

I am trying to create a canvas with one useful function for me. I need to make my program understand when object on canvas is too big so this object will collide with borders of canvas and automatically will decrise size of object. I know that canvas can't change size of objects, canvas just change coordinates of object.

So, I did almost everything, and it works, but only first time. If I create a rectangle with bigger sizes again, my program will not change coordinates again. With .bbox function we can see, that coordinates are still the same. I think that after "If statment" I need to update new position of coordinates.

Better just to take my code and try it. For example: maximum size for height is 356mm and for width is 473mm. If you will write into height 357mm or into width 474mm -> function "create" will automatically change coordinates with ".scale", but only once.

My idea is to write different sizes of the rectangle and I always want to see my rectangle in the middle of the canvas. Not to allow this rectangle touch borders, but if it did -> change coordinates and make it smaller.

How I can make it each time when object touching borders?

My code:

from tkinter import *
from tkinter import ttk
import tkinter as tk

create_win = tk.Tk()
create_win.title("Sample canvas")

create_win.geometry("500x550")

create_win.resizable(False, False)
create_win.configure(background="white")

create_win.columnconfigure(0, weight=1)
create_win.rowconfigure(0, weight=1)

main_frame = LabelFrame(create_win, text="Sample Canvas", background="white")
main_frame.grid(row=0, column=0, sticky=NW SE, padx=10, pady=[0,10])

c = Canvas(main_frame, background="white", cursor="crosshair")
c.pack(fill=BOTH, expand=True)

entry_fields = LabelFrame(create_win, text="Enter data", background="white")
entry_fields.grid(row=1, column=0, sticky=NW SE, padx=10, pady=[0,10])

width_lbl = Label(entry_fields, text="Width", font=("Calibri Light", 14), background="white")
width_lbl.grid(row=0, column=0)

height_lbl = Label(entry_fields, text="Height", font=("Calibri Light", 14), background="white")
height_lbl.grid(row=0, column=1)

width_entry = Entry(entry_fields, font=("Calibri Light", 14), bd=2, justify=CENTER, width=22)
width_entry.grid(row=1, column=0, padx=[10,0], pady=[5,10])

height_entry = Entry(entry_fields, font=("Calibri Light", 14), bd=2, justify=CENTER, width=22)
height_entry.grid(row=1, column=1, padx=[4,0], pady=[5,10])

create_win.update()
canvas_w = c.winfo_width()
canvas_h = (c.winfo_height() - 60)

#print(canvas_w)
#print(canvas_h)

def create():
    width_entry_int = int(float(width_entry.get()))
    height_entry_int = int(float(height_entry.get()))
    x1 = (canvas_w - width_entry_int) / 2
    y1 = (canvas_h - height_entry_int) / 2
    x2 = x1   int(float(width_entry.get()))
    y2 = y1   int(float(height_entry.get()))
    c.delete("all")
    rect = c.create_rectangle(x1, y1, x2, y2, fill="red", outline="red")
    data = c.bbox(rect)
    print(data)
    if float(data[0]) <= 0 or float(data[1]) <= 0:
        c.scale("all", ((x1 x2) / 2), ((y1 y2) / 2), 0.5, 0.5)
        
apply_btn = Button(create_win, text="Apply", font=("Calibri Light", 14), padx=5, pady=5, bd=0, background="#747d8c", fg="white", cursor="hand2", command=create)
apply_btn.grid(row=2, column=0, pady=[0,10])

create_win.mainloop()

Thanks in advance!

CodePudding user response:

Okay now, you should change this part

data = c.bbox(rect)

if float(data[0]) <= 0 or float(data[1]) <= 0:
    print(data)
    c.scale("all", ((x1 x2) / 2), ((y1 y2) / 2), 0.5, 0.5)

into this one:

data = c.bbox(rect)
while float(data[0]) <= 0 or float(data[1]) <= 0:
    c.scale("all", ((x1 x2) / 2), ((y1 y2) / 2), 0.5, 0.5)
    data = c.bbox(rect)

Now until it doesn't touches walls, it rescales.

  • Related