Работа с данными ВК / подсказка к 6 задачке

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)
        )
        
        # ...

вот другое дело теперь: