WedX - журнал о программировании и компьютерных науках

Событие ввода Python Tkinter

Я новичок в Tkinter и пытаюсь сделать анимированную кнопку.

Я использую события ввода-вывода, но нажатие кнопки не очень хорошо отвечает.

Мой код:

    imagePath = "Resources/"
    imagelist = ["boton_1.gif","boton_2.gif","boton_3.gif","boton_4.gif","boton_5.gif","boton_6.gif",
                    "boton_7.gif","boton_8.gif","boton_9.gif","boton_10.gif","boton_11.gif","boton_12.gif",
                    "boton_13.gif","boton_14.gif","boton_15.gif","boton_16.gif"]


    giflist = []
    for imagefile in imagelist:
        photo = PhotoImage(file=imagePath+imagefile)
        giflist.append(photo)

    self.photo=giflist[0]
    button = Button(buttonFrame, image=self.photo,background='orange',activebackground='lightsalmon',
                    command=lambda: controller.show_frame(ListPlayerPage))
    button.pack(pady=5)

    def enter(event):
        self.clickOnButton1 = True
        for i in range(1,8):
            button.config(image=giflist[i])
            button.update()
            time.sleep(0.1)
            if self.clickOnButton1 == False:
                break
        while (self.clickOnButton1):
            for i in range (9,15):
                button.config(image=giflist[i])
                button.update()
                time.sleep(0.08)
                if self.clickOnButton1 == False:
                    break

    def leave(event):
        self.clickOnButton1 = False
        button.config(image=self.photo)
        button.update()

    button.bind("<Enter>",enter)
    button.bind("<Leave>",leave)

Спасибо!!

11.09.2015

  • Как это не отвечает? Вылетает с ошибкой или просто зависает? 11.09.2015
  • Не вылетает, иногда нажимаешь, и экран меняется, а иногда ничего не делает 11.09.2015
  • Итак, иногда кнопка меняется, а иногда кнопка остается прежней? 11.09.2015
  • Не используйте time.sleep() для задержек в программе tkinter — они плохо взаимодействуют с основным циклом tkinter. Вместо этого вам нужно использовать метод tkinter .after(). См. здесь простой пример. 11.09.2015
  • Не уверен, что это причина, но я вижу две возможные проблемы: 1) PhotoImages могут быть удалены сборщиком мусора или 2) использование time.sleep в пользовательском интерфейсе, как правило, плохая идея; лучше использовать after. 11.09.2015
  • @tobias_k: Он хранит ссылки на PhotoImages в giflist, так что не должно ли это препятствовать сборке мусора? 11.09.2015
  • В стороне: self.clickOnButton1 назван сбивчиво. self.animateButton было бы лучше. 11.09.2015
  • @StevenRumbalski Ну, это зависит от того, что содержит ссылку на giflist. Судя по всем этим self, кажется, что это внутри метода. С другой стороны, giflist может выжить при закрытии enter и leave, не уверен на 100%. 11.09.2015
  • @StevenRumbalski: PhotoImages странные, см. примечание в конце документов PhotoImage. Но, как говорит tobias_k, без минимально воспроизводимого примера трудно сказать наверняка. 11.09.2015
  • FWIW, вот пример, который я написал, который сохраняет ссылку на PhotoImage как атрибут кнопки (конечно, этот метод не применимо для этого кода). Если вы закомментируете строку b.photo = photo в конце цикла, только последняя кнопка получит изображение. 11.09.2015
  • Чего именно вы пытаетесь достичь? Кажется, вы перебираете картинки — вы пытаетесь создать анимированную кнопку? Есть лучшие способы добиться этого, чем использовать спящий режим и бесконечные циклы, вызывающие update. Если бы мы лучше знали, чего вы пытаетесь достичь, мы могли бы дать более точные ответы. 11.09.2015
  • Брайан Окли, да, я пытаюсь создать анимированную кнопку, но у меня плохо получается... 11.09.2015
  • Спасибо за ваши комментарии!! 11.09.2015

Ответы:


1

Часть проблемы определенно связана с тем фактом, что вы звоните sleep. Как правило, вы никогда не должны вызывать sleep в основном потоке графического интерфейса. Он не позволяет графическому интерфейсу обрабатывать все события, включая обновления экрана.

Вообще говоря, вам также следует избегать вызова update. Это может привести к вложенным циклам событий, если во время обработки update вы в конечном итоге вызовете метод, который снова вызывает update.

Вот действительно простой пример решения, которое создает кнопку, которую можно анимировать. Он использует after для перебора списка текстовых строк, по одной новой строке каждые полсекунды. Этот пример будет анимироваться вечно, но вы легко можете показать каждый элемент только один раз. Это изменяет текст, чтобы сделать пример короче, но вы можете легко изменить его, чтобы заменить изображения вместо текста.

import Tkinter as tk # use tkinter for python 3.x
class AnimatedButton(tk.Button):
    def __init__(self, *args, **kwargs):
        tk.Button.__init__(self, *args, **kwargs)
        self._job = None

    def cancel_animation(self):
        if self._job is not None:
            self.after_cancel(self._job)
            self._job = None

    def animate(self, textlist):
        text = textlist.pop(0)
        textlist.append(text)
        self.configure(text=text)
        self._job = self.after(500, self.animate, textlist)

Вы используете ее как любую другую кнопку, но вы можете вызвать animate, чтобы запустить анимацию, и cancel_animate, чтобы отменить ее:

button = AnimatedButton(root, width=10)
data = ["one","two","three","four","five","six"]
button.bind("<Enter>", lambda event: button.animate(data))
button.bind("<Leave>", lambda event: button.cancel_animation())
11.09.2015
  • Спасибо!! Я попытаюсь сделать этот пример, но с изображениями. Я думаю, что метод update() блокирует событие onclick().. поэтому, когда я нажимаю на него, он занят сменой изображений и не обращает внимания на мой щелчок. 11.09.2015

  • 2

    Я последовал примеру Брайана Окли и нашел хорошее решение!

    Во-первых, это анимированная кнопка с немного сложной анимацией. У меня есть 16 изображений. Первое — это базовое изображение. Затем у меня есть восемь изображений, которые являются первой частью анимации. Остальные изображения являются циклической частью анимации.

    Когда вы наводите мышь на кнопку, запускается анимация.

    Вот код!:

    import Tkinter as tk # use tkinter for python 3.x
    
    root = tk.Tk()
    root.geometry("300x200")
    
    class AnimatedButton(tk.Button):
    
        def __init__(self, *args, **kwargs):
            tk.Button.__init__(self, *args, **kwargs)
            self._job = None
            self.i = 1
    
        def cancel_animation(self,image):
            self.configure(image=image)
            self.i = 1
            if self._job is not None:
                self.after_cancel(self._job)
                self._job = None
    
    
        def animate(self, imagelist):
            image = imagelist[self.i]
            self.i+=1
            if self.i == (len(imagelist)-1):
                self.i = 9
            self.configure(image=image)
            self._job = self.after(80, self.animate, imagelist)
    
    
    imagePath = "Resources/"
    imagelist = ["boton_1.gif","boton_2.gif","boton_3.gif","boton_4.gif","boton_5.gif","boton_6.gif",
                    "boton_7.gif","boton_8.gif","boton_9.gif","boton_10.gif","boton_11.gif","boton_12.gif",
                    "boton_13.gif","boton_14.gif","boton_15.gif","boton_16.gif"]
    
    giflist = []
    for imagefile in imagelist:
        photo = tk.PhotoImage(file=imagePath+imagefile)
        giflist.append(photo)
    
    image = giflist[0]
    button = AnimatedButton(root,image = image)
    button.bind("<Enter>", lambda event: button.animate(giflist))
    button.bind("<Leave>", lambda event: button.cancel_animation(image))
    
    button.pack()
    
    root.mainloop()
    

    Спасибо!!!

    11.09.2015
    Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]