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!