Python Tkinter按钮高亮显示功能在调用命令后停止工作

Python Tkinter按钮高亮显示功能在调用命令后停止工作,python,tkinter,Python,Tkinter,我一直在tkinter开发我的第一个GUI——我正在使用Windows。我现在的目标是拥有实现这些目标的按钮: 鼠标悬停在按钮上方时,按钮将高亮显示 如果单击,按钮将保持高亮显示 一次只能“选择”(单击突出显示)一个按钮 我最初以为我已经做到了!但我现在意识到我的工作还没有完成 以下是我所看到的: 我将鼠标移到按钮A上。它将高亮显示!(好) 我点击按钮A。它保持高亮显示!(好) 我将鼠标移到按钮B上。它将高亮显示!(好) 我点击按钮B。它保持高亮显示!将删除A中的高光!(好) 我将鼠标移到按钮A

我一直在tkinter开发我的第一个GUI——我正在使用Windows。我现在的目标是拥有实现这些目标的按钮:

  • 鼠标悬停在按钮上方时,按钮将高亮显示
  • 如果单击,按钮将保持高亮显示
  • 一次只能“选择”(单击突出显示)一个按钮
  • 我最初以为我已经做到了!但我现在意识到我的工作还没有完成

    以下是我所看到的:

  • 我将鼠标移到按钮A上。它将高亮显示!(好)
  • 我点击按钮A。它保持高亮显示!(好)
  • 我将鼠标移到按钮B上。它将高亮显示!(好)
  • 我点击按钮B。它保持高亮显示!将删除A中的高光!(好)
  • 我将鼠标移到按钮A上。它不会高亮显示。(坏)
  • 当我单击按钮B时,我正在调用按钮A上的默认_着色类函数。但是,这似乎关闭了按钮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()
    
    将tkinter作为tk导入
    蓝色=“#0000BB”
    白色=“#FFFFFF”
    类悬停按钮(tk.Button):
    def初始功率(自身、主、位置=无,**kw):
    tk.按钮。\uuuuu初始化(自,主=主,**kw)
    self.defaultBackground=self[“background”]
    self.default前台=self[“前台”]
    self.bind(“,self.on_输入)
    self.bind(“,self.on_-leave”)
    self.bind(“,self.hover\u单击)
    self.state=0
    self.position=位置
    def on_进入(自我,e):
    如果self.state==0:
    self['background']=self['activebackground']
    self['foreground']=self['activeforeground']
    休假时的def(自我,e):
    如果self.state==2:
    self.state=0
    如果self.state==0:
    self['background']=self.defaultBackground
    self['foreground']=self.defaultForeground
    def悬停单击(自身,e):
    self.state+=1
    self.state=self.state%3
    如果self.state==2:
    self['background']=self.defaultBackground
    self['foreground']=self.defaultForeground
    def默认颜色(自):
    self['background']=self.defaultBackground
    self['foreground']=self.defaultForeground
    类AddOnFrame(tk.Frame):
    定义初始(自我,主):
    self.selectedbutton=无
    超级()。\uuuu初始化\uuuuu(主)
    游戏=['A','B','C']
    self.objs=list()
    自我['bg']=蓝色
    对于范围(3)中的i:
    self.objs.append(悬停按钮(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.\u悬停\u按钮\u单击(self.objs[c])
    self.objs[i].grid(行=i,列=0,粘滞=tk.W+tk.E)
    self.blanklabel=tk.Label(self,text='',background=white)
    self.blanklabel.grid(行=0,列=1,行跨度=10,粘性=tk.N+tk.E+tk.W+tk.S)
    self.grid\u columnconfigure(1,权重=1,最小尺寸=10)
    self.grid\u columnconfigure(2,重量=1,最小尺寸=500)
    self.grid\u columnconfigure(3,重量=1,最小尺寸=500)
    self.grid\u columnconfigure(4,重量=1,最小尺寸=500)
    self.pack(expand=True)
    def_悬停按钮_单击(自身,悬停按钮):
    self.lastbutton=self.selectedbutton
    如果self.lastbutton!=无:
    self.objs[self.lastbutton]。默认颜色()
    self.selectedbutton=HoverButton.position
    window=tk.tk()
    window.geometry('1750x950'))
    窗口['bg']=蓝色
    window.title(“测试”)
    lf=附加框架(窗口)
    lf['bg']=蓝色
    window.mainloop()
    
    粗略检查后,这一顺序似乎是问题所在:

    • 单击按钮时,
      AddOnFrame.\u hover\u按钮\u单击
      方法被调用
    • AddOnFrame.selectedbutton
      最初是
      None
      ,这意味着
      AddOnFrame.\u hover\u button\u clicked
      中的if语句将不可用 第一次执行。这就是为什么按钮似乎能正常工作的原因 第一次单击它们时,但不是之后
    • 但是,下次调用时(下次调用按钮时 按下),
      AddOnFrame。selectedbutton
      不是
      None
      ,并且永远不会 再次成为
      None
      ,这意味着从现在起,每次单击都将导致 调用
      悬停按钮
      默认着色
      方法
    • default\u coloring
      会在单击按钮后立即调用,该按钮 导致从活动颜色快速闪烁为默认颜色, 并且按钮不会一直高亮显示
    快速解决方案:

    基本上,不要做
    default\u着色
    之类的事情。它对你的伤害似乎大于帮助。我不太清楚你为什么要这么做(设置命令、lambda、整个
    \u hover\u按钮\u clicked
    方法的所有内容),因为当调用
    on\u leave
    hover\u click
    时,按钮似乎正在将颜色设置回默认值。您可以通过更改
    鼠标悬停按钮的主体来解决问题。默认的\u着色功能如下:

    def default_coloring(self):
        return
    
    真正的解决办法是对代码进行一些重组

    编辑我提供此功能是为了帮助您简化工作:

    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())
    
    
    
    def default_coloring(self):
              self.state = 0
              self['background'] = self.defaultBackground
              self['foreground'] = self.defaultForeground
    
    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