Python tkinter gui. При вызове нескольких изображений показывает только последнее

Рейтинг: 0Ответов: 1Опубликовано: 26.01.2023

Пытаюсь создать симулятор игральных костей с имитацией броска. Программа в целом работает, за исключением того, что из двух запланированных кубиков отображается только последний, указанный в коде. Т.е. функция roll, в которой указаны команды на создание двух изображений кубиков, выводит на экран только последнее.

from tkinter import *
import random, time

def sides():
    global side
    d1 = PhotoImage(file=('d1.png'))
    d2 = PhotoImage(file=('d2.png'))
    d3 = PhotoImage(file=('d3.png'))
    d4 = PhotoImage(file=('d4.png'))
    d5 = PhotoImage(file=('d5.png'))
    d6 = PhotoImage(file=('d6.png'))
    side = random.choice([d1,d2,d3,d4,d5,d6])
    return side

def button():
    throw.config(state='active')
    
def roll():
    global dice_l, dice_r
    throw.config(state='disabled')
    for i in range(15):
        dice_l = canvas.create_image(270,250,image=sides())
        dice_r = canvas.create_image(530,250,image=sides())
        window.update()
        time.sleep(0.1)
    button()

window = Tk()
window.title('Dice')
window.resizable(height=False, width=False)
window.iconphoto(True, PhotoImage(file=('ikonka.png')))

canvas = Canvas(window, width=800, height=500)
canvas.pack()

bgrd = PhotoImage(file=('stol2.png'))

canvas.create_image(400,250,image=bgrd)

throw = Button(window, text='ROLL', command=roll)
throw.place(relx=0.5, rely=0.9, anchor=S)

roll()

window.mainloop()

Изначально пробовал делать через Label с указанием места размещения меток с привязкой к ним кубиков в теле программы, ссылаясь на них в функции roll. Но прозрачность пнг-изображений в таком случае выключалась, и вокруг кубиков появлялся серый фон, потому и перешёл на canvas.

Так-то я только начал питон изучать, и где-то на начальном уровне сейчас, и потому возможно не вижу очевидного. Есть ли какое-то решение данной проблемы?

Ответы

▲ 0Принят

Чтобы сборщик мусора не удалял изображения, объекты PhotoImage нужно после создания куда-то сохранять (если одно - просто в глобальную переменную, если их много - то например в список). См. вопрос: Не отображается изображение в Label.

Чтобы новые изображения не создавались каждый раз при вызове roll, нужно изображения один раз загрузить при старте программы, потом только выбирать одно из них из списка:

sides_images = []


def load_images():
    for name in ('d1.png', 'd2.png', 'd3.png', 'd4.png', 'd5.png', 'd6.png'):
        sides_images.append(PhotoImage(file=name))


# Загружаем изображения при старте
load_images()


def sides():
    # Не грузим изображения заново,
    # просто выбираем случайное изображение из ранее загруженных
    side = random.choice(sides_images)  
    return side