引言
当你要处理一定的耗时任务时,一定不希望tkinter界面卡住,而是希望使用者能够知道程序现在需要用户等待片刻。在tkinter中,有进度条组件,但是很难进行实际应用。因为很多时候我们没办法预测进度,因此我们只能够让使用者等待。
这时,可以考虑使用一个组件来显示等待动画,让使用者明白现在可以去做别的事,让程序先完成一定量的工作。
因此,我们会在TinUI加入等待动画组件。
布局
函数结构
目前,TinUI使用以下函数绘制圆形等待框:
def add_waitbar1(self,pos:tuple,fg='blue',bg='',okfg='lightgreen',okbg='',bd=2,r=20):#绘制圆形等待组件
'''
pos::位置
fg::边框颜色
bg::内部颜色
okfg::完成时边框颜色
okbg::完成时内部颜色
bd::边框宽度
r::半径
'''
pass
画布内容
我们需要创建一个可以改变角度的扇形画布对象,那么就是用create_arc函数。
bbox=(pos[0],pos[1],pos[0]+2*r,pos[1]+2*r)
waitbar1=self.create_arc(bbox,outline=fg,fill=bg,extent=5,start=90,width=bd)
注意,在创建画布内容时,半径与起始位置之间的关系。create_arc通过指定矩形范围来绘制图像,因此需要将选定的矩形范围调整为刚好绘制一个“圆”的大小。
动画样式
因为我们使用的是圆形等待组件,那么基本动画就是让这个圆弧转一圈,然后再重头来过。
首先,因为tkinter本身不支持多线程,干脆我们直接使用after函数解决调用时差问题。通过获取指定的扇形角度,设定相应的时间来执行绘制函数。当绘制函数的绘制角度最大时,在重新开启定时函数。很明显,我们需要两个函数。
def __init__(...):
#...
self.waitbar1_list=[i for i in range(0,360,5)]
#...
def add_waitbar1(self,pos:tuple,fg='blue',bg='',okfg='lightgreen',okbg='',bd=2,r=20):#绘制圆形等待组件
def __start(i):#绘制函数
self.itemconfig(waitbar1,extent=i)
if i==355:
start()
def start():#定时函数
for i in self.waitbar1_list:
self.after(i*15,lambda i=i:__start(i))
#...
然后,将start
函数加入创建完图像后的代码中。
结束函数
我们没必要让一个等待组件一直转下去,当我们完成我们的既定任务时,可以让其停下(删掉也可以)。那么,我们在创建一个停止等待函数,并将其作为对象函数回传,供之后调用。
def ok():
self.itemconfig(waitbar1,outline=okfg,fill=okbg,extent=359)
之所以将“extent”参数使用359而不是360,是因为圆周角时,arc不会展现我们想要的效果
之后呢?定时函数和绘制函数怎么知道结束没有。这时,我们需要一个结构体,通过改变布朗值告诉定时函数和绘制函数,本组件的工作结束了。
先定义结构体(好吧,只要是自定义属性就可以):
class TinUINum:#数据结构,请忽略
pass
再将一个数据结构写入函数中:
def add_waitbar1(self,pos:tuple,fg='blue',bg='',okfg='lightgreen',okbg='',bd=2,r=20):#绘制圆形等待组件
def __start(i):#绘制函数
if ifok.re==True:
return
#...
def start():#定时函数
if ifok.re==True:
return
#...
#...
ifok=TinUINum
ifok.re=False
#...
完整代码函数
def add_waitbar1(self,pos:tuple,fg='blue',bg='',okfg='lightgreen',okbg='',bd=2,r=20):#绘制圆形等待组件
def __start(i):
if ifok.re==True:
return
self.itemconfig(waitbar1,extent=i)
if i==355:
start()
def start():
if ifok.re==True:
return
for i in self.waitbar1_list:
self.after(i*10,lambda i=i:__start(i))
def ok():
ifok.re=True
self.itemconfig(waitbar1,outline=okfg,fill=okbg,extent=359)
ifok=TinUINum
ifok.re=False
bbox=(pos[0],pos[1],pos[0]+2*r,pos[1]+2*r)
waitbar1=self.create_arc(bbox,outline=fg,fill=bg,extent=5,start=90,width
start()
return waitbar1,ok
效果
测试代码
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()
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,30,'这里用来输入')
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/')
waitbar1,ok1=b.add_waitbar1((500,220),bg='lightgreen')
b.add_button((500,270),'停止等待动画',activefg='blue',activebg='black',command=test2)
a.mainloop()
最终效果
2021-7-30新样式
2022-7-11新样式
更具动态感。
github项目
pip下载
pip install tinui
结语
TinUI仍然在探索绘制组件的动画,使界面更加生动。
🔆tkinter创新🔆