当前位置: 首页 > article >正文

tkinter绘制组件(44)——浮出ui控件

tkinter绘制组件(44)——浮出ui控件

  • 引言
  • 布局
    • 函数结构
    • ui框架
    • 对齐方向
    • 绑定已有控件
    • 出现和隐藏逻辑
    • 出现和隐藏动画
    • 完整代码函数
  • 效果
    • 测试代码
    • 最终效果
  • github项目
  • pip下载

引言

TinUI的浮出ui控件(flyout)其实是一个之间创建在UI框架内的完整BasicTinUI类,且已经绑定了TinUIXml。该控件并不之间占有窗口句柄,因此可以大量创建,包括但不限于:

  1. 弹出已有控件的说明
  2. 绑定已有控件,弹出某个操作、用法的说明
  3. 绑定已有控件,弹出简单的内部对话框或说明

从上面罗列的使用场景可以看出,flyout就是用来作为窗口内提示与简单交互的,只不过是一个轻量的UI框架,和TinUI的内嵌ui控件(ui)非常类似,只不过绑定在了已有的控件。


布局

函数结构

def add_flyout(self, fid, width:int=250, height:int=150, bind='<Button-1>', line='#dcdcdc', bg='#f9f9f9', anchor='n'):# 绘制一个浮出ui控件
    # 注意,默认布局在fid正上方
    """
    fid::绑定控件的uid
    width::宽度
    height::高度
    bind::绑定的事件
    line::边框颜色
    bg::背景颜色
    anchor::展开方向
    """

ui框架

上文说过,flyout本质就是一个BasicTinUI。

ui = BasicTinUI(self, bg=bg, highlightbackground=line, highlightthickness=1, relief='flat')
uixml = TinUIXml(ui)

对齐方向

由于是弹出控件,因此flyout的anchor不再代表控件本身的对齐方向,而是指布局在绑定控件的那一侧。比如n就代表正上方,nw代表左上方。

bbox = self.bbox(fid)
if anchor == 'nw':
    x = bbox[0] - 4
    y = bbox[1] - 4
    _anchor = 'se'
    dxy = (1, 1)
elif anchor == 'n':
    x = (bbox[0] + bbox[2]) / 2
    y = bbox[1] - 4
    _anchor ='s'
    dxy = (0, 1)
elif anchor == 'ne':
    x = bbox[2] + 4
    y = bbox[1] - 4
    _anchor = 'sw'
    dxy = (1, 1)
elif anchor == 'e':
    x = bbox[2] + 4
    y = (bbox[1] + bbox[3]) / 2
    _anchor = 'w'
    dxy = (1, 0)
elif anchor =='se':
    x = bbox[2] + 4
    y = bbox[3] + 4
    _anchor = 'nw'
    dxy = (1, 1)
elif anchor =='s':
    x = (bbox[0] + bbox[2]) / 2
    y = bbox[3] + 4
    _anchor = 'n'
    dxy = (0, 1)
elif anchor =='sw':
    x = bbox[0] - 4
    y = bbox[3] + 4
    _anchor = 'ne'
    dxy = (1, 1)
elif anchor == 'w':
    x = bbox[0] - 4
    y = (bbox[1] + bbox[3]) / 2
    _anchor = 'e'
    dxy = (1, 0)
else:# 默认为center
    x = (bbox[0] + bbox[2]) / 2
    y = (bbox[1] + bbox[3]) / 2
    _anchor = 'center'
    dxy = (1, 1)
uid = self.create_window(x, y, width=width, height=height, window=ui, anchor=_anchor)

dxy稍后解释

绑定已有控件

self.itemconfig(uid, state='hidden')
self.tag_bind(fid, bind, show)

出现和隐藏逻辑

出现逻辑很显然,就是对于绑定控件的绑定事件,默认就是左键单击。

对于隐藏逻辑,我能够想到的就是左键单击本UI框架,这样做可以减少对其他不确定元素的依赖,且BasicTinUI本身不对单击做出响应,也不应该对单击做出响应(窗口单击获得焦点是系统层决定,这不影响)。单击本UI框架收回flyout是比较合理的。

def show(e):
    self.tag_unbind(fid, bind)# 避免接下来绑定self <button-1>事件时同步触发
    self.itemconfig(uid, state='normal')
    motion(None, 1)
    self.after(100, go_to_bind)# 避免直接触发控件点击事件
def go_to_bind():
    self.bind('<Button-1>', hide)
def hide(e):
    self.unbind('<Button-1>')
    self.tag_bind(fid, bind, show)
    motion(None, -1)
    self.itemconfig(uid, state='hidden')

注意上面代码片段中的两个注释内容,简单来说就是避免绑定控件左键单击和本UI框架左键单击同时触发,导致showhide调用混乱。

出现和隐藏动画

这就涉及到前文提到的dxy,且内容就是x和y方向,需要变化的为1,不需要变化的为0。

此外,motion函数的dis参数为1表示展开,-1表示收缩。

def motion(e, dis):
    # 展开/收缩动画
    # dxy为动画方向,0为不变,1为变化
    if dis == 1:
        # 展开
        _width = width * (1-dxy[0])
        _height = height * (1-dxy[1])
        dwidth = width / 10 * dxy[0]
        dheight = height / 10 * dxy[1]
    else:
        # 收缩
        _width = width
        _height = height
        dwidth = -width / 10 * dxy[0]
        dheight = -height / 10 * dxy[1]
    for _ in range(10):
        time.sleep(0.01)
        _width += dwidth
        _height += dheight
        self.itemconfig(uid, width=_width, height=_height)
        self.update_idletasks()

完整代码函数

def add_flyout(self, fid, width:int=250, height:int=150, bind='<Button-1>', line='#dcdcdc', bg='#f9f9f9', anchor='n'):# 绘制一个浮出ui控件
    # 注意,默认布局在fid正上方
    def show(e):
        self.tag_unbind(fid, bind)# 避免接下来绑定self <button-1>事件时同步触发
        self.itemconfig(uid, state='normal')
        motion(None, 1)
        self.after(100, go_to_bind)# 避免直接触发控件点击事件
    def go_to_bind():
        self.bind('<Button-1>', hide)
    def hide(e):
        self.unbind('<Button-1>')
        self.tag_bind(fid, bind, show)
        motion(None, -1)
        self.itemconfig(uid, state='hidden')
    def motion(e, dis):
        # 展开/收缩动画
        # dxy为动画方向,0为不变,1为变化
        if dis == 1:
            # 展开
            _width = width * (1-dxy[0])
            _height = height * (1-dxy[1])
            dwidth = width / 10 * dxy[0]
            dheight = height / 10 * dxy[1]
        else:
            # 收缩
            _width = width
            _height = height
            dwidth = -width / 10 * dxy[0]
            dheight = -height / 10 * dxy[1]
        for _ in range(10):
            time.sleep(0.01)
            _width += dwidth
            _height += dheight
            self.itemconfig(uid, width=_width, height=_height)
            self.update_idletasks()
    ui = BasicTinUI(self, bg=bg, highlightbackground=line, highlightthickness=1, relief='flat')
    uixml = TinUIXml(ui)
    # 围绕fid进行布局
    bbox = self.bbox(fid)
    if anchor == 'nw':
        x = bbox[0] - 4
        y = bbox[1] - 4
        _anchor = 'se'
        dxy = (1, 1)
    elif anchor == 'n':
        x = (bbox[0] + bbox[2]) / 2
        y = bbox[1] - 4
        _anchor ='s'
        dxy = (0, 1)
    elif anchor == 'ne':
        x = bbox[2] + 4
        y = bbox[1] - 4
        _anchor = 'sw'
        dxy = (1, 1)
    elif anchor == 'e':
        x = bbox[2] + 4
        y = (bbox[1] + bbox[3]) / 2
        _anchor = 'w'
        dxy = (1, 0)
    elif anchor =='se':
        x = bbox[2] + 4
        y = bbox[3] + 4
        _anchor = 'nw'
        dxy = (1, 1)
    elif anchor =='s':
        x = (bbox[0] + bbox[2]) / 2
        y = bbox[3] + 4
        _anchor = 'n'
        dxy = (0, 1)
    elif anchor =='sw':
        x = bbox[0] - 4
        y = bbox[3] + 4
        _anchor = 'ne'
        dxy = (1, 1)
    elif anchor == 'w':
        x = bbox[0] - 4
        y = (bbox[1] + bbox[3]) / 2
        _anchor = 'e'
        dxy = (1, 0)
    else:# 默认为center
        x = (bbox[0] + bbox[2]) / 2
        y = (bbox[1] + bbox[3]) / 2
        _anchor = 'center'
        dxy = (1, 1)
    uid = self.create_window(x, y, width=width, height=height, window=ui, anchor=_anchor)
    self.itemconfig(uid, state='hidden')
    self.tag_bind(fid, bind, show)
    return ui, uixml, hide, uid

效果

测试代码

flylabel = b.add_label((1500,500),text='点击展开浮出UI')[-1]
_, flyxml, flyhide, _ = b.add_flyout(flylabel)
flyxml.funcs['flyhide']=flyhide
flyxml.loadxml('''<tinui><line><paragraph text='浮出UI'></paragraph></line>
               <line><paragraph text='add_flyout(fid, anchor="...")'></paragraph></line>
               <line><paragraph text='使用hide关闭'></paragraph></line>
<line><button2 text='关闭浮出UI控件' command="self.funcs['flyhide']"></button2>
</line></tinui>''')

最终效果

在这里插入图片描述


github项目

TinUI的github项目地址

pip下载

pip install tinui

🔆tkinter创新🔆


http://www.kler.cn/a/517942.html

相关文章:

  • 83,【7】BUUCTF WEB [MRCTF2020]你传你[特殊字符]呢
  • 想品客老师的第七天:闭包和作用域
  • 【开源免费】基于Vue和SpringBoot的医院资源管理系统(附论文)
  • 奖励模型:解析大语言模型的关键工具
  • Zookeeper(28)Zookeeper的线性化写入和顺序一致性读是什么?
  • 【MySQL】我在广州学Mysql 系列——MySQL用户管理详解
  • css-background-color(transparent)
  • 【玩转全栈】----Django基本配置和介绍
  • LeetCode题练习与总结:分糖果--575
  • 算法刷题Day27:BM65 最长公共子序列(二)
  • SpringCloud两种注册中心
  • 代码随想录刷题day14(2)|(链表篇)02.07. 链表相交(疑点)
  • 《网络安全中的“泛洪”攻击:揭秘、防范与应对策略》
  • TIM编码器接口函数及应用
  • 环境变量配置与问题解决
  • Gin 学习笔记
  • JAVA实战开源项目:在线旅游网站(Vue+SpringBoot) 附源码
  • 【Linux跬步积累】——thread封装
  • 使用Pytest Fixtures来提升TestCase的可读性、高效性
  • Java 实现Excel转HTML、或HTML转Excel
  • 「 机器人 」系统辨识实验浅谈
  • 如何有效进行软件集成测试?常见的集成测试工具分享
  • 工程数学速记手册(下)
  • 汽车免拆诊断案例 | 2007 款日产天籁车起步加速时偶尔抖动
  • 前端react后端java实现提交antd form表单成功即导出压缩包
  • LMI Gocator GO_SDK VS2019引用配置