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!