tkinter绘制组件(16)——现代输入框
引言
实际上,在TinUI中,很早就有了add_entry
这个函数,以此在TinUI界面中添加单行输入框。但是,这只是一种简化操作,并没有完全实现TinUI对于组件现代化的目标。
如果使用Windows10系统的各位,打开【设置】后,可以看到顶部有输入框。我们仔细观察这个输入框,会发现有以下特点:
- 以扁平化设计响应焦点得失
- 拥有默认文本
- 如果没有任何输入内容,右侧显示一个图标,标识输入框的意义
- 当有输入内容时,右侧显示清除标识按钮
那么,我们将以winUI的输入框为样式标准,改进TinUI中的输入框。
因为tkinter画布的限制,任何人都不可能完全绘制一个接受输入的画布对象。
布局
函数结构
def add_entry(self,pos:tuple,width:int,text:str='',fg='black',bg='white',font=('微软雅黑',12),outline='#999999',onoutline='#4258cc',icon='>',anchor='nw'):#绘制单行输入框
'''
pos::位置
width::输入框宽度
text::默认文本
fg::字体颜色
bg::背景色
font::字体
outline::边框颜色
onoutline::输入框获取焦点后,边框颜色;标识符响应颜色
icon::标识符
anchor::对齐位置
'''
组件功能
以winUI最为参考,我们TinUI的输入框也要有同winUI输入框相同的基本功能。只不过,我们有一点不同,那就是标识符。
因为我并没有使用过winUI,因此对于输入框右侧的标识符能否自定义尚不清楚。在【设置】界面中,标识符为“🔎”(字符版),而TinUI输入框的标识为“>”。
创建输入框
这个,如果是初学者的话……对不起,这一步很简单,对于我们这些感兴趣而研究tkinter的人来说,直接上代码。
entry=Entry(self,fg=fg,bg=bg,font=font,relief='flat',highlightcolor=fg,bd=2)
entry.insert(0,text)
funce=self.create_window(pos,window=entry,width=width,anchor=anchor)#输入框画布对象
创建标识符和边框
根据前面十多篇开发TinUI的经验,相信按顺序一直看这个专栏的读者已经完全掌握了通过覆盖位置确定新画布对象位置的技巧。这里直接上代码。
绘制标识符:
funcw=self.create_text((pos[0]+width,pos[1]),text=icon,fill=fg,font=font,anchor='nw')
根据Entry和标识符的画布覆盖位置,绘制边框:
注意,因为通过字体大小很难找到对应的实际覆盖尺寸,因此我们以Entry的覆盖高度最为边框高度基数,而不是用标识符的高度。
w=self.bbox(funcw)[2]
h=self.bbox(funce)[3]
back=self.create_rectangle((pos[0]-2,pos[1]-2,w+2,h+2),outline=outline,fill=bg)
self.lower(back)
响应焦点事件
TinUI尚简,因此对于这些比较简单、只改变样式的事件回调,我们使用lambda
语句创建函数。
这样,我们可以为Entry添加焦点事件:
entry.bind('<FocusIn>',lambda event:self.itemconfig(back,outline=onoutline))
entry.bind('<FocusOut>',lambda event:self.itemconfig(back,outline=outline))
标识符功能
前面讲到,我们需要模仿winUI的输入框标识符功能,以此使TinUI的输入框更加现代化和人性化。
因为输入框的内容显示取决于键盘事件,因此我们需要绑定Entry的键盘输入事件。
def if_empty():
#...
pass
entry.bind('<KeyRelease>',if_empty)
我们可以通过判断输入框内的内容,栏更改标识符的样式和绑定的事件。这样可以进行简单梳理:
- 如果输入内容为空,则显示默认标识符,不响应任何事件
- 如果有输入内容,则显示“×”,点击删除输入内容并恢复默认标识符
从上面的分析,得出以下代码:
def if_empty(event):
ch=entry.get()
if ch=='':
self.tag_unbind(funcw,'<Leave>')
self.tag_unbind(funcw,'<Enter>')
self.tag_unbind(funcw,'<Button-1>')
self.itemconfig(funcw,text=icon,fill=fg)
else:
self.itemconfig(funcw,text='×')
self.tag_bind(funcw,'<Enter>',lambda event:self.itemconfig(funcw,fill=onoutline))
self.tag_bind(funcw,'<Leave>',lambda event:self.itemconfig(funcw,fill=fg))
self.tag_bind(funcw,'<Button-1>',lambda event:(entry.delete(0,'end'),if_empty(None)))
而为了避免每一次检测到有输入内容,就重新更新标识符和绑定事件,这会导致占用一定的计算资源。因此我们可以先判断目前标识符的状态,再决定是否执行刷新操作:
def if_empty(event):
ch=entry.get()
if ch=='':
#...
else:
if self.itemcget(funcw,'text')==icon:
#...
OK,大功告成。
完整代码函数
def add_entry(self,pos:tuple,width:int,text:str='',fg='black',bg='white',font=('微软雅黑',12),outline='#999999',onoutline='#4258cc',icon='>',anchor='nw'):#绘制单行输入框
#这是一个半绘制组件
def if_empty(event):
ch=entry.get()
if ch=='':
self.tag_unbind(funcw,'<Leave>')
self.tag_unbind(funcw,'<Enter>')
self.tag_unbind(funcw,'<Button-1>')
self.itemconfig(funcw,text=icon,fill=fg)
else:
if self.itemcget(funcw,'text')==icon:
self.itemconfig(funcw,text='×')
self.tag_bind(funcw,'<Enter>',lambda event:self.itemconfig(funcw,fill=onoutline))
self.tag_bind(funcw,'<Leave>',lambda event:self.itemconfig(funcw,fill=fg))
self.tag_bind(funcw,'<Button-1>',lambda event:(entry.delete(0,'end'),if_empty(None)))
entry=Entry(self,fg=fg,bg=bg,font=font,relief='flat',highlightcolor=fg,bd=2)
entry.insert(0,text)
entry.bind('<KeyRelease>',if_empty)
entry.bind('<FocusIn>',lambda event:self.itemconfig(back,outline=onoutline))
entry.bind('<FocusOut>',lambda event:self.itemconfig(back,outline=outline))
funce=self.create_window(pos,window=entry,width=width,anchor=anchor)#输入框画布对象
funcw=self.create_text((pos[0]+width,pos[1]),text=icon,fill=fg,font=font,anchor='nw')
w=self.bbox(funcw)[2]
h=self.bbox(funce)[3]
back=self.create_rectangle((pos[0]-2,pos[1]-2,w+2,h+2),outline=outline,fill=bg)
self.lower(back)
if_empty(None)
return entry
效果
测试代码
def test(event):
a.title('TinUI Test')
b.add_paragraph((50,150),'这是TinUI按钮触达的事件函数回显,此外,窗口标题也被改变、首行标题缩进减小')
b.coords(m,100,5)
def test1(word):
print(word)
def test2(event):
ok1()
def test3(event):
ok2()
def test4(event):
from time import sleep
for i in range(1,101):
sleep(0.02)
progressgoto(i)
def test5(result):
b.itemconfig(scale_text,text='当前选值:'+str(result))
if __name__=='__main__':
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')
m1=b.add_title((0,680),'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),'测试按钮',activefg='white',activebg='red',command=test,anchor='center')
b.add_checkbutton((80,430),'允许TinUI测试',command=test1)
b.add_label((10,220),'这是由画布TinUI绘制的Label组件')
b.add_entry((250,300),350,'这里用来输入')
b.add_separate((20,200),600)
b.add_radiobutton((50,480),300,'sky is blue, water is blue, too. So, what is your heart',('red','blue','black'),command=test1)
b.add_link((400,500),'TinGroup知识库','http://tinhome.baklib-free.com/')
_,ok1=b.add_waitbar1((500,220),bg='#CCCCCC')
b.add_button((500,270),'停止等待动画',activefg='cyan',activebg='black',command=test2)
bu1=b.add_button((700,200),'停止点状滚动条',activefg='white',activebg='black',command=test3)[1]
bu2=b.add_button((700,250),'nothing button 2')[1]
bu3=b.add_button((700,300),'nothing button 3')[1]
b.add_labelframe((bu1,bu2,bu3),'box buttons')
_,_,ok2=b.add_waitbar2((600,400))
b.add_combobox((600,550),text='你有多大可能去珠穆朗玛峰',content=('20%','40%','60%','80%','100%','1000%'))
b.add_button((600,480),text='测试进度条(无事件版本)',command=test4)
_,_,_,progressgoto=b.add_progressbar((600,510))
b.add_table((180,630),data=(('a','space fans over the world','c'),('you\ncan','2','3'),('I','II','have a dream, then try your best to get it!')))
b.add_paragraph((300,810),text='上面是一个表格')
b.add_onoff((600,100))
b.add_spinbox((680,100))
b.add_scalebar((680,50),command=test5)
scale_text=b.add_label((890,50),text='当前选值:2')
a.mainloop()
最终效果
2022-1-15新样式
- 更加丰富的样式设定:平常和激活时的边框与背景色、字体颜色
- TinUI组件被左键单击时,TinUI获取焦点,输入框恢复常规样式
2022-2-19新样式
- 添加自调用函数参数
- 当指定回调函数时,可以使用按钮或回车调用
2022-5-3新样式
- 圆角背景元素
- 提示边框移到底部
- 仿WinUI3元素布局,之前是WinUI2
2022-8-7新功能
- 新增返回值
funcs
,提供一些基础方法
2024-6-23密码框新标识符
github项目
pip下载
pip install tinui
结语
现在你可以将TinUI运用到你自己的tkinter项目了,甚至可以将TinUI最为窗口的唯一部件。你也可以再次基础上开发现代化的Text部件。
我开通了我自己的个人博客,欢迎访问。
🔆tkinter创新🔆