Добавить на модальную форму каких-нибудь еще полей помимо имени и картинки, например количество друзей, информация о себе, в общем, на свой вкус =)
Работа с данными ВК / подсказка к 6 задачке
Попробуем создать модальное окно по клику на имя пользователя. Модальное окно которое открывается поверх главного окна приложения и которое нельзя закрыть.
По сути процесс открытия нового окна напоминает создание дополнительной формы.
Добавим сначала событие клика при клике на имя:
class UI():
@staticmethod
def get_request(offset_from_start):
# ...
@staticmethod
def fetch_image(image_url):
# ...
def set_label_image(self, image, lblImage):
#...
def fill_labels(self, data):
# ...
for r in items:
# это не трогаем
first_name = r['first_name']
last_name = r['last_name']
label = Label(text=f"{first_name} {last_name}")
label.place(x=40, y=y)
# конец не троганья
# а тут добавляем реакцию на клик
label.bind("<Button>", self.on_name_click)
# ...
# и функцию добавим
def on_name_click(self, event):
print("clicked")
тестим:
ну вроде работает, хотелось бы только что бы как-то передать информацию о том, на кого кликнули, причем не просто имя, а именно словарик на основании которого мы выводили строку.
Добавим третий параметр в функцию on_name_click, в него собственно и будем передавать данные:
# добавил параметр
def on_name_click(self, event, data):
print("clicked")
И теперь чтобы этот третий параметр заполнялся, снова воспользуемся partial
class UI():
# ...
def fill_labels(self, data):
# ...
for r in items:
# это не трогаем
first_name = r['first_name']
last_name = r['last_name']
label = Label(text=f"{first_name} {last_name}")
label.place(x=40, y=y)
# конец не троганья
# создаем из трех-аргументной функции, двух-аргументную, у которой в data окажется словарик с информацией о юзере
label.bind("<Button>", partial(self.on_name_click, data=r))
# ...
def on_name_click(self, event, data):
print(data) # тут еще сделаем вывод data
проверяем:
отлично! =)
Теперь попробуем показать модальное окно, процесс напоминает создание интерфейса в __init__
, только надо выполнять целую кучу специфических операций
def on_name_click(self, event, data):
print(data)
# создаем модальное окно
top = Toplevel(gui)
# устанавливаем ему размеры
top.geometry(300, 100)
# следующие три штуки нужны чтобы перевести фокус на модальное окно
# а также заблокировать главное окно
top.transient(gui)
top.grab_set()
top.focus_set()
top.wait_window()
тестируем:
Ура! Открывается! =)
Теперь попробуем добавить информацию об юзере, в принципе тут все как с обычной формой, только top везде вставляем
def on_name_click(self, event, data):
# ЭТО НЕ ТРОГАЕМ
print(data)
top = Toplevel(gui)
top.geometry("200x300")
# конец ЭТО НЕ ТРОГАЕМ
# создаём лейбл с именем, обратите внимание на первый параметр top
label = Label(top, text=data['first_name'], font="TimesNewRoman 14 bold")
label.place(x=10, y=10)
# создаём лейбл с фамилией, обратите внимание на первый параметр top
label = Label(top, text=data['last_name'], font="TimesNewRoman 12")
label.place(x=10, y=40)
# создаем лейбл под картинку
lblImage = Label(top, borderwidth=1, relief="solid")
lblImage.place(x=10, y=70, width=180, height=180)
# и в принципе картинку можно грузить асинхронно
self.pool.apply_async(
self.fetch_image,
(data['photo_max_orig'], ),
callback=partial(self.set_label_image, lblImage=lblImage)
)
# ЭТО НЕ ТРОГАЕМ
top.transient(gui)
top.grab_set()
top.focus_set()
top.wait_window()
ну в принципе не плохо, можно только картинку побольше сделать.
Вообще, картинка получается маленькой, потому что так срабатывает наш асинхронный метод fetch_image, у него картинка уменьшается всегда до 20px.
Добавим ему еще один параметр, куда можно будет прописать размер картинки:
@staticmethod
def fetch_image(image_url, size=20): # добавил параметр size со значением по умолчанию 20
image_data = requests.get(image_url, stream=True).raw
image = Image.open(image_data)
# тут 20 на size меняем
image.thumbnail([size, size], Image.ANTIALIAS)
return image
и теперь при создании модальной формы, передадим туда 180:
def on_name_click(self, event, data):
print(data)
# ...
lblImage = Label(top, borderwidth=1, relief="solid")
lblImage.place(x=10, y=70, width=180, height=180)
self.pool.apply_async(
self.fetch_image,
(data['photo_max_orig'], 180), # параметры сюда прописываются, пишем 180
callback=partial(self.set_label_image, lblImage=lblImage)
)
# ...
вот другое дело теперь: