cs2612
cs2612

Reputation: 131

Change button color on click among similar multiple buttons

Let me elaborate the process. Following is the sample code snippet of my application

import tkinter as tk
class ldo(Frame):
    def __init__(self, master = None):
        Frame.__init__(self,master)
        self.grid()
        self.appOutline()

    def appOutline(self):
        self.masterframe1 = Frame(self.master,width=300,height=300)
        self.masterframe1.grid(sticky=N,padx=20)

        self.masterframe2 = Frame(self.master,width=300,height=100)
        self.masterframe2.grid(sticky=S,padx=20)

        self.addtabbutton = Button(self.masterframe2,text="Add Step", width=10, command=self.popup2, bg="sienna1")
        self.addtabbutton.grid(row=0,column=0,sticky=EW)
        self.runallbutton = Button(self.masterframe2,text="Run All", width=10, command=self.underprocess, bg="sienna1",state=DISABLED)
        self.runallbutton.grid(row=0,column=1,sticky=EW)
        self.runselbutton = Button(self.masterframe2,text="Run Selected", width=10, command=self.popup2, bg="sienna1",state=DISABLED)
        self.runselbutton.grid(row=0,column=2,sticky=EW)

    def popup2(self):
        self.child = Toplevel()
        self.child.geometry("300x300")
        self.child.title("Secondary")

        self.label1 = Label(self.child,text="Your input")
        self.label1.pack()

        self.entryinp = StringVar()
        self.entry1 = Entry(self.child,textvariable=entryinp)
        self.entry1.pack()

        self.submit = Button(self.child,text="Submit",command=self.evaluation,bg="pink")
        self.submit.pack()

    def evaluation(self):
        self.inputValue = self.entry1.get()

        self.steps = Button(self.masterframe1,text=self.inputValue,command=self.colorchange,bg="light blue")
        self.steps.pack()

        self.runallbutton.config(state=NORMAL) 
        self.child.destroy()

    def colorchange(self):
        self.steps.config(bg="white")
        self.runselbutton.config(state=NORMAL)

    def underprocess(self):
        print("processing...")

if __name__ == "__main__":
    app = ldo()
    app.master.title("Primary")
    app.mainloop()

Below screenshot is the output of my app. My need is I want to change the colour of button I click in Primary interface, but what happens is whatever the button I click, it is changing colour of the last button. I tried using lambda, but I doubt if I am using it correctly. The above snippet is working except the colour change part. Please guide me on how to get this done.

Also, I want "Run Selected" button to print (text of) that particular button I clicked.

P.S.: I have checked in this link too yet not solvable.

Output

Upvotes: 1

Views: 744

Answers (1)

FJSevilla
FJSevilla

Reputation: 4513

One option is to use lambda or functools.partial and pass the instance of the boton as argument. Instead of setting the callback when the button is instantiated (the reference does not yet exist) you can use the config method. On the other hand you can use an instance attribute to store the references of the selectable buttons (self._step_buttons in the code below, a list) and another attribute that stores the reference of the selected button (self._step_selected in the code below).

The code could look like this:

import tkinter as tk
from functools import partial



class Popup2(tk.Toplevel):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.geometry("300x300")
        self.title("Secondary")

        self.entry_input = tk.StringVar()
        tk.Label(self, text="Your input").pack()
        tk.Entry(self, textvariable=self.entry_input).pack()
        tk.Button(self, text="Submit", command=self.evaluation, bg="pink").pack()

    def evaluation(self):
        input_value = self.entry_input.get()
        self.master.add_step(input_value)
        self.destroy()


class Ldo(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self._step_buttons = []
        self._step_selected = None
        self.grid()
        self.app_outline()


    def app_outline(self):
        self.masterframe1 = tk.Frame(self.master, width=300, height=300)
        self.masterframe1.grid(sticky=tk.N, padx=20)

        self.masterframe2 = tk.Frame(self.master, width=300, height=100)
        self.masterframe2.grid(sticky=tk.S, padx=20)

        self.addtabbutton = tk.Button(self.masterframe2, text="Add Step", width=10,
                                      command=self.open_popup, bg="sienna1")
        self.addtabbutton.grid(row=0, column=0, sticky=tk.EW)
        self.runallbutton = tk.Button(self.masterframe2, text="Run All", width=10,
                                      command=self.process_all, bg="sienna1", state=tk.DISABLED)
        self.runallbutton.grid(row=0, column=1, sticky=tk.EW)
        self.runselbutton = tk.Button(self.masterframe2, text="Run Selected", width=10,
                                      command=self.process_selected, bg="sienna1", state=tk.DISABLED)
        self.runselbutton.grid(row=0, column=2, sticky=tk.EW)

    def open_popup(self):
        Popup2(master=self)

    def add_step(self, step):
        btn = tk.Button(self.masterframe1, text=step, bg="light blue")
        btn.configure(command=partial(self.select_button, btn))
        btn.pack()
        self._step_buttons.append(btn)
        self.runallbutton.config(state=tk.NORMAL)

    def select_button(self, button):
        if self._step_selected == button:
            self._step_selected.config(bg="light blue")
            self._step_selected = None
            self.runselbutton.config(state=tk.DISABLED)

        else:
           if self._step_selected:
               self._step_selected.config(bg="light blue")
           button.config(bg="white")
           self._step_selected = button
           self.runselbutton.config(state=tk.NORMAL)

    def process_all(self):
        print("Processing all: ")
        for btn in self._step_buttons:
            print("  Processing {}...".format(btn["text"]))

    def process_selected(self):
        print("Processing selected: ")
        print("  Processing {}...".format(self._step_selected["text"]))


if __name__ == "__main__":
    app = Ldo()
    app.master.title("Primary")
    app.mainloop()

I have modified other things, for example, I have provided a toggle button behavior for the buttons.

This is the result:

enter image description here

Upvotes: 1

Related Questions