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



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

  1. 鼠标悬停在上面时,按钮会高亮显示
  2. 如果单击该按钮,该按钮将保持高亮显示状态
  3. 一次只能"选择"一个按钮(单击高亮显示(

我最初以为我已经完成了!但我现在意识到我的工作还没有完成。

以下是我所看到的:

  1. 我将鼠标悬停在按钮A上。它变为高亮显示!(好(
  2. 我点击按钮A。它保持高亮显示!(好(
  3. 我将鼠标悬停在按钮B上。它变为高亮显示!(好(
  4. 我点击按钮B。它保持高亮显示!A中的高亮显示已删除!(好(
  5. 我把鼠标移到按钮A上。它不会突出显示。(坏(

当我单击按钮B时,我正在调用按钮A上的default_coloring类函数。然而,这似乎关闭了按钮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()

我想我找到了问题的主要来源。单击另一个按钮时,将恢复上次单击按钮的颜色,但不会重置其状态。将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

粗略检查后,这个序列似乎是问题所在:

  • 单击按钮时,AddOnFrame._hover_button_clicked方法
  • AddOnFrame.selectedbutton最初是None,这意味着如果AddOnFrame._hover_button_clicked中的语句将不会第一次执行。这就是为什么按钮似乎可以工作第一次点击它们,但之后不会
  • 但是,下次调用它时(下次调用按钮时按下(,AddOnFrame.selectedbutton不是None,并且永远不会再次成为None,这意味着从现在起,每次单击都将导致对该CCD_ 8的CCD_ 9方法的调用
  • 单击按钮后立即调用default_coloring导致从活动颜色到默认颜色的快速闪烁,并且该按钮不保持高亮显示

快速修复:

基本上,不要做default_coloring的事情。它对你的伤害似乎大于帮助。首先不确定为什么要这样做(设置命令、lambda和整个_hover_button_clicked方法的所有内容(,因为当调用on_leavehover_click时,按钮似乎会将其颜色设置回默认值。您可以通过将HoverButton.default_coloring函数的主体更改为以下内容来解决问题:

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())

最新更新