Функция выделения кнопки Tkinter перестает работать после вызова команды - PullRequest
1 голос
/ 31 октября 2019

Я работал над своим первым графическим интерфейсом в tkinter - я использую Windows. Моя цель сейчас - иметь кнопки, которые выполняют эти цели:

  1. Кнопки подсвечиваются при наведении на них.
  2. Кнопка остается подсвеченной при нажатии.
  3. Толькоодна кнопка может быть «выбрана» (выделена щелчком мыши) за раз.

Сначала я думал, что достиг этого! Но теперь я понимаю, что моя работа не завершена.

Вот что я вижу:

  1. Я намыкаю на кнопку A. Она подсвечивается! (ХОРОШО)
  2. Я нажимаю кнопку А. Она остается выделенной! (ХОРОШО)
  3. Я наведите курсор мыши на кнопку B. Она подсвечивается! (ХОРОШО)
  4. Я нажимаю на кнопку B. Она остается выделенной! Основной момент от A удален! (ХОРОШО)
  5. Я наведите курсор мыши на кнопку А. Она не подсвечивается. (ПЛОХО)

Я вызываю функцию класса default_coloring для кнопки A, когда нажимаю кнопку B. Однако, это, кажется, отключает функции подсветки кнопки A, и кнопка больше не функционирует правильнов соответствии с тремя правилами, которые я перечислил вверху.

Как мне обеспечить, чтобы кнопки продолжали нормально функционировать даже после вызова команды? Неправильно ли я подхожу к этому?

  import tkinter as tk

  blue = '#0000BB'
  white = '#FFFFFF'

  class HoverButton(tk.Button):
        def __init__(self, master, position = None, **kw):
              tk.Button.__init__(self,master=master,**kw)
              self.defaultBackground = self["background"]
              self.defaultForeground = self["foreground"]
              self.bind("<Enter>", self.on_enter)
              self.bind("<Leave>", self.on_leave)
              self.bind("<Button-1>", self.hover_click)
              self.state = 0
              self.position = position

        def on_enter(self, e):
              if self.state == 0:
                    self['background'] = self['activebackground']
                    self['foreground'] = self['activeforeground']

        def on_leave(self, e):
              if self.state == 2:
                    self.state = 0
              if self.state == 0:
                    self['background'] = self.defaultBackground
                    self['foreground'] = self.defaultForeground

        def hover_click(self, e):
              self.state += 1
              self.state = self.state % 3
              if self.state == 2:
                    self['background'] = self.defaultBackground
                    self['foreground'] = self.defaultForeground

        def default_coloring(self):
              self['background'] = self.defaultBackground
              self['foreground'] = self.defaultForeground

  class AddOnFrame(tk.Frame):
        def __init__(self, master):
              self.selectedbutton = None
              super().__init__(master)
              games = ['A','B','C']
              self.objs = list()
              self['bg'] = blue
              for i in range(3):
                    self.objs.append(HoverButton(self,position = i, text = games[i].upper(), activebackground = white,activeforeground = blue,fg = white, bg = blue, borderwidth=0, relief = 'flat', highlightbackground = white))
                    self.objs[i]['command'] = lambda c=i: self._hover_button_clicked(self.objs[c])
                    self.objs[i].grid(row = i, column = 0, sticky = tk.W + tk.E)
              self.blanklabel = tk.Label(self, text = '', background = white)
              self.blanklabel.grid(row = 0, column = 1,rowspan = 10, sticky = tk.N + tk.E + tk.W + tk.S)
              self.grid_columnconfigure(1, weight=1, minsize=10)
              self.grid_columnconfigure(2, weight=1, minsize=500)
              self.grid_columnconfigure(3, weight=1, minsize=500)
              self.grid_columnconfigure(4, weight=1, minsize=500)
              self.pack(expand = True)

        def _hover_button_clicked(self, HoverButton):
              self.lastbutton = self.selectedbutton
              if self.lastbutton != None:
                    self.objs[self.lastbutton].default_coloring()
              self.selectedbutton = HoverButton.position

  window = tk.Tk()
  window.geometry('1750x950')
  window['bg'] = blue
  window.title('Testing')
  lf = AddOnFrame(window)
  lf['bg'] = blue

  window.mainloop()

Ответы [ 2 ]

1 голос
/ 31 октября 2019

Я думаю, что нашел основной источник проблемы. При нажатии другой кнопки вы восстанавливаете цвет последней нажатой кнопки, но не сбрасываете ее состояние. Измените свою функцию default_coloring на:

def default_coloring(self):
          self.state = 0
          self['background'] = self.defaultBackground
          self['foreground'] = self.defaultForeground

Но вы должны также запретить default_coloring, если та же кнопка нажата снова:

def _hover_button_clicked(self, HoverButton):
          self.lastbutton = self.selectedbutton
          if (self.lastbutton != None) and (self.lastbutton != HoverButton.position):
                self.objs[self.lastbutton].default_coloring()
          self.selectedbutton = HoverButton.position
1 голос
/ 31 октября 2019

После беглого осмотра эта последовательность кажется проблемой:

  • При нажатии кнопки вызывается метод AddOnFrame._hover_button_clicked.
  • AddOnFrame.selectedbutton изначально None, что означает, что оператор if в AddOnFrame._hover_button_clicked не будет выполнен в первый раз. Вот почему кнопки, кажется, работают в первый раз, когда вы нажимаете их, но не после этого.
  • Однако при следующем вызове (при следующем нажатии кнопки) AddOnFrame.selectedbutton не None, и никогда больше не будет None, означая, что с этого момента каждый щелчок приведет к вызову этого default_coloring метода HoverButton.
  • default_coloring вызывается, как толькопри нажатии кнопки происходит быстрое мигание активного цвета до цвета по умолчанию, и кнопка не остается выделенной.

Быстрое исправление:

В основном,не делай вещи default_coloring. Кажется, это причиняет тебе боль больше, чем помогает. Не совсем уверен, почему вы делаете это в первую очередь (все это с настройкой команды, лямбда, весь метод _hover_button_clicked), так как кнопки, кажется, устанавливают свои цвета обратно по умолчанию, просто отлично, когда on_leave или hover_click. Вы можете исправить свою проблему, изменив тело вашей функции HoverButton.default_coloring следующим образом:

def default_coloring(self):
    return

Реальным исправлением будет некоторая реструктуризация вашего кода.

EDIT Я предлагаю это, чтобы помочь вам упростить вещи:

import tkinter as tk

colors = {
    "white": "#FFFFFF",
    "blue": "#0000BB"
}


class HoverButton(tk.Button):

    def __init__(self, *args, **kwargs):
        tk.Button.__init__(self, *args, **kwargs)
        self.is_selected = False
        self.is_highlighted = False
        self["borderwidth"] = 0
        self["relief"] = tk.FLAT
        self["font"] = ("United Sans Cd Bk", 30)
        self["activeforeground"] = colors["blue"]
        self["activebackground"] = colors["white"]
        self["highlightbackground"] = colors["white"]
        self.recolor()

        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)
        self.bind("<Button-1>", self.on_click)

    def recolor(self):
        self["background"] = [colors["blue"], colors["white"]][self.is_highlighted]
        self["foreground"] = [colors["white"], colors["blue"]][self.is_highlighted]

    def on_enter(self, *args):
        self.is_highlighted = True
        self.recolor()

    def on_leave(self, *args):
        if self.is_selected:
            return
        self.is_highlighted = False
        self.recolor()

    def on_click(self, *args):
        self.is_selected = not self.is_selected


class Application(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.title("Window")
        self.geometry("256x256")
        self.resizable(width=False, height=False)
        self["background"] = colors["blue"]

        button_labels = ["A", "B", "C"]
        self.buttons = []
        for row, button_label in enumerate(button_labels):
            button = HoverButton(text=button_label)
            button.grid(row=row, column=0, sticky=tk.W)
            self.buttons.append(button)


def main():

    application = Application()
    application.mainloop()

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...