tkinter开发:用bind给各个button绑定功能,遇到一些问题

各位大侠好,小弟在tkinter开发中又遇到了一个问题,还希望各位大侠鼎力相助,谢谢!
GUI界面上有很多button,想用bind将button绑定功能:鼠标移动到button上能够提示此button的功能。功能已经实现,但遇到一个问题:当一个button的功能提示框显示出来以后,并且是重叠在另外一个button上时,点击ok关闭提示框后,另外一个button的功能提示框会接着显示出来,不知道这个怎么弄?还望各位大侠帮忙,谢谢!
代码如下:
gui界面:
logContinueButton=tk.Button(commonRow2Frame,text=”LOG Continue”,width=12,command=AdbCmdImpl.adbCmdLogContinue) logContinueButton.pack(side=tk.LEFT,fill=tk.X,padx=2,pady=3)
logContinueButton.bind(““,func=lambda buttonIndex: ShowButtonTip.showButtonFunctionInfo(buttonIndex,buttonConst.LOG_CONTINUE_BUTTON))
DPEnableButton=tk.Button(commonRow2Frame,text=”Debug Parser En”,command=AdbCmdImpl.adbCmdDPEnable) DPEnableButton.pack(side=tk.LEFT,fill=tk.X,padx=1,pady=3)
DPEnableButton.bind(““,func=lambda buttonIndex: ShowButtonTip.showButtonFunctionInfo(buttonIndex,buttonConst.DP_ENABLE_BUTTON))
….
类似定义了很多button,并且都用bind绑定了提示框函数
showButtonTip.py
“ “
def showButtonFunctionInfo(self,buttonIndex):
if buttonIndex== buttonConst.LOG_CONTINUE_BUTTON:
message=”aaaa”
elif buttonIndex== buttonConst.DP_ENABLE_BUTTON:
message = “bbbb”
…..
time.sleep(2)
tk.messagebox.showinfo(“功能介绍”,messages)

Jason990420
最佳答案

你问题的代码太乱了, ``` python 前要记得多空一行. 事件内容都不见了 …

  1. showButtonTip.py 如果是个模块, 而 ShowButtonTip 是个类的实例
  2. 绑定时, showButtonFunctionInfo方法有两个参数, 定义中, 扣掉 self 不算, 只有一个参数.
# Binding
lambda buttonIndex: ShowButtonTip.showButtonFunctionInfo(buttonIndex, buttonConst.LOG_CONTINUE_BUTTON)

# Define
def showButtonFunctionInfo(self, buttonIndex):


有关工具提示, 以下的代码来自 PySimpleGUI, 仅供参考

class ToolTip:
    """
    Create a tooltip for a given widget
    (inspired by https://stackoverflow.com/a/36221216)
    This is an INTERNALLY USED only class.  Users should not refer to this class at all.
    """

    def __init__(self, widget, text, timeout=DEFAULT_TOOLTIP_TIME):
        """
        :param widget: The tkinter widget
        :type widget: widget type varies
        :param text: text for the tooltip. It can inslude \n
        :type text: (str)
        :param timeout: Time in milliseconds that mouse must remain still before tip is shown
        :type timeout: (int)
        """
        self.widget = widget
        self.text = text
        self.timeout = timeout
        # self.wraplength = wraplength if wraplength else widget.winfo_screenwidth() // 2
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0
        self.widget.bind("<Enter>", self.enter)
        self.widget.bind("<Leave>", self.leave)
        self.widget.bind("<ButtonPress>", self.leave)

    def enter(self, event=None):
        """
        Called by tkinter when mouse enters a widget
        :param event:  from tkinter.  Has x,y coordinates of mouse

        """
        self.x = event.x
        self.y = event.y
        self.schedule()

    def leave(self, event=None):
        """
        Called by tktiner when mouse exits a widget
        :param event:  from tkinter.  Event info that's not used by function.

        """
        self.unschedule()
        self.hidetip()

    def schedule(self):
        """
        Schedule a timer to time how long mouse is hovering
        """
        self.unschedule()
        self.id = self.widget.after(self.timeout, self.showtip)

    def unschedule(self):
        """
        Cancel timer used to time mouse hover
        """
        if self.id:
            self.widget.after_cancel(self.id)
        self.id = None

    def showtip(self):
        """
        Creates a topoltip window with the tooltip text inside of it
        """
        if self.tipwindow:
            return
        x = self.widget.winfo_rootx() + self.x + DEFAULT_TOOLTIP_OFFSET[0]
        y = self.widget.winfo_rooty() + self.y + DEFAULT_TOOLTIP_OFFSET[1]
        self.tipwindow = tk.Toplevel(self.widget)
        # if not sys.platform.startswith('darwin'):
        try:
            self.tipwindow.wm_overrideredirect(True)
        except:
            print('* Error performing wm_overrideredirect *')
        self.tipwindow.wm_geometry("+%d+%d" % (x, y))
        self.tipwindow.wm_attributes("-topmost", 1)


        label = ttk.Label(self.tipwindow, text=self.text, justify=tk.LEFT,
                          background=TOOLTIP_BACKGROUND_COLOR, relief=tk.SOLID, borderwidth=1)
        if TOOLTIP_FONT is not None:
            label.config(font=TOOLTIP_FONT)
        label.pack()

    def hidetip(self):
        """
        Destroy the tooltip window
        """
        if self.tipwindow:
            self.tipwindow.destroy()
        self.tipwindow = None

另外1楼不知道在说什么 … 没头没尾的.

3年前 评论
讨论数量: 14

另外我按照如下操作均没有成功,鼠标悬浮到按键上,按相应的键没有任何响应, 1、表示鼠标中键单击,其中的 2 换成 3 表示右 键被单击 2、表示 A 键被按下,其中的 A 可以换成其他的键位。 3、表示按下的是 Ctrl 和 V 键,V 可以换成其他 键位。 4、表示按下的是 F1 键,对于 Fn 系列的,都可以随便 换。

3年前 评论
Jason990420

你问题的代码太乱了, ``` python 前要记得多空一行. 事件内容都不见了 …

  1. showButtonTip.py 如果是个模块, 而 ShowButtonTip 是个类的实例
  2. 绑定时, showButtonFunctionInfo方法有两个参数, 定义中, 扣掉 self 不算, 只有一个参数.
# Binding
lambda buttonIndex: ShowButtonTip.showButtonFunctionInfo(buttonIndex, buttonConst.LOG_CONTINUE_BUTTON)

# Define
def showButtonFunctionInfo(self, buttonIndex):


有关工具提示, 以下的代码来自 PySimpleGUI, 仅供参考

class ToolTip:
    """
    Create a tooltip for a given widget
    (inspired by https://stackoverflow.com/a/36221216)
    This is an INTERNALLY USED only class.  Users should not refer to this class at all.
    """

    def __init__(self, widget, text, timeout=DEFAULT_TOOLTIP_TIME):
        """
        :param widget: The tkinter widget
        :type widget: widget type varies
        :param text: text for the tooltip. It can inslude \n
        :type text: (str)
        :param timeout: Time in milliseconds that mouse must remain still before tip is shown
        :type timeout: (int)
        """
        self.widget = widget
        self.text = text
        self.timeout = timeout
        # self.wraplength = wraplength if wraplength else widget.winfo_screenwidth() // 2
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0
        self.widget.bind("<Enter>", self.enter)
        self.widget.bind("<Leave>", self.leave)
        self.widget.bind("<ButtonPress>", self.leave)

    def enter(self, event=None):
        """
        Called by tkinter when mouse enters a widget
        :param event:  from tkinter.  Has x,y coordinates of mouse

        """
        self.x = event.x
        self.y = event.y
        self.schedule()

    def leave(self, event=None):
        """
        Called by tktiner when mouse exits a widget
        :param event:  from tkinter.  Event info that's not used by function.

        """
        self.unschedule()
        self.hidetip()

    def schedule(self):
        """
        Schedule a timer to time how long mouse is hovering
        """
        self.unschedule()
        self.id = self.widget.after(self.timeout, self.showtip)

    def unschedule(self):
        """
        Cancel timer used to time mouse hover
        """
        if self.id:
            self.widget.after_cancel(self.id)
        self.id = None

    def showtip(self):
        """
        Creates a topoltip window with the tooltip text inside of it
        """
        if self.tipwindow:
            return
        x = self.widget.winfo_rootx() + self.x + DEFAULT_TOOLTIP_OFFSET[0]
        y = self.widget.winfo_rooty() + self.y + DEFAULT_TOOLTIP_OFFSET[1]
        self.tipwindow = tk.Toplevel(self.widget)
        # if not sys.platform.startswith('darwin'):
        try:
            self.tipwindow.wm_overrideredirect(True)
        except:
            print('* Error performing wm_overrideredirect *')
        self.tipwindow.wm_geometry("+%d+%d" % (x, y))
        self.tipwindow.wm_attributes("-topmost", 1)


        label = ttk.Label(self.tipwindow, text=self.text, justify=tk.LEFT,
                          background=TOOLTIP_BACKGROUND_COLOR, relief=tk.SOLID, borderwidth=1)
        if TOOLTIP_FONT is not None:
            label.config(font=TOOLTIP_FONT)
        label.pack()

    def hidetip(self):
        """
        Destroy the tooltip window
        """
        if self.tipwindow:
            self.tipwindow.destroy()
        self.tipwindow = None

另外1楼不知道在说什么 … 没头没尾的.

3年前 评论

class Interface:

......
def initADBCmdGui(adbCmdFrame):
      .....
      logContinueButton=
     tk.Button(commonRow2Frame,text="LOGContinue",width=12,command=AdbCmdImpl.adbCmdLogContinue)
      logContinueButton.pack(side=tk.LEFT,fill=tk.X,padx=2,pady=3)
      logContinueButton.bind("<Enter>",func=lambda buttonIndex: 
      ShowButtonTip.showButtonFunctionInfo(buttonIndex,buttonConst.LOG_CONTINUE_BUTTON))
      DPEnableButton=tk.Button(commonRow2Frame,text="Debug Parser 
                                                                                        En",command=AdbCmdImpl.adbCmdDPEnable)
      DPEnableButton.pack(side=tk.LEFT,fill=tk.X,padx=1,pady=3)
      DPEnableButton.bind("<Enter>",func=lambda buttonIndex: 
                                 ShowButtonTip.showButtonFunctionInfo(buttonIndex,buttonConst.DP_ENABLE_BUTTON))

interface类中函数initADBCmdGui中定义了两个Button:1. logContinueButton 2. DPEnableButton,此处每个button有两个功能,单击时执行一个功能,另外当鼠标悬浮在button上达两秒会显示提示功能,下面类实现 class ShowButtonTip:

 ......
 def showButtonFunctionInfo(self,buttonIndex):
        if buttonIndex ==buttonConst.LOG_CONTINUE_BUTTON:
                 messages="Log continue"
        elif buttonIndex ==buttonConst.DP_ENABLE_BUTTON:
                 messages="DP Enable"
        time.sleep(2)
        tk.messagebox.showinfo("功能",messages)

ShowButtonTip类意在实现鼠标移动到上面定义的两个button中的任意一个时,两秒钟后能够显示提示: 此button的功能, 此代码运行遇到一个问题:当鼠标移动到button1上时,程序会按照实现逻辑,2秒后提示一个消息,当此消息框落在button2上时,点击消息框上的确定按钮后,程序会接着显示本该在鼠标移动到button2上显示的消息, 此程序中有10多个button,此处只拿出了两个button作说明,当消息框不是落在其他button上时,没有此问题 谢谢!

3年前 评论
Jason990420

它是按照你定义的方式在工作啊, 点击消息框上的确定按钮后, 鼠标就在 button2 上, 所以就该显示 button2 的消息啊.

你的代码是一旦鼠标进入Button, 不管多久, 都会显示讯息, 虽然是延迟两秒才显示; 我给你的范例是鼠标要在Button上停上两秒才会显示, 这两者不一样的. 后者不会有你说的问题.

3年前 评论

我在程序中设定了两秒后执行:

time.sleep(2) tk.messagebox.showinfo("功能",messages) 点击第一个button的确定按钮后,也没有达到2秒就执行了下一个button的消息显示

3年前 评论
Jason990420

可能是两个以上已显示 button 的消息, 因为重叠, 所以你只看到最后的那一个.

鼠标移动时也许经过了几个 button, 也都已调用各个 button 的 callback.

3年前 评论

另外还有一个问题,为什么百度上搜索的几个方法都无效呢?如但鼠标停留在某个button上时再按F1,一点反应都没有,其他的都类似

1、我们在使用 bind 函数的时候,它的第一个参数就是事件 的类型了。 2、表示鼠标左键单击,其中的 1 换成 3 表示右 键被单击,为 2 的时候表示鼠标中键,感觉不算常用。 3、表示 A 键被按下,其中的 A 可以换成其他 的键位。 4、表示按下的是 Ctrl 和 V 键,V 可以换成其他 键位。 5、表示按下的是 F1 键,对于 Fn 系列的,都可以随便 换。

3年前 评论
Jason990420

百度上搜索的几个方法都无效呢?如但鼠标停留在某个 button 上时再按 F1, 一点反应都没有

你是说绑定F1于button ?? 如果是这样的话, 是没有意义的, 得绑定在窗口. ( 如果你希望F1 只有鼠标在button 上才有效, 那得反向思考–按了F1, 再利用event 参数, 去判断鼠标是否在Button 上方)

import tkinter as tk

def hello():
    print('Hello,world !')

def enter(event):
    print('Inside Button')

def f1(event):
    print('Key F1 Pressed')

root = tk.Tk()
root.bind('<KeyPress-F1>', f1)

button = tk.Button(text='Button', command=hello)
button.bind('<Enter>', enter)
button.pack()

root.mainloop()
3年前 评论

谢谢,我大概明白问题所在了,另外,如果我想实现鼠标悬浮在button上,两秒钟后,当前button有一定的反应,或者是说鼠标悬浮在button上,按F1键(除单击以外的其他操作),当前button能够做出一定的反应,这个应该怎么去实现呢?麻烦给个建议,

非常感谢

3年前 评论
Jason990420
  1. 最前面PO文的代码就是鼠标悬浮在 button 上,timeout时间后,button 会显示相关的提示; 如果时间未到, 就移开鼠标, 取消计时.
  2. 鼠标悬浮在 button 上,按 F1 键,button 能够做出一定的反应, 绑定F1键, 来比对鼠标的位置是否在该按键部件所占的位置中, 是的话才作反应.
3年前 评论

谢谢支持,已经仿照你的代码实现了我这边的功能,非常感谢!!!

3年前 评论

@Jason990420

追加一个问题,仿照您给的class ToolTip的代码,已经实现了我要现实tip的功能,但这个widget位置的获取有一些不准确,但从我百度出来的答案看出:从event中获取当前的位置并没有什么问题,不知道问题出在了哪里?目的是想实现在当前控件的位置能显示这个tip, 还麻烦您帮忙指明一下,感谢!!

3年前 评论
Jason990420

鼠标相对于该部件的座标为 (event.x, event.y), 如果要相对于鼠标位置偏移 (offset_x, offset_y), 真正的座标为

x = self.widget.winfo_rootx() + self.x + offset_x
y = self.widget.winfo_rooty() + self.y + offset_y
3年前 评论

好的,非常感谢!!!

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!