2025, Sep 29 03:17
Почему CTkButton не отображает image и как это исправить
Почему в CustomTkinter CTkButton игнорирует image, хотя CTkImage виден в метках. Пример и решение: задайте image при создании кнопки и меняйте через configure.
Когда вы подключаете иконки к кнопкам в интерфейсе CustomTkinter, всё кажется простым — пока изображения не начинают игнорировать CTkButton, хотя тот же CTkImage без проблем отображается, например, в метках. Если это знакомая ситуация, корень проблемы часто в том, как параметр image инициализируется у самой кнопки.
Минимальный пример, который воспроизводит исчезающую иконку
import customtkinter as ctk
from PIL import Image
import os
from pathlib import Path
import tkinter
base_dir = Path.home() / "AppData" / "Local" / "TestApp"
icons_dir = os.path.join(base_dir, "Risorse", "icone")
pil_img = Image.open(os.path.join(icons_dir, "icona_cartelle.png"))
ctk_img = ctk.CTkImage(light_image=pil_img, dark_image=pil_img, size=(40, 40))
img_store = {"folder_with_items": ctk_img}
def make_button(container, label_text, row_index, col_index, pad_x):
    global img_store
    btn = ctk.CTkButton(master=container,
                        text=label_text,
                        compound="top",
                        fg_color="white",
                        text_color="black",
                        corner_radius=6,
                        cursor="hand2",
                        hover=True)
    btn._text_label.configure(wraplength=150)
    btn.grid(row=row_index, column=col_index, padx=pad_x, pady=5, sticky="w")
    btn.configure(image=img_store["folder_with_items"])  # изображение назначается после создания
    btn.assigned_img = img_store["folder_with_items"]
    print(btn.assigned_img)
    return btn
root = ctk.CTk()
make_button(root, "test", 2, 5, 5)
root.mainloop()В этом варианте CTkImage загружается один раз, сохраняется и передаётся в CTkButton уже после создания виджета. Хотя на первый взгляд всё корректно, значок может не появляться на кнопке, тогда как то же изображение работает в метках.
Что на самом деле происходит
Поведение зависит от того, как задан параметр image у CTkButton. Если кнопку создать без исходного изображения и потом попытаться добавить его через configure(image=...), вы изменяете то, что не было определено при создании. В итоге иконка на кнопке отображается нестабильно. При этом метки в том же коде выводят картинку корректно — значит, дело в том, как CTkButton инициализирует параметр image.
Решение: задавайте изображение при создании кнопки
Надёжный подход — указать image в момент конструирования CTkButton. После этого вызов configure(image=...) работает как обновление уже определённого параметра.
import customtkinter as ctk
from PIL import Image
import os
from pathlib import Path
import tkinter
base_dir = Path.home() / "AppData" / "Local" / "TestApp"
icons_dir = os.path.join(base_dir, "Risorse", "icone")
pil_img = Image.open(os.path.join(icons_dir, "icona_cartelle.png"))
ctk_img = ctk.CTkImage(light_image=pil_img, dark_image=pil_img, size=(40, 40))
img_store = {"folder_with_items": ctk_img}
def make_button(container, label_text, row_index, col_index, pad_x):
    global img_store
    btn = ctk.CTkButton(master=container,
                        text=label_text,
                        compound="top",
                        fg_color="white",
                        text_color="black",
                        corner_radius=6,
                        cursor="hand2",
                        hover=True,
                        image=img_store["folder_with_items"])  # изображение задаётся при создании
    btn._text_label.configure(wraplength=150)
    btn.grid(row=row_index, column=col_index, padx=pad_x, pady=5, sticky="w")
    # Позже при необходимости вы всё равно можете его обновить
    # btn.configure(image=img_store["folder_with_items"]) 
    btn.assigned_img = img_store["folder_with_items"]
    print(btn.assigned_img)
    return btn
root = ctk.CTk()
make_button(root, "test", 2, 5, 5)
root.mainloop()С этой правкой у кнопки изначально есть параметр image. Любой последующий configure(image=...) меняет уже существующее значение, и значок отображается стабильно.
Почему это важно
В интерфейсном коде разница между передачей параметра при инициализации и попыткой добавить его постфактум — это часто грань между предсказуемым поведением и плавающими сбоями. В случае с CustomTkinter создание CTkButton с параметром image позволяет позже спокойно менять картинку через configure(), не сталкиваясь с непоследовательным рендерингом. Это особенно удобно, когда вы управляете пулом иконок и переиспользуете их в кнопках и метках.
Выводы
Если CTkButton не показывает иконку, а тот же CTkImage отображается в других виджетах, задайте image при создании кнопки. Затем по необходимости обновляйте иконку через configure(image=...). Храните изображения в общем хранилище, чтобы переиспользовать их по всему интерфейсу без повторной загрузки.
Материал основан на вопросе на StackOverflow от Andrea Buscetto и ответе Andrea Buscetto.