Skip to content Skip to sidebar Skip to footer

Tkinter: Scaling Items On A Canvas

I was trying to understand how the scaling of canvas works. Take for example, the following code. Why is that canvas.scale('all', ...), which is bind to mouse wheel, is scaling all

Solution 1:

The Scaling of text is not "really" a scaling of text. It is (at least with the Canvas-widget) a change of font.

From the documentation :

This method will not change the size of a text item, but may move it.

Edit: This behaviour also applies to images (created with Tkinter.Canvas.create_image(...)) and windows (created with Tkinter.Canvas.create_window(...)). As the documentation defines scaling as

.scale(tagOrId, xOffset, yOffset, xScale, yScale)

Scale all objects according to their distance from a point P=(xOffset, yOffset). The scale factors xScale and yScale are based on a value of 1.0, which means no scaling. Every point in the objects selected by tagOrId is moved so that its x distance from P is multiplied by xScale and its y distance is multiplied by yScale.

Please note the italic part for how scaling works.

End Edit

If you want to perform an increase of font-size you need to configure all the text elements by yourself using the itemconfigure method.

To Implement it in a very functional way you could use tags to identify all text elements. Increasing can happen not only absolute but also relatively if you first get the fontsize (itemcget) and then increase it depending on scale factor.

Solution 2:

I know this post is old but I solved a similar question so I thought I would post a solution for the problem as well.

The idea is to add a tag to the text item and then reconfigure it each time the zoomer is called. Note, this solution does not change the linux zoom (zoomerP)

import tkinter as tk
import random

pressed = FalseclassExample(tk.Frame):
    def__init__(self, root):
        tk.Frame.__init__(self, root)
        self.canvas = tk.Canvas(self, width=400, height=400, background="bisque")
        self.xsb = tk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
        self.ysb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.ysb.set, xscrollcommand=self.xsb.set)
        self.canvas.configure(scrollregion=(0,0,1000,1000))

        self.xsb.grid(row=1, column=0, sticky="ew")
        self.ysb.grid(row=0, column=1, sticky="ns")
        self.canvas.grid(row=0, column=0, sticky="nsew")
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.fontSize = 10#Plot some rectanglesfor n inrange(50):
            x0 = random.randint(0, 900)
            y0 = random.randint(50, 900)
            x1 = x0 + random.randint(50, 100)
            y1 = y0 + random.randint(50,100)
            color = ("red", "orange", "yellow", "green", "blue")[random.randint(0,4)]
            self.canvas.create_rectangle(x0,y0,x1,y1, outline="black", fill=color, activefill="black", tags=n)
        self.canvas.create_text(50,10, anchor="nw", text="Click and drag to move the canvas\nScroll to zoom.", font = ("Helvetica", int(self.fontSize)), tags="text")

        # This is what enables using the mouse:
        self.canvas.bind("<ButtonPress-1>", self.move_start)
        self.canvas.bind("<B1-Motion>", self.move_move)

        self.canvas.bind("<ButtonPress-2>", self.pressed2)
        self.canvas.bind("<Motion>", self.move_move2)

        #linux scroll
        self.canvas.bind("<Button-4>", self.zoomerP)
        self.canvas.bind("<Button-5>", self.zoomerM)
        #windows scroll
        self.canvas.bind("<MouseWheel>",self.zoomer)
        # Hack to make zoom work on Windows
        root.bind_all("<MouseWheel>",self.zoomer)

    #movedefmove_start(self, event):
        self.canvas.scan_mark(event.x, event.y)
    defmove_move(self, event):
        self.canvas.scan_dragto(event.x, event.y, gain=1)

    #movedefpressed2(self, event):
        global pressed
        pressed = not pressed
        self.canvas.scan_mark(event.x, event.y)
    defmove_move2(self, event):
        if pressed:
            self.canvas.scan_dragto(event.x, event.y, gain=1)

    #windows zoomdefzoomer(self,event):
        if (event.delta > 0):
            self.canvas.scale("all", event.x, event.y, 1.1, 1.1)
            self.fontSize = self.fontSize * 1.1elif (event.delta < 0):
            self.canvas.scale("all", event.x, event.y, 0.9, 0.9)
            self.fontSize = self.fontSize * 0.9
        self.canvas.configure(scrollregion = self.canvas.bbox("all"))
        for child_widget in self.canvas.find_withtag("text"):
            self.canvas.itemconfigure(child_widget, font=("Helvetica", int(self.fontSize)))
        print(self.fontSize)

    #linux zoomdefzoomerP(self,event):
        self.canvas.scale("all", event.x, event.y, 1.1, 1.1)
        self.canvas.configure(scrollregion = self.canvas.bbox("all"))
    defzoomerM(self,event):
        self.canvas.scale("all", event.x, event.y, 0.9, 0.9)
        self.canvas.configure(scrollregion = self.canvas.bbox("all"))

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

Post a Comment for "Tkinter: Scaling Items On A Canvas"