如何修改tkinter canvas文本对象的宽高比实现单字符定向缩放效果
Tkinter Canvas 文本非等比缩放形变解决方案
问题根因
Tkinter 原生 canvas.create_text() 渲染的文本属于矢量字形对象,canvas.scale() 方法的坐标变换仅会修改文本的绘制位置,不会作用于字形本身的轮廓,因此无法实现单独缩放宽度/高度的形变效果。
实现方案
借助 Pillow 库将字符渲染为位图图像,对位图做非等比缩放后再贴到 Canvas 上,即可实现自定义形变效果:
- 保留原有的线段绘制逻辑,
canvas.scale()对线形元素生效,可直接跟随缩放参数调整 - 保留宽度调整高度(前倾/绕地平线旋转效果):x轴缩放比例固定为1,动态修改y轴缩放比例
- 保留高度调整宽度(侧向旋转效果):y轴缩放比例固定为1,动态修改x轴缩放比例
依赖安装
pip install pillow
完整可运行代码
import tkinter as tk from PIL import Image, ImageDraw, ImageFont, ImageTk class FlipDigit(): def __init__(self,master): self.master = master self.canvas_width = 150 self.canvas_height = 150 self.digit = tk.Canvas(master, width=self.canvas_width, height=self.canvas_height, bg='black') # 预先生成原始字符位图,避免多次缩放失真 self.font_size = 150 self.font = ImageFont.truetype("calibri.ttf", self.font_size) self.raw_char = 'A' # 生成原始透明位图 self.raw_img = Image.new('RGBA', (self.canvas_width, self.canvas_height), (0,0,0,0)) draw = ImageDraw.Draw(self.raw_img) # 居中绘制字符 text_bbox = draw.textbbox((0,0), self.raw_char, font=self.font) text_x = (self.canvas_width - (text_bbox[2] - text_bbox[0])) // 2 text_y = (self.canvas_height - (text_bbox[3] - text_bbox[1])) // 2 draw.text((text_x, text_y), self.raw_char, font=self.font, fill='white') # 初始化字符显示为原始尺寸 self.tk_img = ImageTk.PhotoImage(self.raw_img) self.letter = self.digit.create_image(self.canvas_width//2, self.canvas_height//2, image=self.tk_img) # 保留原有的两侧线段 self.digit.create_line(5,25,5,125,width=10,fill='#808080') self.digit.create_line(145,25,145,125,width=10,fill='#808080') self.digit.pack() self.count = 0 self.master.after(50, self.Bump) def Bump(self): y_scale = .8 if self.count > 10: y_scale = 1.25 if self.count > 20: self.count = -1 self.count += 1 # 位图非等比缩放:x轴比例固定1,y轴按参数缩放 scaled_img = self.raw_img.resize((self.canvas_width, int(self.canvas_height * y_scale)), Image.Resampling.LANCZOS) self.tk_img = ImageTk.PhotoImage(scaled_img) # 更新canvas上的字符图像 self.digit.itemconfig(self.letter, image=self.tk_img) # 缩放两侧线段 self.digit.scale('all', 75, 75, 1, y_scale) self.master.after(150, self.Bump) if __name__ == '__main__': root = tk.Tk() Digit = FlipDigit(root) root.mainloop()
扩展说明
如果需要实现保留高度调整宽度的侧向旋转效果,只需修改缩放逻辑:将y轴缩放比例固定为1,动态调整x轴的缩放比例即可。
内容的提问来源于stack exchange,提问作者Burtski
相关产品推荐
相关产品推荐

