Кнопки переключения, которые ссылаются на один и тот же код для той же функции - PullRequest
0 голосов
/ 08 октября 2018

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

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 раз, изменив имена переменных для завершения программы, это работает, но я хочу знать, есть липуть к тому же определению переключателя для каждой кнопки, в отличие от определения нового переключателя для каждой кнопки?Переключатель используется для изменения цвета кнопки, переключая его с одного цвета на другой, и я не уверен, как заставить одинаковые команды вызываться всеми кнопками для воздействия на каждую кнопку в отдельности.спасибо!

Ответы [ 3 ]

0 голосов
/ 08 октября 2018

Вот что-то работоспособное, показывающее, как реализовать подход, предложенный мной в одном из моих комментариев:

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 в настоящее время добивается в своем ответ ).Тем не менее, я все еще думаю, что показанный здесь код будет полезен для вас, чтобы увидеть и понять, какие вещи возможны с Python, и tkinter.

Я вижу, @Bryan Oakley теперь опубликовал ответ , что делает Toggler Button подклассом вместо независимого, как показано здесь.Я подумал сделать это, потому что это было бы более элегантно, но решил, что это может быть слишком продвинутым, и пошел дальше и реализовал, как показано здесь (и так как я упомянул в комментарии).Кроме того, похоже, что у Брайана также есть идея @ Натана, которая будет работать.

0 голосов
/ 08 октября 2018

Вы можете создавать кнопки в циклах и сохранять ссылку на кнопку в словаре или списке.

Необъектно-ориентированный подход

В следующем примере используется традиционный подход к выполнениювсе работы в основном классе.Он использует 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()
0 голосов
/ 08 октября 2018

Один из вариантов - поместить в список self.A, self.B и т. Д. (Например, self.buttons).

Затем вместо создания toggleA(self), toggleB(self) и т. Д. Вы можете сделать toggle(self,button), который использует аргумент button, где вы в настоящее время используете self.A, self.B и т. Д.

Затем используйте цикл for над self.buttons и вызовите toggle для каждого изих.

for button in buttons:
    toggle(button)
...