- List item
tkinter绘制组件(2)——按钮
引言
看过前一篇文章,就基本知道了TinUI的主体框架和开发宗旨。
接下来,我们将继续完善TinUI的组件绘制功能。先从最简单的按钮开始,毕竟按钮是界面交互中与使用者接触最多的组件,也是有着强大执行能力的组件,必须要让tkinter绘制出一个可以识别、好用、现代化的按钮UI组件。
目标
凡事都得定一个目标。
用TinUI会指出来的按钮,必须满足以下几个条件:
- 可以让人识别出来是按钮(这个很重要)
- 可执行函数,即响应交互(废话)
- 对鼠标事件有反应
这是几个基础目标,那么TinUI的标准,就是Windows10的exe原生界面按钮。Windows10的原生按钮有以下几个特点:
- 常规背景色为:#E1E1E1
- 响应背景色为:#E5F1FB
- 响应边框色为:#82BDEB
- 可自定字体颜色
那么,现在开工。
绘制按钮
定义函数
在TinUI中,使用add_button
添加按钮,其定义:
def add_button(self,pos:tuple,text:str,fg='black',bg='#E1E1E1',font=('微软雅黑',12),command=None):#绘制按钮
'''
pos::位置,(x,y)
text::按钮文字
fg::按钮文字颜色
bg::按钮背景色
font::文字字体
command::响应的函数
'''
绘制文字和按钮主体
因为使用画布绘制组件,一般来说,后创建的组件要比之前创建的组件位置层级要高,一般人会先绘制矩形,再添加文字。但这样有一个问题:我怎么知道矩形能否匹配文字?万一文字超出矩形范围不久“露馅”了?
在tkinter的Canvas中,通过绘制矩形和文字就可以绘制出一个虚拟按钮组件。但是,必须要先创建文字,再根据文字所占用的画布空间绘制矩形。代码如下:
button=self.create_text(pos,text=text,fill=fg,font=font,anchor='nw')
bbox=self.bbox(button)#获取文字占用的画布空间
#下面的代码主要是为了让人看起来更顺眼,使矩形能够更好地覆盖文字
x1,y1,x2,y2=bbox[0]-3,bbox[1]-3,bbox[2]+3,bbox[3]+3
#根据文字占位绘制矩形
back=self.create_rectangle((x1,y1,x2,y2),fill=bg,outline='grey')
这一番操作后,矩形会覆盖文字,那么还需要一个迷之操作来使文字到矩形上方:
self.tkraise(button)
相应鼠标事件
作为一个虚拟按钮,就必须要能够响应点击事件,执行函数:
self.tag_bind(button,'<Button-1>',command)
那么,为了提高按钮的“颜值”,当鼠标进入按钮时,按钮需要变色来使鼠标操作更有力度。当鼠标离开按钮时,按钮就要恢复其本身的颜色样式。接下来创建改变按钮样式的两个函数,这两个函数以内部函数创建。
def in_button(event):#鼠标进入
self.itemconfig(back,fill='#E5F1FB',outline='#82BDEB')
def out_button(event):#鼠标离开
self.itemconfig(back,fill=bg,outline='grey')
然后再绑定文字的事件:
一定是文字的事件,因为文字在矩形之上,矩形不会响应事件。
self.tag_bind(button,'<Enter>',in_button)
self.tag_bind(button,'<Leave>',out_button)
至此,我们完成通过TinUI绘制虚拟按钮组件的功能了。
完整函数代码
def add_button(self,pos:tuple,text:str,fg='black',bg='#E1E1E1',font=('微软雅黑',12),command=None):#绘制按钮
def in_button(event):
self.itemconfig(back,fill='#E5F1FB',outline='#82BDEB')
def out_button(event):
self.itemconfig(back,fill=bg,outline='grey')
button=self.create_text(pos,text=text,fill=fg,font=font,anchor='nw')
bbox=self.bbox(button)
x1,y1,x2,y2=bbox[0]-3,bbox[1]-3,bbox[2]+3,bbox[3]+3
back=self.create_rectangle((x1,y1,x2,y2),fill=bg,outline='grey')
self.tag_bind(button,'<Button-1>',command)
self.tag_bind(button,'<Enter>',in_button)
self.tag_bind(button,'<Leave>',out_button)
self.tkraise(button)
return button
效果
按钮效果
测试代码:
def test(event):
print('ok')
a.title('TinUI Test')
b.add_paragraph((50,200),'这是TinUI按钮触达的事件函数回显,此外,窗口标题也被改变')
a=Tk()
a.geometry('700x700+5+5')
b=TinUI(a,bg='white')
b.pack(fill='both',expand=True)
m=b.add_title((600,0),'TinUI is a test project for futher tin using')
b.add_title((40,670),'test TinUI scrolled',size=2,angle=24)
b.add_paragraph((20,290),''' TinUI是基于tkinter画布开发的界面UI布局方案,作为tkinter拓展和TinEngine的拓展而存在。目前,TinUI尚处于开发阶段。如果想要使用完整的TinUI,敬请期待。''',
angle=-18)
b.add_paragraph((20,100),'下面的段落是测试画布的非平行字体显示效果,也是TinUI的简单介绍')
b.add_button((250,450),'测试按钮',command=test)
#a.after(5000,lambda:b.delete(m))
a.mainloop()
以下是按钮渲染的效果:
效果图中的代码,段落渲染部分没有使用 -angle 参数。
真的虚拟控件
不要认为这个按钮是我用 create_window 加上去的,看看它有没有句柄:
没有。很显然,我们成功创建了虚拟按钮。
2021-7-29新样式
与Label区分开来。
2021-12-4新样式
优化视觉效果;同时适配TinUI菜单 (现使用button2)。
2024-7-7新参数
可指定最小宽度和最大宽度,下图为限制minwidth=200
:
github项目
结语
怎么样?玩tkinter,就应该玩出花样来。
🔆tkinter创新🔆