tkinter绘制组件(31)——支点标题
- 引言
- 布局
- 函数结构
- 标题标签
- 布局框架
- 绑定事件
- 默认选值
- 完整代码函数
- 效果
- 测试代码
- 最终效果
- 2026-10-30新样式
- github项目
- pip下载
- 结语
引言
看到这四个字——支点标题,是不是很疑惑?
其实……我写下来的时候也挺疑惑的。
这个名称(pivot)取自winui的Pivot控件,中文就是支点的意思。在winui中pivot类似于标题栏,可以让使用者决定现在要看哪一个标题对应的窗口或者内容。
当然,在TinUI中,支点标题仅仅是标题,类似于单选组控件,提高编写者对于窗口切换代码编写的高自由度。除此之外,TinUI中的支点标题可以同时横向与纵向布局,也是类似于单选组控件。虽然pivot和radiobox有很多相似之处,但是对于使用者来说则是两个完全不同的交互控件。
布局
函数结构
defadd_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 '''标题标签
标题标签指的是content参数中,每个常规元素的第二个元素,这样标题被点击时返回的不是标题名称,而是这个标签,这里叫做tag。
布局框架
之前我们创建了单选组控件(radiobox),这里的布局逻辑与其相似,不清楚的可以翻回那一篇文章看看。
texts=[]#[(text,tag,text-uid),...]count=-1select=-1#当前选定t_bbox=Nonenowx,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))foriincontent:count+=1#计数ifi=='':ift_bbox==None:#没有底部坐标数据nowy+=padyelse:nowy=t_bbox[3]+pady nowx=pos[0]texts.append(('\n','\n',None))continue#...这里面的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,'<Enter>',lambdaevent,num=count,tag=text:button_in(num,tag))self.tag_bind(text,'<Leave>',lambdaevent,num=count,tag=text:button_out(num,tag))self.tag_bind(text,'<Button-1>',lambdaevent,num=count,tag=text,tagname=i[1]:sel_it(num,tag,tagname))绑定事件
上文中已经可以看到标题绑定了三种事件,三种事件的处理如下:
defbutton_in(num,text_uid):ifnum!=select:self.itemconfig(text_uid,fill=activefg)defbutton_out(num,text_uid):ifnum!=select:self.itemconfig(text_uid,fill=fg)defsel_it(num,text_uid,tag):nonlocalselectifnum==select:returnself.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))ifcommand!=None:command(tag)注意的有两点:
sel_it中,先恢复之前选定标题,载重新设置当前选中select别忘了提示线移动(重绘)
默认选值
因为这个是标题内容,因此不能向单选组控件一样有空值。
在结尾加上一段代码。
sel_it(0,texts[0][2],texts[0][1])完整代码函数
defadd_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):#绘制支点标题defbutton_in(num,text_uid):ifnum!=select:self.itemconfig(text_uid,fill=activefg)defbutton_out(num,text_uid):ifnum!=select:self.itemconfig(text_uid,fill=fg)defsel_it(num,text_uid,tag):nonlocalselectifnum==select:returnself.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))ifcommand!=None:command(tag)texts=[]#[(text,tag,text-uid),...]count=-1select=-1#当前选定t_bbox=Nonenowx,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))foriincontent:count+=1#计数ifi=='':ift_bbox==None:#没有底部坐标数据nowy+=padyelse:nowy=t_bbox[3]+pady nowx=pos[0]texts.append(('\n','\n',None))continuetext=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,'<Enter>',lambdaevent,num=count,tag=text:button_in(num,tag))self.tag_bind(text,'<Leave>',lambdaevent,num=count,tag=text:button_out(num,tag))self.tag_bind(text,'<Button-1>',lambdaevent,num=count,tag=text,tagname=i[1]:sel_it(num,tag,tagname))sel_it(0,texts[0][2],texts[0][1])returntexts,uid效果
测试代码
#...b.add_pivot((1200,300),command=test10)#...最终效果
2026-10-30新样式
添加点击响应颜色;添加提示线过渡动画。
github项目
TinUI的github项目地址
pip下载
pipinstalltinui结语
自我感觉,这个比tkinter原生的标题框好看多了。
🔆tkinter创新🔆