简体   繁体   中英

python tkinter mouse left click works only with double click

With the below code Button-1 click called relief change works only when it is already clicked once (only double click works 1st time, 2nd time it is ok, but if an other widget is selected, the same happens):

def selected(event):
    event.widget.config(relief=SUNKEN if event.widget.cget("relief") == "raised" else RAISED)    

B1 = Button(root, text ='BUTTON1', font='-size 8', relief=RAISED)
B1.bind("<Button>", selected)
B1.grid(row = 1, column = 2, sticky = N+E+S+W)

B2 = Button(root, text ='BUTTON2', font='-size 8', relief=RAISED)
B2.bind("<Button>", selected)
B2.grid(row = 2, column = 2, sticky = N+E+S+W)

With Button-2 and Button-3 it is working properly,

What is the reason?

Problem is that tkinter can bind many functions to event and there is already binded default function which changed relief when you click button. You can use return "break" in your function to inform tkinter that you processed this event and it will skip other functions.

Or you could use standard command= to assing function and then it will skip other function.

import tkinter as tk  # PEP8: `import *` is not preferred
 
# --- functions ---

def selected1(event):
    event.widget.config(relief='sunken' if event.widget.cget('relief') == 'raised' else 'raised')    
    return "break"

def selected2():
    B2.config(relief='sunken' if B2.cget("relief") == 'raised' else 'raised')    

# --- main ---

root = tk.Tk()

B1 = tk.Button(root, text='BUTTON1', relief='raised')
B1.bind("<Button>", selected1)
B1.grid(row=1, column=2, sticky='news')

B2 = tk.Button(root, text='BUTTON2', relief='raised', command=selected2)
B2.grid(row=2, column=2, sticky='news')

root.mainloop()  

The same using for -loop and lambda .

Normally it use only reference to button which valeu is changed in loop so finally all functions use reference to the same value - which is last value assigned in loop.

Using lambda arg=button it create new variable in every loop and copy value from button to arg so every widget use different arg with differen value.

import tkinter as tk  # PEP8: `import *` is not preferred
 
# --- functions ---

def selected(widget):
    widget.config(relief='sunken' if widget.cget('relief') == 'raised' else 'raised')    

# --- main ---

root = tk.Tk()

for x in range(1, 6):
    button = tk.Button(root, text=f'LOOP BUTTON {x}', relief='raised')
    #button.config(command=lambda arg=button:selected3(arg))
    button['command'] = lambda arg=button:selected(arg)
    button.grid(row=x, column=2, sticky='news')

root.mainloop()  

As @acw1668 mentioned in comment you can also uses Checkbutton(..., indicator=False) to get the same effect without extra function

import tkinter as tk  # PEP8: `import *` is not preferred
 
# --- main ---

root = tk.Tk()

for x in range(1, 6):
    button = tk.Checkbutton(root, text=f'LOOP BUTTON {x}', indicator=False, padx=10, pady=5)
    button.grid(row=x, column=2, sticky='news')

root.mainloop()  

It seems that you just have to tweak a single thing in order to single-click on buttons to activate the function. Try changing the bind to this:

def selected(event):
    event.widget.config(relief=SUNKEN if event.widget.cget("relief") == "raised" else RAISED)    

B1 = Button(root, text ='BUTTON1', font='-size 8', relief=RAISED)
B1.bind("<Button-1>", selected)
B1.grid(row = 1, column = 2, sticky = N+E+S+W)

B2 = Button(root, text ='BUTTON2', font='-size 8', relief=RAISED)
B2.bind("<Button-1>", selected)
B2.grid(row = 2, column = 2, sticky = N+E+S+W)

Just change "Button" to "Button-1" and please tell me if there are errors

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM