tkinter文本框小功能(2):提示框
- 引言
- 思路
- 实现
- 窗口外的ToolTip
- 注意区别
引言
在Python自带,用tkinter编写的IDLE中,会出现一些函数使用气泡提示框在文本框中显示注释文本,虽然效率有点慢,但是能够让读者直观地显示函数的意义和作用。
从idlelib的源码中,可以看出这个是用tix中的气泡提示框实现的,但是只能够显示文本。在我的这篇使用Label实现Balloon的文章中,Label组件内可以继续放置tkinter组件,从而提升气泡提示框的丰富程度。
现在,我们可以用那一篇文章的思路,更简洁地来完成这个功能。
思路
之前的文章是在窗口下实现对组件绑定气泡提示框,而在文本框中,绑定tag就可以实现相同的功能。
为了在所有文本框中均可以使用,先定义一个文本框类:
from tkinter import Text
class MyText(Text):
def __init__(self,master,**kw):
Text.__init__(self,master,**kw)
def text_balloon_show(self,event,text,fg='black',bg='#f0f0f0'):#显示提示框
pass
def text_balloon_end(self,event):#提示框关闭
pass
根据前面的文章,思路是在文本框中,通过对文本添加tag,当鼠标进入时显示气泡提示框,当鼠标离开时关闭气泡提示框。
实现
以下是测试代码:
t=MyText(fg='black',bg='#00011')#颜色是乱写的
t.tag_configure('test',bg='blue')
t.insert('end','长征火箭','test')
t.tag_bind('test','<Enter>',lambda event:t.text_balloon_show(event,'中国航天局的运载火箭系列名称,英文:CZ'))
t.tag_bind('test','<Leave>',t.text_balloon_end)
t.mainloop()#组件也有mainloop
由此可以继续编写text_balloon_show和text_balloon_end两个函数
from tkinter import Text
class MyText(Text):
def __init__(self,master,**kw):
Text.__init__(self,master,**kw)
def text_balloon_show(self,event,text,fg='black',bg='#f0f0f0'):#受控的气泡提示框
ball=Label(self,text=text,fg=fg,bg=bg)#创建一个Label
ball.place(x=event.x,y=event.y)#定位鼠标在文本框中的位置
self.ball_text=ball
def text_balloon_end(self,event):
self.ball_text.place_forget()
效果见tkinter文本框小功能(1)。
在TinReader中的超链接,使用 <word>描述;前景色;链接
窗口外的ToolTip
之前的代码中,提示框都是显示在组件内部,但是相比于整个窗口而言,提示框的功能就小了很多。而在常见的tkinter拓展中,都会出现一个叫 ToolTip 的拓展组件,这个组件可以设置透明度、显示延迟、鼠标跟随,同时还能够插入其它组件。下面的ToolTip代码取自PAGE-tkinter编辑器。
class ToolTip(Toplevel):
"""
Provides a ToolTip widget for Tkinter.
To apply a ToolTip to any Tkinter widget, simply pass the widget to the
ToolTip constructor
"""
def __init__(self, wdgt, tooltip_font, msg=None, msgFunc=None, fg='black', bg='#ffff00',
delay=0.5, follow=True):
"""
Initialize the ToolTip
Arguments:
wdgt: The widget this ToolTip is assigned to
tooltip_font: Font to be used
msg: A static string message assigned to the ToolTip
msgFunc: A function that retrieves a string to use as the ToolTip text
delay: The delay in seconds before the ToolTip appears(may be float)
follow: If True, the ToolTip follows motion, otherwise hides
"""
self.wdgt = wdgt
# The parent of the ToolTip is the parent of the ToolTips widget
self.parent = self.wdgt.master
self.fg,self.bg=fg,bg
# Initalise the Toplevel
Toplevel.__init__(self, self.parent, bg=self.bg, padx=1, pady=1)
# Hide initially
self.withdraw()
# The ToolTip Toplevel should have no frame or title bar
self.overrideredirect(True)
# The msgVar will contain the text displayed by the ToolTip
self.msgVar = tk.StringVar()
if msg is None:
self.msgVar.set('No message provided')
else:
self.msgVar.set(msg)
self.msgFunc = msgFunc
self.delay = delay
self.follow = follow
self.visible = 0
self.lastMotion = 0
# The text of the ToolTip is displayed in a Message widget
tk.Message(self, textvariable=self.msgVar, bg=self.bg, fg=self.fg,
font=tooltip_font,
aspect=1000).grid()
# Add bindings to the widget. This will NOT override
# bindings that the widget already has
self.wdgt.bind('<Enter>', self.spawn, '+')
self.wdgt.bind('<Leave>', self.hide, '+')
self.wdgt.bind('<Motion>', self.move, '+')
def spawn(self, event=None):
"""
Spawn the ToolTip. This simply makes the ToolTip eligible for display.
Usually this is caused by entering the widget
Arguments:
event: The event that called this funciton
"""
self.visible = 1
# The after function takes a time argument in milliseconds
self.after(int(self.delay * 1000), self.show)
def show(self):
"""
Displays the ToolTip if the time delay has been long enough
"""
if self.visible == 1 and time() - self.lastMotion > self.delay:
self.visible = 2
if self.visible == 2:
self.deiconify()
def move(self, event):
"""
Processes motion within the widget.
Arguments:
event: The event that called this function
"""
self.lastMotion = time()
# If the follow flag is not set, motion within the
# widget will make the ToolTip disappear
#
if self.follow is False:
self.withdraw()
self.visible = 1
# Offset the ToolTip 10x10 pixes southwest of the pointer
self.geometry('+%i+%i' % (event.x_root+20, event.y_root-10))
try:
# Try to call the message function. Will not change
# the message if the message function is None or
# the message function fails
self.msgVar.set(self.msgFunc())
except:
pass
self.after(int(self.delay * 1000), self.show)
def hide(self, event=None):
"""
Hides the ToolTip. Usually this is caused by leaving the widget
Arguments:
event: The event that called this function
"""
self.visible = 0
self.withdraw()
def update(self, msg):
"""
Updates the Tooltip with a new message. Added by Rozen
"""
self.msgVar.set(msg)
这里里面的注释写得很详细。如果想用在文本框内,可进行如下更改:
def __init__(self, text, tagname,tooltip_font, msg=None, msgFunc=None, fg='black', bg='#ffff00',
delay=0.5, follow=True):#wdgt=>tagname, +text
self.tagname=tagname###
self.parent = text.master###
#...
text.tag_bind(self.tagname,'<Enter>', self.spawn, '+')
text.tag_bind(self.tagname,'<Leave>', self.hide, '+')
text.tag_bind(self.tagname,'<Motion>', self.move, '+')
注意区别
与前一篇文章相比,该文章是有一定的区别的,使用场合也是不一样的。
如果没有看过之前的文章,现在建议查看一下使用Label实现Balloon。
在之前的文章中,是组建需要绑定提示框,那么提示框必须在组件之外。<Button-1>事件中,event会返回两个坐标数组,其中rootx, rooty是相对于窗口左上角顶点的坐标,因此Label只能创建在主窗口中。
在文本框里,文字始终在文本框内部,而且可以滚动,因此使用event.x, event.y更加方便。
需要注意的是,这篇文章只是在文本框实现的小功能,并不是之前那篇文章的升级,因此需要注意使用场合和方式。
☀tkinter创新☀