tkinter绘制组件(38)——状态开关按钮

news2024/10/6 10:37:58

tkinter绘制组件(38)——状态开关按钮

  • 引言
  • 布局
    • 函数结构
    • 按钮主体
    • 渐变色处理
      • 颜色处理基础
      • 渐变色列表
      • 形成列表
    • 样式绑定
    • 完整函数代码
  • 效果
    • 测试代码
    • 最终效果
  • github项目
  • pip下载
  • 结语

引言

TinUI里的状态开关按钮(togglebutton)和开关(onoff)一样,都是用来显示并操作两种对立状态的交互控件。在很多UI库中,这两个控件均由按钮派生出来。开关类控件提供了即时状态改变响应的接口,开关控件多用于设置界面,状态开关按钮则多用于应用运行中的状态更改。


布局

函数结构

    def add_togglebutton(self,pos:tuple,text:str,fg='#1b1b1b',bg='#fbfbfb',line='#CCCCCC',linew=1,activefg='#f3f4fd',activebg='#3041d8',activeline='#5360de',font=('微软雅黑',12),command=None,anchor='nw'):#绘制状态开关按钮
    '''
- pos::位置
- text::文本
- fg::文本颜色
- bg::背景色
- line::边框颜色
- linew::边框宽度
- activefg::开启状态文本颜色
- activebg::开启状态背景色
- activeline::开启状态边框颜色
- font::字体
- command::响应函数,接受一个参数:`True`开启,`False`关闭
- anchor::对齐方向
    '''

按钮主体

参考WinUI3中的状态开关按钮,按钮的主体使用TinUI中的圆角按钮(button2),在此基础上进行功能修改:

        #...
        button=self.create_text(pos,text=text,fill=fg,font=font,anchor=anchor)
        uid='togglebutton'+str(button)
        self.itemconfig(button,tags=uid)
        x1,y1,x2,y2=self.bbox(button)
        linew-=1
        outline_t=(x1-linew,y1-linew,x2+linew,y1-linew,x2+linew,y2+linew,x1-linew,y2+linew)
        outline=self.create_polygon(outline_t,width=9,tags=uid,fill=line,outline=line)
        back_t=(x1,y1,x2,y1,x2,y2,x1,y2)
        back=self.create_polygon(back_t,width=7,tags=uid,fill=bg,outline=bg)
        self.tag_bind(button,'<Button-1>',on_click)
        #self.tag_bind(button,'<Enter>',in_button)
        #self.tag_bind(button,'<Leave>',out_button)
        self.tag_bind(back,'<Button-1>',on_click)
        #self.tag_bind(back,'<Enter>',in_button)
        #self.tag_bind(back,'<Leave>',out_button)
        self.tkraise(button)
        funcs=FuncList(3)
        funcs.change_command=change_command
        funcs.disable=disable
        funcs.active=active    
        #...

整个绘制过程基本copy了button2的代码,但是除了一些小修改以外,就是去除了对于鼠标进出的响应过程(被注释掉的代码)。为了避免添加过多参数,同时方便编写者管理按钮样式,将激活时的颜色作为状态开启的提示色。

渐变色处理

这是togglebutton创建的一个重点,也是唯一值得讲一讲的。

TinUI中使用渐变色作为togglebutton的过渡动画。因为这一段代码是我突发兴致决定的,所以肯定由比较繁琐的地方,往后或许会修改,也希望指正。

颜色处理基础

渐变色过程由十进制方式计算,而tkinter(Tcl/Tk)的颜色模式采用的是十六进制字符串,很有想法,做个微操:

        def __rgb2num(rgb):#tkinter颜色类型转十进制rgb
            return int(rgb[1:3],16),int(rgb[3:5],16),int(rgb[5:],16)
        def __num2rgb(hexs:tuple):#十进制rgb转tkinter颜色类型
            co='#'
            for i in hexs:
                co+=str(hex(i))[2:]
            return co

渐变色列表

为了不让动画过于耗时,使用两个列表存储渐变颜色(25个过渡颜色)而不是临时计算,一个列表是从关闭状态到激活状态的颜色变化,另一个就是倒序。因此,只需要写一个正序颜色列表的计算式就行了。

思路也十分清晰简单:

  1. 将始末颜色转为十进制方便计算。

  2. 分别计算RGB差值(末减初)。

  3. 循环25遍(算上初始值是26遍),每次计算颜色变化量t

具体代码如下:

        def get_color_change(st,ed):
            colors_list=[]
            #起始和终止颜色,十进制rgb
            a1,a2,a3=__rgb2num(st)
            b1,b2,b3=__rgb2num(ed)
            #两颜色差值
            r,g,b=(b1-a1),(b2-a2),(b3-a3)
            for i in range(26):
                t=i/25
                rgb=(int(a1 + r * t), int(a2 + g * t), int(a3 + b * t))
                colors_list.append(__num2rgb(rgb))
            return colors_list

其中的r,g,b是颜色差值,t=i/25就是在计算颜色变化量,也就是渐变到哪一步的指示。通过[r|g|b] * t就可以得到这一步颜色的具体变化值。

之后可能把这个渐变色列表生成方法作为TinUI的通用函数,具体看其它控件使用需要。

形成列表

这一步就简单了。

        #...
        #处理渐变色
        colors.append(get_color_change(fg,activefg))#文本颜色
        colors.append(get_color_change(bg,activebg))#背景颜色
        #re_colors 反向颜色列表
        re_colors=[colors[0][::-1],colors[1][::-1]]
        nowcolors=colors

样式绑定

这里要注意,我们之前只是创建了渐变颜色列表而已,动画部分还没完成。

因为控件的不同状态对应的渐变顺序不一样,因此每当按钮状态改变时要重新指定动画颜色列表,这个操作放在on_click中执行。

        def on_click(event):
            nonlocal state
            if state==False:
                state=True
                self.itemconfig(outline,fill=activeline,outline=activeline)
                change_color(0,2)
            else:
                state=False
                self.itemconfig(outline,fill=line,outline=line)
                change_color(0,1)
            if command!=None:
                command(state)

里面提到的change_color就是变化颜色函数,通过tkinter计时器进行函数循环,间隔时间是0.005秒,完成后改变指向的颜色列表。

        def change_color(t,change:int):#变化颜色
            #change:: 1=>colors, 2=>re_colors
            nonlocal nowcolors
            if t<=25:
                self.itemconfig(back,fill=nowcolors[1][t],outline=nowcolors[1][t])
                self.itemconfig(button,fill=nowcolors[0][t])
                self.after(5,lambda : change_color(t+1,change))
            else:
                if change==1:
                    nowcolors=colors
                elif change==2:
                    nowcolors=re_colors

完整函数代码

    def add_togglebutton(self,pos:tuple,text:str,fg='#1b1b1b',bg='#fbfbfb',line='#CCCCCC',linew=1,activefg='#f3f4fd',activebg='#3041d8',activeline='#5360de',font=('微软雅黑',12),command=None,anchor='nw'):#绘制状态开关按钮
        def in_button(event):
            pass
        #状态开关按钮当前不再对鼠标进入和离开进行响应
        def out_button(event):
            pass
        def on_click(event):
            nonlocal state
            if state==False:
                state=True
                self.itemconfig(outline,fill=activeline,outline=activeline)
                change_color(0,2)
            else:
                state=False
                self.itemconfig(outline,fill=line,outline=line)
                change_color(0,1)
            if command!=None:
                command(state)
        def change_color(t,change:int):#变化颜色
            #change:: 1=>colors, 2=>re_colors
            nonlocal nowcolors
            if t<=25:
                self.itemconfig(back,fill=nowcolors[1][t],outline=nowcolors[1][t])
                self.itemconfig(button,fill=nowcolors[0][t])
                self.after(5,lambda : change_color(t+1,change))
            else:
                if change==1:
                    nowcolors=colors
                elif change==2:
                    nowcolors=re_colors
        def change_command(new_func):
            nonlocal command
            command=new_func
        def disable(fg='#9d9d9d',bg='#f5f5f5'):
            if state==False:#区分当前状态进行禁用配色
                self.itemconfig(button,state='disable',fill=fg)
                self.itemconfig(back,state='disable',disabledfill=bg)
            else:
                self.itemconfig(button,state='disable',fill=bg)
                self.itemconfig(back,state='disable',disabledfill=fg)
        def active():
            self.itemconfig(button,state='normal')
            self.itemconfig(back,state='normal')
            out_button(None)
        def __rgb2num(rgb):#tkinter颜色类型转十进制rgb
            return int(rgb[1:3],16),int(rgb[3:5],16),int(rgb[5:],16)
        def __num2rgb(hexs:tuple):#十进制rgb转tkinter颜色类型
            co='#'
            for i in hexs:
                co+=str(hex(i))[2:]
            return co
        def get_color_change(st,ed):
            colors_list=[]
            #起始和终止颜色,十进制rgb
            a1,a2,a3=__rgb2num(st)
            b1,b2,b3=__rgb2num(ed)
            #两颜色差值
            r,g,b=(b1-a1),(b2-a2),(b3-a3)
            for i in range(26):
                t=i/25
                rgb=(int(a1 + r * t), int(a2 + g * t), int(a3 + b * t))
                colors_list.append(__num2rgb(rgb))
            return colors_list
        state=False#off:False on:True
        colors=[]#渐变色颜色列表,25个,off->on,[[文本颜色,...],[背景色,...]]
        button=self.create_text(pos,text=text,fill=fg,font=font,anchor=anchor)
        uid='togglebutton'+str(button)
        self.itemconfig(button,tags=uid)
        x1,y1,x2,y2=self.bbox(button)
        linew-=1
        outline_t=(x1-linew,y1-linew,x2+linew,y1-linew,x2+linew,y2+linew,x1-linew,y2+linew)
        outline=self.create_polygon(outline_t,width=9,tags=uid,fill=line,outline=line)
        back_t=(x1,y1,x2,y1,x2,y2,x1,y2)
        back=self.create_polygon(back_t,width=7,tags=uid,fill=bg,outline=bg)
        self.tag_bind(button,'<Button-1>',on_click)
        #self.tag_bind(button,'<Enter>',in_button)
        #self.tag_bind(button,'<Leave>',out_button)
        self.tag_bind(back,'<Button-1>',on_click)
        #self.tag_bind(back,'<Enter>',in_button)
        #self.tag_bind(back,'<Leave>',out_button)
        self.tkraise(button)
        funcs=FuncList(3)
        funcs.change_command=change_command
        funcs.disable=disable
        funcs.active=active
        #处理渐变色
        colors.append(get_color_change(fg,activefg))#文本颜色
        colors.append(get_color_change(bg,activebg))#背景颜色
        #re_colors 反向颜色列表
        re_colors=[colors[0][::-1],colors[1][::-1]]
        nowcolors=colors
        return button,back,outline,funcs,uid

效果

测试代码

def test13(state):
    if state:
        b.itemconfig(tgbutton,text='状态开关按钮:开启')
    else:
        b.itemconfig(tgbutton,text='状态开关按钮:关闭')    

if __name__=='__main__':
    tgbutton=b.add_togglebutton((1200,230),text='状态开关按钮:关闭',command=test13)[0]

最终效果

在这里插入图片描述


github项目

TinUI的github项目地址

pip下载

pip install tinui

结语

TinUI4可能会时不时加一些莫名其妙的控件,而基础的应用功能基本不会改变,但还是会偶尔更新的。

🔆tkinter创新🔆

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/173391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DPU网络开发SDK—DPDK(五)

rte_eal_init 接上次内容继续对rte_eal_init()所做的工作进行分析。 18. 检查是否允许直接物理地址访问 rte_eal_using_phys_addrs()会去检查当前系统是否允许在进程虚拟地址空间直接访问物理地址。需要有两个支持条件&#xff1a;存在大页内存和能够进行虚拟地址到物理地址…

智云通CRM:如何把握拓客成交的三种时间?

在我们邀约、拜访及展示产品之后&#xff0c;客户就一定会成为你的客户吗&#xff1f;当然不尽然&#xff0c;这取决于众多因素。任何事情都不是一蹴而就的&#xff0c;我们不能刚到某个场合认识了一个人&#xff0c;就一定要立即成交&#xff0c;或者反过来因为对方此时没有需…

Pytorch实战笔记(2)——CNN实现情感分析

本文展示的是使用 Pytorch 构建一个 TextCNN 来实现情感分析。本文的架构是第一章详细介绍 TextCNN&#xff08;不带公式版&#xff09;&#xff0c;第二章是核心代码部分。 目录1. TextCNN2. TextCNN 实现情感分析参考1. TextCNN 相较于 LSTM 而言&#xff0c;我个人其实是没…

手把手教你学51单片机-C语言基础

二进制、十进制和十六进制 对于二进制来说,8 位二进制我们称之为一个字节。 我们在进行 C 语言编程的时候,我们只写十进制和十六进制,那么不带 0x 的就 是十进制,带了 0x 符号的就是十六进制。 C 语言变量类型和范围 C 语言的数据基本类型分为字符型、整型、长整型以及…

【算法题解】12. 删除链表中的节点

文章目录题目题解Java 代码实现Go 代码实现复杂度分析这是一道简单题&#xff0c;题目来自 leetcode 题目 给定一个单链表的 head&#xff0c;我们想删除它其中的一个节点 node。 只给你一个需要删除的节点 node 。你将 无法访问 第一个节点 head。 链表的所有值都是 唯一的&…

1.吴恩达机器学习课程笔记:多元梯度下降法

1.吴恩达机器学习课程笔记&#xff1a;多元梯度下降法 笔记来源&#xff1a;吴恩达机器学习课程笔记&#xff1a;多元梯度下降法 仅作为个人学习笔记&#xff0c;若各位大佬发现错误请指正 1.1 多元特征&#xff08;变量&#xff09; 每一列代表一个特征&#xff0c;例如&…

FMC子卡设计资料原理图:FMC550-基于ADRV9002双窄带宽带射频收发器FMC子卡

FMC550-基于ADRV9002双窄带宽带射频收发器FMC子卡一、产品概述 ADRV9002 是一款高性能、高线性度、高动态范围收发器&#xff0c;旨在针对性能与功耗系统进行优化。该设备是可配置的&#xff0c;非常适合要求苛刻、低功耗、便携式和电池供电的设备。ADRV9002 的工作频率为 …

计算机基础——无处不网络(2)

作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.计算机网络的接入方式 1

青龙脚本-稳定阅读

稳定阅读积分 查看请求头的cookie 变量 export zzbhd 多号或换行 */ 脚本附后 /* 查看请求头的cookie 变量 export zzbhd 多号或换行*/const $ new Env(至尊宝阅读); const axios require(axios); let request require("request"); request request.defaults(…

纯手工模拟Vue中的数据劫持和代理

为什么要实现数据劫持和代理 举一个场景&#xff1a;比如在小程序开发中&#xff0c;我们需要逻辑层修改的数据能同步响应更新到视图层的页面上&#xff0c;那么底层框架在实现这种效果的时候&#xff0c;机制是什么样的呢&#xff1f; 其实这里的底层原理类似于Vue中的数据劫…

基于蜣螂算法优化的BP神经网络(预测应用) - 附代码

基于蜣螂算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录基于蜣螂算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍3.蜣螂优化BP神经网络3.1 BP神经网络参数设置3.2 蜣螂算法应用4.测试结果&#xff1a;5.Matlab代码摘要&am…

ClickHouse快速复习

ClickHouse​一.特性​1.列式数据库管理系统​2.数据压缩​3.数据的磁盘存储​4.支持SQL​5.索引​6.适合在线查询​7.支持数据复制和数据完整性​8.实时的数据更新​9.处理大量短查询的吞吐量​10.处理大量短查询的吞吐量​11.限制​二.数据类型​1.数字类型​2.浮点数(float)…

前端都在聊什么 - 第 1 期

Hello 小伙伴们早上、中午、下午、晚上、深夜好&#xff0c;我是爱折腾的 jsliang~「前端都在聊什么」是 jsliang 日常写文章/做视频/搞直播过程中&#xff0c;小伙伴们的提问以及我的解疑整理。本期对应 2023 年的 01.01-01.15 这个时间段。本期针对「工作」「学习」「规划」「…

迭代器、可迭代对象、生成器的区别和联系

目录1 迭代器2 可迭代对象3 生成器1 迭代器 迭代器是一种可以更新迭代的工具&#xff0c;迭代器对象从集合的第一个元素开始访问&#xff0c;直到所有的元素被访问完结束。但是他不能像列表一样使用下标来获取数据&#xff0c;也就是说迭代器是不能返回的。迭代器只能往前不会…

Universal Links方式:私有化部署服务器来托管apple-app-site-association文件创建通用链接

Universal Links方式:私有化部署服务器来托管apple-app-site-association第一步&#xff1a;开启Associated Domains服务第二步&#xff1a;配置Associated Domains&#xff08;域名&#xff09;第三步&#xff1a;服务器配置apple-app-site-association文件第四步&#xff1a;…

java的数据类型:引用数据类型(String、数组、枚举)

2.3.3 引用数据类型 引用数据类型大致包括&#xff1a;类、 接口、 数组、 枚举、 注解、 字符串等 它和基本数据类型的最大区别就是&#xff1a; 基本数据类型是直接保存在栈中的引用数据类型在栈中保存的是一个地址引用&#xff0c;这个地址指向的是其在堆内存中的实际位置…

四旋翼无人机学习第22节--padstack editor创建过孔

1 首先打开padstack editor软件。 2、选择过孔&#xff0c;注意与前面的博客不同&#xff0c;这里的单位最好使用mil。 在小马哥的教程中&#xff0c;过孔可以分为几类&#xff0c;下面主要对下图的五种过孔进行设置。 3、接着对过孔的孔径进行设置。 4、不做修改。 5、修…

网络交换机常见故障及解决方法

在日常的网络故障维护中我们接触最多的设备就是交换机&#xff0c;特别是接入层交换机&#xff0c;它是连接用户和交换路由设备的桥梁。但是交换机设备无论性能多么好&#xff0c;都会存在潜在故障问题&#xff0c;就像人一样&#xff0c;无论多么健康&#xff0c;也总会出现一…

MindMaster思维导图及亿图图示会员 优惠活动

MindMaster思维导图及亿图图示会员 超值获取途径 会员九折优惠方法分享给大家&#xff01;如果有需要&#xff0c;可以上~ 以下是食用方法&#xff1a; MindMaster 截图 亿图图示 截图 如果需要MindMaster思维导图或者亿图图示会员&#xff0c;可按照如下操作领取超值折扣优惠…

java成员变量/局部变量2023017

成员变量/局部变量 1.定义位置不同&#xff0c;成员变量定义在类里&#xff0c;局部变量定义在类的方法里。 来自网络 2.成员变量中&#xff0c;其中类变量从该类的准备阶段起开始存在&#xff0c;直到系统完全销毁这个类&#xff0c;类变量的作用域与这个类的生存范围相同&…