python - Tkinter 按钮工具提示线程问题
问题描述
您好我正在尝试创建在悬停时具有工具提示气泡的 Tkinter 按钮。我希望工具提示在输入时延迟,并且只显示一定的时间。我正在使用线程来显示工具提示,以免阻止单击按钮。我似乎非常接近解决方案,但我认为有一个问题与线程有关。工具提示是一个没有任何窗口装饰(标题栏、边框等)的顶级窗口。输入按钮时,会显示工具提示,但有时它有装饰,有时没有,有时它出现在正确的位置,有时却没有。我不知道为什么会发生这种行为,下面我发布了我用来解决这个问题的测试代码,但现在我失去了任何帮助将不胜感激。
from time import sleep
from tkinter import Tk, Button, Label, Toplevel
from threading import Thread
class _Button(Button):
def __init__(self, parent, *args, **kwargs):
self.tooltip_text = kwargs.pop('tooltip', None)
super().__init__(*args, **kwargs)
self.t = None
self.parent = parent
self.btn_tooltip = None
def tooltip(self):
if not self.t:
self.t = Thread(target=self.tooltip_render)
self.t.start()
def tooltip_render(self):
sleep(0.5)
if not self.btn_tooltip:
self.btn_tooltip = Toplevel()
self.btn_tooltip.wm_overrideredirect(True)
x, y, cx, cy = self.bbox('insert')
x += self.winfo_rootx() + 25
y += self.winfo_rooty() + 25
self.btn_tooltip.geometry('+%d+%d' % (x, y))
label = Label(
self.btn_tooltip, text=self.tooltip_text, background='yellow', borderwidth=1,
)
label.pack(ipadx=5, ipady=2)
sleep(1)
if self.btn_tooltip:
self.btn_tooltip.destroy()
self.btn_tooltip = None
self.t = None
def enter(e):
e.widget.tooltip()
def leave(e):
if e.widget.btn_tooltip:
e.widget.btn_tooltip.destroy()
e.widget.btn_tooltip = None
e.widget.t = None
root = Tk()
bt1 = _Button(root, text='Button 1', tooltip='Tooltip1')
bt1.bind('<Enter>', enter)
bt1.bind('<Leave>', leave)
bt1.grid()
bt2 = _Button(root, text='Button 2', tooltip='Tooltip2')
bt2.bind('<Enter>', enter)
bt2.bind('<Leave>', leave)
bt2.grid(row=0, column=1)
root.mainloop()
解决方案
您不需要线程来显示工具提示,然后在几秒钟后消失。即使您有丰富的线程经验,线程也很困难。如果不这样做会更加困难,而将其与基于事件的程序结合起来会更加困难。
相反,您应该使用 tkinter 提供的工具。即,after
可以调度代码运行到未来的方法。
您需要做的就是使用after
来显示您的工具提示,然后after
再次使用来关闭它。
基本模式如下所示:
def tooltip_render(self):
# create the tooltip
self.btn_tooltip = Toplevel()
...
<the rest of your code to render the tooltip>
...
# schedule it to go away
self.after(1000, self.btn_tooltip.destroy)
接下来,render_tooltip
再次使用after
:
def tooltip(self):
self.after(500, self.tooltip_render)
仅此一项不会为您提供完美的工具提示。如果用户快速移动鼠标,您仍然需要防止尝试渲染和销毁多个工具提示,但这为您提供了通用框架,而无需求助于线程。
推荐阅读
- javascript - Javascript - 基于另一个 javascript 对象属性的排序数组
- apache-spark - Spark Dataframe 的 RDD spark.default.parallelism 等效项
- c# - iOS/Xamarin 如何使用 Biometrics 允许用户登录已有用户名和密码的帐户?
- algorithm - 这个硬币找零算法的时间复杂度是多少?
- rest - Netsuite Webservices Postman 集合在哪里?
- python - 将列添加到数据框
- angular - 如何从模板中获取与Angular中数组中的属性匹配的对象计数?
- python - 编码作为值列表的分类变量
- uproot - 如何将大量数据作为惰性数组读取
- amazon-dynamodb - 已定义分区键和排序键时,DynamoDB如何通过createdAt查询