Python. Работа с изображениями в tkinter.

На уроке Python. Работа с изображениями мы с вами научились загружать и отображать картинки, а также всяко извращаться с ними. Это мы делали при помощи библиотеки PIL.  На уроке Python. GUI мы с вами при помощи библиотеки tkinter создавали виндовый интерфейс программы: всякие кнопочки, флажки, и прочие элементы управления. Но возникает вопрос: а нельзя ли при помощи tkinter как-то выводить изображение на виндовую форму? Можно. Например вот такая программа:

import tkinter
from PIL import Image, ImageTk

root = tkinter.Tk()

# создаем рабочую область
frame = tkinter.Frame(root)
frame.grid()

#Добавим метку
label = tkinter.Label(frame, text="Hello, World!").grid(row=1,column=1)


# вставляем кнопку
but = tkinter.Button(frame, text="Кнопка").grid(row=1, column=2)

#Добавим изображение
canvas = tkinter.Canvas(root, height=400, width=700)
image = Image.open("d:/3/Dscn0116.jpg")
photo = ImageTk.PhotoImage(image)
image = canvas.create_image(0, 0, anchor='nw',image=photo)
canvas.grid(row=2,column=1)
root.mainloop()

выдаст вот такое окно:

Что интересно, PIL здесь нужен, чтобы загружать изображения типа jpg, gif-ы и png можно открыть и без него:

import tkinter

root = tkinter.Tk()

# создаем рабочую область
frame = tkinter.Frame(root)
frame.grid()

#Добавим метку
label = tkinter.Label(frame, text="Hello, World!").grid(row=1,column=1)


# вставляем кнопку
but = tkinter.Button(frame, text="Кнопка").grid(row=1, column=2)

#Добавим изображение
canvas = tkinter.Canvas(root, height=400, width=700)
img = tkinter.PhotoImage(file = 'd:/3/Dscn0116.png') 
image = canvas.create_image(0, 0, anchor='nw',image=img)
canvas.grid(row=2,column=1)
root.mainloop()

А теперь попробуем при нажатии на кнопку сменить изображение:

import tkinter
from PIL import Image, ImageTk

root = tkinter.Tk()

# создаем рабочую область
frame = tkinter.Frame(root)
frame.grid()

# Добавим метку
label = tkinter.Label(frame, text="Hello, World!").grid(row=1, column=1)

image = Image.open("d://1//DSCN1128.png")
photo = ImageTk.PhotoImage(image)


def my_event_handler():
    print("my_event_handler")
    image = Image.open("d://1//original.jpg")
    photo = ImageTk.PhotoImage(image)
    image = canvas.create_image(0, 0, anchor='nw', image=photo)
    canvas.grid(row=2, column=1)


# вставляем кнопку
but = tkinter.Button(frame, text="Кнопка", command=my_event_handler).grid(row=1, column=2)

# Добавим изображение
canvas = tkinter.Canvas(root, height=400, width=700)
image = canvas.create_image(0, 0, anchor='nw', image=photo)
canvas.grid(row=2, column=1)
root.mainloop()

Но не тут то было. При нажатии на кнопку изображение не меняется. Хотя, казалось бы, все написано правильно, и наш обработчик событий работает, наше сообщение, что мы выводим командой print выводится в окно сообщений. В чем же дело? А дело в сборщике мусора (garbage collector). Как только мы вышли из my_event_handler, локальные переменные тут же уничтожаются сборщиком мусора. Именно поэтому мы видим на форме ту же самую картинку, что и до нажатия на кнопку. Как же быть? Не использовать локальные переменные. Давайте объявим класс, пусть изображение и прочие объекты хранятся в его полях:

import tkinter
from PIL import Image, ImageTk

class App:
    def __init__(self):
        self.root = tkinter.Tk()

        # создаем рабочую область
        self.frame = tkinter.Frame(self.root)
        self.frame.grid()

        # Добавим метку
        self.label = tkinter.Label(self.frame, text="Hello, World!").grid(row=1, column=1)

        self.image = Image.open("d://1//DSCN1128.png")
        self.photo = ImageTk.PhotoImage(self.image)

        # вставляем кнопку
        self.but = tkinter.Button(self.frame, text="Кнопка", command=self.my_event_handler).grid(row=1, column=2)

        # Добавим изображение
        self.canvas = tkinter.Canvas(self.root, height=600, width=700)
        self.c_image = self.canvas.create_image(0, 0, anchor='nw', image=self.photo)
        self.canvas.grid(row=2, column=1)
        self.root.mainloop()

    def my_event_handler(self):
        print("my_event_handler")
        self.image = Image.open("d://1//original.jpg")
        self.photo = ImageTk.PhotoImage(self.image)
        self.c_image = self.canvas.create_image(0, 0, anchor='nw', image=self.photo)
        self.canvas.grid(row=2, column=1)

app= App()

Теперь все работает.

 

Comments

So empty here ... leave a comment!

Добавить комментарий

Sidebar