tkinter绘制组件(45)------导航栏
引言
《汉赛尔和格莱特》吗?有点意思,面包屑。
TinUI中的breadcurmb
期望操作如下:
- 最后一层不可点击;
- 根目录永远存在;
- 返回列表为文本元素的画布id,由编写者自行转为文本。
布局
函数结构
python
def add_breadcrumb(self,pos:tuple,font='微软雅黑 12',fg='#000000',bg='#ffffff',activefg='#5c5c5c',root='HOME',command=None,anchor='nw'):
"""
pos::位置
fg::文本颜色
bg::背景色
activefg::响应鼠标文本颜色
root::根目录文本
command::回调函数,接收层级文本元素列表
anchor::整体对齐方向
"""
导航栏目
导航栏目很简单,就是一堆导航标题文本,中间使用右箭头文本隔开,只有非最后标题文本可以交互。栈嘛,直接用collections
里的deque
就行,当然,为了方便,右箭头元素也用另一个栈存储。
初始化只需要一个根目录和背景即可。
python
root = self.create_text(pos, text=root, font=font, fill=fg, anchor='w')
font_size = self.__get_text_size(root)
segeo_font = '{Segoe Fluent Icons}' + font_size
uid = 'breadcrumb' + str(root)
uid_button = uid + 'button'
self.itemconfig(root, tags=(uid,uid_button))
bbox = self.bbox(root)
back = self.__ui_polygon(((bbox[0]+2,bbox[1]+2),(bbox[2]-2,bbox[3]-2)),fill=bg,outline=bg,width=9,tags=uid)
self.tkraise(root)
stack = collections.deque()
stack.append(root)
symstack = collections.deque()
_, dy = self.__auto_anchor(uid, pos, anchor)
endx = self.bbox(root)[2]
center_line = pos[1] + dy
处理鼠标信号
这个控件的交互很简单,只有鼠标进出和左键单击:
python
def click(cid):
if command == None:
return
res = []
for i in stack:
res.append(i)
if i == cid:
break
command(res)
def in_button(cid):
self.itemconfig(cid, fill=activefg)
def out_button(cid):
self.itemconfig(cid, fill=fg)
添加和删除
这里只说添加和删除一个导航标题。
其实需要注意的只有两点:
- 最后的导航标题不可交互。添加后,倒数第二个标题需要响应交互事件;删除后,最后一个标题取消交互;
- 由于
breadcrumb
长度经常变换,因此每次操作后均需要进行对齐。
python
def add(text):
# 添加一个路径元素
nonlocal endx
sym = self.create_text((endx+2,center_line), text='\uE76C', font=segeo_font, fill=fg, anchor='w', tags=(uid,uid_button))
symstack.append(sym)
endx = self.bbox(sym)[2]
t = self.create_text((endx+2,center_line), text=text, font=font, fill=fg, anchor='w', tags=(uid,uid_button))
lt = stack[-1]
stack.append(t)
bbox = self.bbox(uid_button)
self.coords(back, (bbox[0]+2,bbox[1]+2,bbox[2]-2,bbox[1]+2,bbox[2]-2,bbox[3]-2,bbox[0]+2,bbox[3]-2))
self.__auto_anchor(uid,pos,anchor)
endx = self.bbox(t)[2]
self.tag_bind(lt, '<Button-1>', lambda e: click(lt))
self.tag_bind(lt, '<Enter>', lambda e: in_button(lt))
self.tag_bind(lt, '<Leave>', lambda e: out_button(lt))
return t
def delete():
# 删除最后一个路径元素
nonlocal endx
if stack.__len__() > 1:
self.delete(stack.pop())
self.delete(symstack.pop())
bbox = self.bbox(uid_button)
self.coords(back, (bbox[0]+2,bbox[1]+2,bbox[2]-2,bbox[1]+2,bbox[2]-2,bbox[3]-2,bbox[0]+2,bbox[3]-2))
self.__auto_anchor(uid,pos,anchor)
lt = stack[-1]
endx = self.bbox(lt)[2]
self.tag_unbind(lt, '<Button-1>')
self.tag_unbind(lt, '<Enter>')
self.tag_unbind(lt, '<Leave>')
完整代码函数
python
def add_breadcrumb(self,pos:tuple,font='微软雅黑 12',fg='#000000',bg='#ffffff',activefg='#5c5c5c',root='HOME',command=None,anchor='nw'):
# 绘制面包屑导航组件
def click(cid):
if command == None:
return
res = []
for i in stack:
res.append(i)
if i == cid:
break
command(res)
def in_button(cid):
self.itemconfig(cid, fill=activefg)
def out_button(cid):
self.itemconfig(cid, fill=fg)
def get():
# 获取当前路径元素
return list(stack)
def add(text):
# 添加一个路径元素
nonlocal endx
sym = self.create_text((endx+2,center_line), text='\uE76C', font=segeo_font, fill=fg, anchor='w', tags=(uid,uid_button))
symstack.append(sym)
endx = self.bbox(sym)[2]
t = self.create_text((endx+2,center_line), text=text, font=font, fill=fg, anchor='w', tags=(uid,uid_button))
lt = stack[-1]
stack.append(t)
bbox = self.bbox(uid_button)
self.coords(back, (bbox[0]+2,bbox[1]+2,bbox[2]-2,bbox[1]+2,bbox[2]-2,bbox[3]-2,bbox[0]+2,bbox[3]-2))
self.__auto_anchor(uid,pos,anchor)
endx = self.bbox(t)[2]
self.tag_bind(lt, '<Button-1>', lambda e: click(lt))
self.tag_bind(lt, '<Enter>', lambda e: in_button(lt))
self.tag_bind(lt, '<Leave>', lambda e: out_button(lt))
return t
def delete():
# 删除最后一个路径元素
nonlocal endx
if stack.__len__() > 1:
self.delete(stack.pop())
self.delete(symstack.pop())
bbox = self.bbox(uid_button)
self.coords(back, (bbox[0]+2,bbox[1]+2,bbox[2]-2,bbox[1]+2,bbox[2]-2,bbox[3]-2,bbox[0]+2,bbox[3]-2))
self.__auto_anchor(uid,pos,anchor)
lt = stack[-1]
endx = self.bbox(lt)[2]
self.tag_unbind(lt, '<Button-1>')
self.tag_unbind(lt, '<Enter>')
self.tag_unbind(lt, '<Leave>')
def delete_to(cid):
nonlocal endx
while stack.__len__() > 1 and stack[-1] != cid:
self.delete(stack.pop())
self.delete(symstack.pop())
bbox = self.bbox(uid_button)
self.coords(back, (bbox[0]+2,bbox[1]+2,bbox[2]-2,bbox[1]+2,bbox[2]-2,bbox[3]-2,bbox[0]+2,bbox[3]-2))
self.__auto_anchor(uid,pos,anchor)
lt = stack[-1]
endx = self.bbox(lt)[2]
self.tag_unbind(lt, '<Button-1>')
self.tag_unbind(lt, '<Enter>')
self.tag_unbind(lt, '<Leave>')
root = self.create_text(pos, text=root, font=font, fill=fg, anchor='w')
font_size = self.__get_text_size(root)
segeo_font = '{Segoe Fluent Icons}' + font_size
uid = 'breadcrumb' + str(root)
uid_button = uid + 'button'
self.itemconfig(root, tags=(uid,uid_button))
bbox = self.bbox(root)
back = self.__ui_polygon(((bbox[0]+2,bbox[1]+2),(bbox[2]-2,bbox[3]-2)),fill=bg,outline=bg,width=9,tags=uid)
self.tkraise(root)
stack = collections.deque()
stack.append(root)
symstack = collections.deque()
_, dy = self.__auto_anchor(uid, pos, anchor)
endx = self.bbox(root)[2]
center_line = pos[1] + dy
funcs = FuncList(4)
funcs.get = get
funcs.add = add
funcs.delete = delete
funcs.delete_to = delete_to
return root, back, funcs, uid
效果
测试代码
python
bc = b.add_breadcrumb((1500,350),anchor='n',command=print)[-2]
for i in range(1,4):
bc.add(f'item{i}')
最终效果

github项目
pip下载
bash
pip install tinui