CustomTkinter中CTkButton无法正确加载图片的问题排查与解决
最近我用CustomTkinter开发一个工作管理的Python应用,需要创建带图标的按钮。选CustomTkinter本来是看中它的视觉效果,但遇到了个头疼的问题:按钮的图标大部分时候都加载不出来。折腾好一阵终于找到原因,把过程和解决方法分享给大家。
问题重现
先给大家看我最初的核心代码,用来创建带图标的CTkButton:
import customtkinter as ctk from PIL import Image import os from pathlib import Path import tkinter directory_base = Path.home() / "AppData" / "Local" / "TestApp" percorso_icone = os.path.join(directory_base,'Risorse','icone') img = Image.open(os.path.join(percorso_icone,'icona_cartelle.png')) cartella_con_elementi = ctk.CTkImage(light_image=img,dark_image=img,size=(40,40)) immagini = {"cartella_con_elementi":cartella_con_elementi} def crea_pulsante(frame, nome, riga, colonna, resto_laterale): global immagini # 初始化按钮时未传入image参数 btn = ctk.CTkButton(master=frame,text=nome,compound='top',fg_color='white',text_color='black',corner_radius=6,cursor='hand2',hover=True) btn._text_label.configure(wraplength=150) btn.grid(row=riga, column=colonna, padx=resto_laterale, pady=5,sticky='w') # 后续通过configure设置图片 btn.configure(image=immagini["cartella_con_elementi"]) # 尝试保存图片引用防止被GC回收 btn.image_associata = immagini["cartella_con_elementi"] print(btn.image_associata) return btn root = ctk.CTk() crea_pulsante(root,'test',2,5,5) root.mainloop()
运行后控制台能正常打印出CTkImage对象(比如<customtkinter.windows.widgets.image.ctk_image.CTkImage object at 0x0000024935E8C6E0>),但按钮上就是看不到图标。更奇怪的是,把同一个CTkImage用在Label上是完全正常显示的,这说明CTkImage本身没问题,问题出在CTkButton的使用方式上。
排查过程
我一开始以为是Python的GC把图片引用回收了,特意给按钮加了btn.image_associata来保留引用,但还是没用。后来反复对比Label和Button的使用差异,发现了关键:我在初始化CTkButton的时候没有传入image参数,之后再用configure设置就不生效。
解决方法
修改CTkButton的初始化代码,在创建按钮时就传入image参数(哪怕先传一个占位的图片,或者直接传目标图片),之后再用configure修改就可以正常显示了。
修改后的按钮初始化代码:
btn = ctk.CTkButton(master=frame,text=nome,compound='top',fg_color='white',text_color='black',corner_radius=6,cursor='hand2',hover=True,image=immagini["documenti_icona"])
之后再执行btn.configure(image=immagini["cartella_con_elementi"]),按钮的图标就能正常加载显示了。
推测原因是CustomTkinter的CTkButton内部逻辑需要在初始化阶段就存在image属性,后续的configure才能正确识别并渲染图片资源。
内容来源于stack exchange




