【问题标题】:python tkinter mouse left click works only with double clickpython tkinter 鼠标左键单击仅适用于双击
【发布时间】:2020-11-26 10:01:36
【问题描述】:

使用下面的代码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 可以正常工作,

是什么原因?

【问题讨论】:

  • 首先使用print() 来检查您点击event.widget.cget("relief") 时会得到什么。第二:根据您的问题创建最小的工作代码,我们可以测试。
  • 尝试在select()函数中添加return 'break'
  • 其实Checkbutton可以和indicator=False一起使用,效果是一样的。
  • 其实我只是觉得默认的鼠标按键释放事件处理器可能会搞乱浮雕状态的同步。但是为什么它在第二次单击时起作用,然后在单击另一个按钮后不起作用,我不知道原因。 return "break" 只是跳过默认事件处理程序。再一次,我更喜欢使用 Checkbuttonindicator=False
  • 你必须将按钮分配给arg= - 你不能直接把它放在selected() - button['command'] = lambda arg=button:selected(arg) 所有的问题是它不会将值从button 复制到@987654337 @ 但仅引用变量button,它在循环中更改,所以最后所有selected 都使用对相同值的引用——for-loop 中的最后一个值。使用 arg=button 它会在每个循环中创建新变量,并将值从 button 复制到 arg - 所以每个 selected() 使用不同的 arg 具有不同的值。

标签: python button events tkinter bind


【解决方案1】:

您似乎只需要调整一个东西就可以单击按钮来激活该功能。尝试将绑定更改为:

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”,如有错误请告诉我

【讨论】:

  • 它不适用于 ,我在这里尝试并使用
  • 尝试使用ButtonPress 而不是Button=1
  • 也一样。
  • 它与&lt;Button&gt;&lt;Button-1&gt;&lt;ButtonReleased&gt;&lt;ButtonReleased-1&gt;&lt;ButtonPressed&gt;&lt;ButtonPressed-1&gt; 几乎相同。问题是 tkinter 可以将许多函数绑定到同一个事件,并且已经绑定(默认)函数必须停止/跳过 - 而return "break" 跳过了第二个函数。
【解决方案2】:

问题是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-loop 和lambda

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

使用lambda arg=button 它在每个循环中创建新变量并将值从button 复制到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()  

【讨论】:

  • 这样for循环生成的按钮也可以工作。谢谢。
  • 将此标记为正确答案,如果它帮助您解决问题:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2012-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多