tkinter绘制组件(45)——导航栏

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)

添加和删除

这里只说添加和删除一个导航标题。

其实需要注意的只有两点:

  1. 最后的导航标题不可交互。添加后,倒数第二个标题需要响应交互事件;删除后,最后一个标题取消交互;
  2. 由于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项目

TinUI的github项目地址

pip下载

bash 复制代码
pip install tinui