【问题标题】:Toggle buttons that references the same code for the same function切换为相同功能引用相同代码的按钮
【发布时间】:2019-03-13 11:42:20
【问题描述】:

我正在尝试编写一个宾果网格程序,并希望减少我的代码以使其更简单。我目前正在重复此代码:

from tkinter import *
from tkinter import Tk, Button, Label
mycolor = '#FF7F50'
mycolor2 = '#FFFFFF'
mycolor3 = '#BAF0FF'
class Window:

    def __init__(self, master):
        self.master = master
        self.master.title("Bingo")
        self.master.minsize(width=1920, height=1080)
        self.master.config(bg=mycolor3)

        self.A = Button(master, text='1', font=('Helvetica', '23'), height=1, width=20, command=self.toggleA, bg=mycolor2)
        self.A.grid(column=0,row=1)

        self.B = Button(master, text='2', font=('Helvetica', '23'), height=1, width=20, command=self.toggleB, bg=mycolor2)
        self.B.grid(column=0,row=2)

    def toggleA(self):
        self.A.config('bg')
        if self.A.config('bg')[-1] == mycolor2:
            self.A.config(bg=mycolor)
        else:
            self.A.config(bg=mycolor2)
    def toggleB(self):
        self.B.config('bg')
        if self.B.config('bg')[-1] == mycolor2:
            self.B.config(bg=mycolor)
        else:
            self.B.config(bg=mycolor2)
root = Tk()
my_win = Window(root)
root.mainloop()

并且准确地使用它,我必须通过更改变量名称来重复这个脚本 75 次以完成程序,这是有效的,但我想知道是否有一种方法可以为每个相反的按钮定义相同的切换为每个按钮定义一个新的切换?切换用于影响按钮的颜色,将其从一种颜色切换到另一种颜色,我不确定如何让所有按钮调用相同的命令以单独影响每个按钮。 谢谢!

【问题讨论】:

  • 你说你在重复这段代码;你能展示一个重复,这样我们就可以看到你在每次重复中改变了什么? (PS:欢迎来到 StackOverflow!??????)
  • 定义一个实例可调用的Toggle 类(即定义一个__call__() 方法),然后创建它们的列表。然后,您可以在当前使用toggleAtoggleB 等的任何位置使用列表元素。
  • 创建一个类或使用forloop
  • DDC208:请在您的问题中添加更多代码...理想情况下是一个最小但可运行的示例,它具有您的代码似乎正在定义的完整类。
  • @thesonyman101:应该创建一个类使用for循环。

标签: python python-3.x button tkinter togglebutton


【解决方案1】:

一种选择是将self.Aself.B 等放入列表中(例如self.buttons)。

然后,您可以创建toggle(self,button),而不是创建toggleA(self)toggleB(self) 等,它在您当前使用self.Aself.B 等的地方使用其button 参数。

然后在self.buttons 上使用for 循环,并对它们每个调用toggle

for button in buttons:
    toggle(button)

【讨论】:

    【解决方案2】:

    您可以在循环中创建按钮,并将对该按钮的引用存储在字典或列表中。

    非面向对象的方法

    以下示例采用传统方法在主类中完成所有工作。它使用lambda 将按钮索引传递给回调函数。

    from tkinter import *
    mycolor = '#FF7F50'
    mycolor2 = '#FFFFFF'
    mycolor3 = '#BAF0FF'
    class Window:
    
        def __init__(self, master):
            self.master = master
            self.master.title("Bingo")
            self.master.minsize(width=1920, height=1080)
            self.master.config(bg=mycolor3)
    
            self.buttons = {}
            font = ('Helvetica', 12)
            for i in range(1,10):
                button = Button(master, text=str(i), font=font,
                                height=1, width=20, bg=mycolor2,
                                command=lambda index=i: self.toggle(index))
                button.grid(column=0, row=i+1)
                self.buttons[i] = button
    
        def toggle(self, index):
            button = self.buttons[index]
            if button.cget('bg') == mycolor2:
                button.configure(bg=mycolor)
            else:
                button.configure(bg=mycolor2)
    
    root = Tk()
    my_win = Window(root)
    root.mainloop()
    

    注意:您可能还需要配置activebackground,以便无需将鼠标从按钮上移开即可看到新颜色。

    button.configure(bg=mycolor, activebackground=mycolor)
    

    面向对象的方法

    另一种解决方案是创建一个内置切换功能的自定义按钮小部件,以便调用者除了创建自定义按钮的实例外无需执行任何操作。这稍微简化了回调,因为每个按钮都知道自己,并且不必被告知要切换哪个按钮。

    此示例仍将按钮存储在字典中,但严格来说,在此特定示例中没有必要:

    from tkinter import *
    mycolor = '#FF7F50'
    mycolor2 = '#FFFFFF'
    mycolor3 = '#BAF0FF'
    class Window:
    
        def __init__(self, master):
            self.master = master
            self.master.title("Bingo")
            self.master.minsize(width=1920, height=1080)
            self.master.config(bg=mycolor3)
    
            self.buttons = {}
            font = ('Helvetica', 23)
            for i in range(1,75):
                button = Toggler(master, text=str(i), font=font, color1=mycolor, color2=mycolor2)
                button.grid(column=0, row=i+1)
                self.buttons[i] = button
    
    
    class Toggler(Button):
        def __init__(self, master, text, font, color1, color2):
            self.color1 = color1
            self.color2 = color2
            Button.__init__(self, master, text=text, font=font,
                            height=1, width=20,
                            background=color1, activebackground=color1,
                            command=self.toggle)
    
        def toggle(self):
            color = self.cget("background")
            new_color = self.color1 if color == self.color2 else self.color2
            self.configure(background=new_color, activebackground=new_color)
    
    
    root = Tk()
    my_win = Window(root)
    root.mainloop()
    

    【讨论】:

      【解决方案3】:

      这里有一些可运行的东西,展示了如何实现我在我的一个 cmets 中建议的方法:

      from tkinter import Tk, Button, Label
      
      MY_COLOR = '#FF7F50'
      MY_COLOR2 = '#FFFFFF'
      MY_COLOR3 = '#BAF0FF'
      NUM_BUTTONS = 3
      
      
      class Toggler:
          """ Toggles background color of a Button widget when called. """
          def __init__(self, btn, color, color2):
              self.btn = btn
              self.color = color
              self.color2 = color2
      
          def __call__(self):
              if self.btn.cget('bg') == self.color:
                  self.btn.config(bg=self.color2)
              else:
                  self.btn.config(bg=self.color)
      
      
      class Window:
          def __init__(self, master):
              self.master = master
              self.master.title("Bingo")
              self.master.minsize(width=800, height=600)
              self.master.config(bg=MY_COLOR3)
      
              # Create the buttons.
              self.buttons = []
              self.togglers = []
              for i in range(NUM_BUTTONS):
                  btn = Button(master, text='Button %d' % i, font=('Helvetica', '23'),
                               height=1, width=20, bg=MY_COLOR2)
                  btn.grid(column=0, row=i)
                  toggler = Toggler(btn, MY_COLOR, MY_COLOR2)
                  btn.config(command=toggler)
                  self.buttons.append(btn)
                  self.togglers.append(toggler)
      
      
      root = Tk()
      my_win = Window(root)
      root.mainloop()
      

      在这种特殊情况下(现在我可以看到更多您的代码),我怀疑这可能有点矫枉过正,并且可以用更少的代码来完成(也许与我认为 @Nathan Hinchey 目前在他的answer)。话虽如此,我仍然认为这里展示的代码有助于您了解和了解 Python 和tkinter 可以实现哪些类型的事情。

      我看到@Bryan Oakley 现在发布了一个answer,它使Toggler 成为Button sub-类,而不是此处所示的独立类。我考虑这样做是因为它会更优雅——但我认为这可能太高级了,并按照此处所示的方式进行实施(因为我在评论中提到过)。除此之外,看起来 Bryan 还以一种可行的方式实现了 @Nathan 的想法。

      【讨论】:

        猜你喜欢
        • 2018-03-03
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 2011-04-18
        • 1970-01-01
        • 2021-08-22
        • 1970-01-01
        相关资源
        最近更新 更多