• tkinter绘制组件(31)——支点标题


    引言

    看到这四个字——支点标题,是不是很疑惑?

    其实……我写下来的时候也挺疑惑的。

    这个名称(pivot)取自winui的Pivot控件,中文就是支点的意思。在winui中pivot类似于标题栏,可以让使用者决定现在要看哪一个标题对应的窗口或者内容。

    当然,在TinUI中,支点标题仅仅是标题,类似于单选组控件,提高编写者对于窗口切换代码编写的高自由度。除此之外,TinUI中的支点标题可以同时横向与纵向布局,也是类似于单选组控件。虽然pivot和radiobox有很多相似之处,但是对于使用者来说则是两个完全不同的交互控件。


    布局

    函数结构

        def add_pivot(self,pos:tuple,fg='#959595',bg='',activefg='#525252',activecolor='#5969e0',content=(('a-title','tag1'),('b-title','tag2'),'',('c-title','tag3')),font='微软雅黑 16',padx=10,pady=10,command=None):#绘制支点标题
        '''
        pos::位置
        fg::字体颜色
        bg::创建时的保留参数
        activefg::激活时字体颜色
        activecolor::提示色
        content::内容,空字符串代表下一行
        font::字体
        padx::横向间距
        pady::纵向间距
        command::响应函数,必须接受一个参数,所选标题的tag
        '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    标题标签

    标题标签指的是content参数中,每个常规元素的第二个元素,这样标题被点击时返回的不是标题名称,而是这个标签,这里叫做tag

    布局框架

    之前我们创建了单选组控件(radiobox),这里的布局逻辑与其相似,不清楚的可以翻回那一篇文章看看。

            texts=[]#[(text,tag,text-uid),...]
            count=-1
            select=-1#当前选定
            t_bbox=None
            nowx,nowy=pos#x坐标为左上角插入坐标,y坐标为底部坐标
            uid='pivot'+str(id(content))
            line=self.create_line((pos[0],pos[1],pos[0]+5,pos[1]),fill=activecolor,width=3,capstyle='round',tags=(uid))
            for i in content:
                count+=1#计数
                if i=='':
                    if t_bbox==None:#没有底部坐标数据
                        nowy+=pady
                    else:
                        nowy=t_bbox[3]+pady
                    nowx=pos[0]
                    texts.append(('\n','\n',None))
                    continue    
                #...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这里面的line是随意位置创建的,这个元素是标题提示线。

    for循环中,省略的部分就是常规标题创建,代码如下:

                text=self.create_text((nowx,nowy),font=font,text=i[0],fill=fg,anchor='nw',tags=(uid))
                t_bbox=self.bbox(text)
                width=t_bbox[2]-t_bbox[0]
                nowx=nowx+width+padx
                texts.append((i[0],i[1],text))
                self.tag_bind(text,'',lambda event,num=count,tag=text:button_in(num,tag))
                self.tag_bind(text,'',lambda event,num=count,tag=text:button_out(num,tag))
                self.tag_bind(text,'',lambda event,num=count,tag=text,tagname=i[1]:sel_it(num,tag,tagname))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    绑定事件

    上文中已经可以看到标题绑定了三种事件,三种事件的处理如下:

            def button_in(num,text_uid):
                if num!=select:
                    self.itemconfig(text_uid,fill=activefg)
            def button_out(num,text_uid):
                if num!=select:
                    self.itemconfig(text_uid,fill=fg)
            def sel_it(num,text_uid,tag):
                nonlocal select
                if num==select:
                    return
                self.itemconfig(texts[select][2],fill=fg)
                select=num
                self.itemconfig(text_uid,fill=activefg)
                bbox=self.bbox(text_uid)
                self.coords(line,(bbox[0],bbox[3]+2,bbox[2],bbox[3]+2))
                if command!=None:
                    command(tag)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意的有两点:

    1. sel_it中,先恢复之前选定标题,载重新设置当前选中select

    2. 别忘了提示线移动(重绘)

    默认选值

    因为这个是标题内容,因此不能向单选组控件一样有空值。

    在结尾加上一段代码。

            sel_it(0,texts[0][2],texts[0][1])
    
    • 1

    完整代码函数

        def add_pivot(self,pos:tuple,fg='#959595',bg='',activefg='#525252',activecolor='#5969e0',content=(('a-title','tag1'),('b-title','tag2'),'',('c-title','tag3')),font='微软雅黑 16',padx=10,pady=10,command=None):#绘制支点标题
            def button_in(num,text_uid):
                if num!=select:
                    self.itemconfig(text_uid,fill=activefg)
            def button_out(num,text_uid):
                if num!=select:
                    self.itemconfig(text_uid,fill=fg)
            def sel_it(num,text_uid,tag):
                nonlocal select
                if num==select:
                    return
                self.itemconfig(texts[select][2],fill=fg)
                select=num
                self.itemconfig(text_uid,fill=activefg)
                bbox=self.bbox(text_uid)
                self.coords(line,(bbox[0],bbox[3]+2,bbox[2],bbox[3]+2))
                if command!=None:
                    command(tag)
            texts=[]#[(text,tag,text-uid),...]
            count=-1
            select=-1#当前选定
            t_bbox=None
            nowx,nowy=pos#x坐标为左上角插入坐标,y坐标为底部坐标
            uid='pivot'+str(id(content))
            line=self.create_line((pos[0],pos[1],pos[0]+5,pos[1]),fill=activecolor,width=3,capstyle='round',tags=(uid))
            for i in content:
                count+=1#计数
                if i=='':
                    if t_bbox==None:#没有底部坐标数据
                        nowy+=pady
                    else:
                        nowy=t_bbox[3]+pady
                    nowx=pos[0]
                    texts.append(('\n','\n',None))
                    continue
                text=self.create_text((nowx,nowy),font=font,text=i[0],fill=fg,anchor='nw',tags=(uid))
                t_bbox=self.bbox(text)
                width=t_bbox[2]-t_bbox[0]
                nowx=nowx+width+padx
                texts.append((i[0],i[1],text))
                self.tag_bind(text,'',lambda event,num=count,tag=text:button_in(num,tag))
                self.tag_bind(text,'',lambda event,num=count,tag=text:button_out(num,tag))
                self.tag_bind(text,'',lambda event,num=count,tag=text,tagname=i[1]:sel_it(num,tag,tagname))
            sel_it(0,texts[0][2],texts[0][1])
            return texts,uid
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    效果

    测试代码

        #...
        b.add_pivot((1200,300),command=test10)    
        #...
    
    • 1
    • 2
    • 3

    最终效果

    在这里插入图片描述


    github项目

    TinUI的github项目地址

    pip下载

    pip install tinui
    
    • 1

    结语

    自我感觉,这个比tkinter原生的标题框好看多了。

    🔆tkinter创新🔆

  • 相关阅读:
    java返给前端ECharts的格式
    Calibreweb安装
    Ruby使用类组织对象
    Java包,继承
    1.QML Hello world
    LeetCode - Easy - 746. Min Cost Climbing Stairs
    市面上北方水稻居多 国稻种芯:南方盛产水稻去哪里了?
    1.0零基础尝试DCM通讯(c-store)
    中级C++:map和set的迷你实现
    【质量工具】使用ls-lint在 vue3,react 等项目中规范命名
  • 原文地址:https://blog.csdn.net/tinga_kilin/article/details/125800311