python tkinter 鼠标左键单击仅适用于双击

python tkinter mouse left click works only with double click

使用下面的代码 Button-1 点击调用 relief 更改仅在已点击一次时才有效(只有第一次双击有效,第二次正常,但如果其他小部件是选择,同样的事情发生):

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)

Button-2 和 Button-3 工作正常,

这是什么原因?

看来您只需要调整一个东西就可以 single-click 在按钮上激活该功能。尝试将绑定更改为此:

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)

只需将“Button”改为“Button-1”,如有错误请告知

问题是 tkinter 可以将许多函数绑定到事件,并且已经绑定了默认函数,当您单击按钮时它会更改 relief。您可以在您的函数中使用 return "break" 来通知 tkinter 您处理了此事件,它将跳过其他函数。

或者您可以使用标准 command= 来分配函数,然后它会跳过其他函数。

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()  

同样使用for循环和lambda

通常它仅使用对 button 的引用,循环中更改的值因此最终所有函数都使用对相同值的引用 - 这是循环中分配的最后一个值。

使用 lambda arg=button 它在每个循环中创建新变量并将值从 button 复制到 arg 因此每个小部件使用不同的 arg 和不同的值。

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()  

正如@acw1668 在评论中提到的,您也可以使用 Checkbutton(..., indicator=False) 获得相同的效果而无需额外的功能

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()