python-3.xuser-interfaceevent-handlingpysimplegui

How to change the button colors onclick event?


On a ms-window app., I wish to update the button style "on-click" event, and keep it back to its original style "on-release". I tested at least these 2 ways, both driving to no effect :

    BTN_TEXT_COLOR = '#b7babd'
    BTN_BCKGD_COLOR = None # also tried with setting a color here
    BTN_TEXT_COLOR_CLICKED = 'green'
    BTN_BCKGD_COLOR_CLICKED = 'darkBlue'
    BTN_NORMAL = (BTN_TEXT_COLOR, BTN_BCKGD_COLOR )
    BTN_CLICKED = (BTN_TEXT_COLOR_CLICKED, BTN_BCKGD_COLOR_CLICKED )
    # see Button class param:  mouseover_colors

    def run(self):
    
        while True:
        
            event, values = self.window.read() 
             
            if event in self.dispatch_dict:                      
                self.visualClick(event) # <-- or: self.visualClick2(event) 
                func2call = self.dispatch_dict.get(event)       
                func2call(event)
            else:
                print(f"Event {event} NOT found in dispatch_dict")
                
            if event in (None, 'Exit'):
                break
    
            if event == sg.WIN_CLOSED:
                break
        
        self.window.close()
        exit(0)       


    def visualClick(self, evt):
        self.window[evt].update(button_color=self.BTN_CLICKED) # NOK (colors changed at key up)
        sleep(0.1)
        self.window[evt].update(button_color=self.BTN_NORMAL) # NOK (or, keeps as 'pressed' if no-or-default original parameters)

    def visualClick2(self, evt):
        self.window[evt].mouseover_colors = self.BTN_CLICKED # NOK
        sleep(0.1)
        self.window[evt].update(button_color=self.BTN_NORMAL) # NOK

I also tried to update the window object within the callback function, and/or to set the BTN_BCKGD_COLOR to a color instead of None: no effect either.
Any help appreciated.


Solution

  • In general, event generated after you released the button, so it will be too late to handle the events.

    There's default binding exist for Button element, so it will work more complex than you thought after you bind another one.

    bind(bind_string, key_modifier, propagate=True) Used to add tkinter events to an Element. propagate: If True then tkinter will be told to propagate the event to the element propagate: (bool)

    Add option propagate=False when binding, but you need to handle all the appearance of Button by yourself.

    Example Code

    import PySimpleGUI as sg
    
    font = ("Courier New", 16)
    sg.theme("DarkBlue")
    sg.set_options(font=font)
    
    keys = ["Button 1", "Button 2"]
    actions = {"PRESSED":("green", "darkblue"), "RELEASED":sg.theme_button_color()}
    
    layout = [[sg.Button(key) for key in keys]]
    window = sg.Window("Title", layout, finalize=True)
    
    for key in keys:
        window[key].bind('<ButtonPress-1>',  '+PRESSED',  propagate=False)
        window[key].bind('<ButtonRelease-1>','+RELEASED', propagate=False)
    
    while True:
    
        event, values = window.read()
    
        if event == sg.WIN_CLOSED:
            break
        elif event.endswith("+PRESSED") or event.endswith("+RELEASED"):
            key, action = event.split("+")
            window[key].update(button_color=actions[action])
    
    window.close()
    

    enter image description here enter image description here