引言

进度条在程序界面中有特殊的作用,它往往使用在处理耗时操作时,告诉用户目前程序进行的程度到哪。当然,一般的进度条是无法明确告诉用户具体的进度的,因为谁也没有办法第一时间确定处理进度,这样才会发生“卡死在99%”的“尴尬去处”。

不过,TinUI也要绘制进度条,一个能够让编写者明确设定进度的进度条,甚至能够实现进度条回退。那么,现在开工。


构思

为了实现进度条,我们需要解决以下问题:

  1. 能够明确设定0~100之间的整数
  2. 可以在进度条上显示我们想要显示的文本
  3. 能够通过自编函数实现进度条的动画

其中,第一和第二个功能是滚动条本身需要具备的,第三个功能是要通过创建滚动条返回的接口方法实现的。


布局

函数结构

def add_progressbar(self,pos:tuple,width=250,fg='#3B3B3B',bg='#63ADE5',percentage=True,text=''):#绘制进度条
    '''
    pos::位置
    width::宽度
    fg::文本和边框颜色
    bg::进度条颜色
    percentage::bool值,如果为True,则文本自动显示当前百分比;如果为False,则显示text内容
    text::当percentage为False时,显示的自定的文本
    '''

创建边框与进度条

不同于之前的组件绘制,因为进度条的主体是进度条本身,而不是在上面显示的文字,因此这次我们将先创建背景边框和进度条,再通过边框的位置绘制文本。

bbox=(pos[0],pos[1],pos[0]+width,pos[1]+15)
back=self.create_rectangle((bbox),outline=fg)#边框
progressbar=self.create_rectangle((pos[0],pos[1],pos[0],pos[1]+15),outline=bg,fill=bg)#进度条

绘制文字

因为TinUI的进度条文本显示提供两种方法,一种是显示进度,另一种是显示自定义文字。所以,我们需要根据参数percentage来确定绘制哪一种文字。但无论是哪一种,都需要返回进度条显示文本。

#是否显示默认文本
if percentage==True:
    text=self.create_text((pos[0]+width//2,pos[1]),anchor='n',text='0%',fill=fg,font='微软雅黑 10')
else:
    text=self.create_text((pos[0]+width//2,pos[1]),anchor='n',text=text,fill=fg,font='微软雅黑 10')

设定进度

在TinUI的进度条中,我们需要一个可以设定进度的操作函数,并且该函数只能允许一个参数,就是进度。

这个参数应该能够表示为x∈[0,100]∩N

 def goto(num:int):
    if not 0<=num<=100:
        return
    #...

Python中,int即整数型,接下来的数值判断即可完成参数范围判定。

借鉴之前绘制waitbar1waitbar2combobox等组件的经验,我们可以通过函数itemconfig来设定progressbar的样式。

但是,这有一个棘手的问题,那就是这的进度条需要改变的样式是长度,也就是矩形覆盖范围,但是覆盖范围(bbox)并不在画布对象属性设置中。那么,我们该如何改变progressbar的长度呢?

方法也不是没有,但是得曲线救国。

我们可以放弃改变单个画布对象的样式,因为这是不可行的。干脆,每次更新进度,我们就重新绘制进度条。具体做法如下:

  1. 删除现有进度条
  2. 通过进度设定重新绘制新的进度条
  3. 将新的进度条绑定为特定的tag标志

那么,如何动态更新进度条,就需要用到tag这个标志来绑定我们的进度条矩形了。为了防止出现全捆绑现象,我们会将边框的ID也加入到标志名称中。

def goto(num:int):
    if not 0<=num<=100:
        return
    pw=width*num//100
    self.delete(pro_tagname)
    new_progressbar=self.create_rectangle((pos[0],pos[1],pos[0]+pw,pos[1]+15),fill=bg,outline=bg)
    self.lower(new_progressbar)
    #将标志名称绑定到新进度条
    self.addtag_withtag(pro_tagname,new_progressbar)
    #是否更新默认文字
    if percentage==True:
        self.itemconfig(text,text=str(num)+'%')
    self.update()
#...
#生成唯一tag标识
pro_tagname='progressbar>'+str(back)
self.addtag_withtag(progressbar,pro_tagname)
#...

到此,我们完成了在TinUI中绘制进度条的工作

完整代码函数

def add_progressbar(self,pos:tuple,width=250,fg='#3B3B3B',bg='#63ADE5',percentage=True,text=''):#绘制进度条
    def goto(num:int):
        if not 0<=num<=100:
            return
        pw=width*num//100
        self.delete(pro_tagname)
        new_progressbar=self.create_rectangle((pos[0],pos[1],pos[0]+pw,pos[1]+15),fill=bg,outline=bg)
        self.lower(new_progressbar)
        self.addtag_withtag(pro_tagname,new_progressbar)
        if percentage==True:
            self.itemconfig(text,text=str(num)+'%')
        self.update()
    bbox=(pos[0],pos[1],pos[0]+width,pos[1]+15)
    back=self.create_rectangle((bbox),outline=fg)
    progressbar=self.create_rectangle((pos[0],pos[1],pos[0],pos[1]+15),outline=bg,fill=bg)
    pro_tagname='progressbar>'+str(back)
    self.addtag_withtag(progressbar,pro_tagname)
    #是否显示默认文本
    if percentage==True:
        text=self.create_text((pos[0]+width//2,pos[1]),anchor='n',text='0%',fill=fg,font='微软雅黑 10')
    else:
        text=self.create_text((pos[0]+width//2,pos[1]),anchor='n',text=text,fill=fg,font='微软雅黑 10')
    return back,pro_tagname,text,goto

效果

测试代码

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)

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/')
    _,ok1=b.add_waitbar1((500,220),bg='lightgreen')
    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),fg='blue')
    b.add_combobox((600,550),text='中考成绩预测',content=('730','740','750','760','770','780'))
    b.add_button((600,480),text='测试进度条(无事件版本)',command=test4)
    _,_,_,progressgoto=b.add_progressbar((600,510))

    a.mainloop()

函数test4就是实现进度条在指定范围、以指定速度、运转到指定进度的一个动态例子。

最终效果

在这里插入图片描述


2021-8-22新样式

在这里插入图片描述

2022-1-22新样式

在这里插入图片描述


github项目

TinUI的github项目地址

pip下载

pip install tinui

结语

TinUI现在能够绘制等待框和进度条等动态样式组件,但是具体使用需要配合多线程和多进程来使用。因为tkinter自身的限制,当after使用多了以后,界面也是会卡住的。

🔆tkinter创新🔆

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐