tkinter绘制组件(32)——圆角按钮

本文介绍如何使用Tkinter创建圆角按钮,包括按钮的布局、逻辑代码、边框与圆角实现细节,并展示了完整的代码示例及效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

容我解释一下,这个圆角按钮(button2)之所以是新控件,而不是原理按钮元素的新样式,主要是有以下几个原因。

  1. 我觉得按钮(button)元素的方形样式还可以,没有一些人说的那么栏

  2. 样式风格差异较大,不适合作为元素样式升级

  3. 与其他爱好者达成妥协。。。

虽然TinUI圆角按钮的诞生有一点点争议,但是一个好消息是,逻辑代码几乎和button一样。所以我就可以抄写借鉴一番。

😏没办法,我是TinUI所有权全权拥有者,也是目前唯一一个TinUI知识产权所有者(TinUI内容100%)。


布局

函数结构

    def add_button2(self,pos:tuple,text:str,fg='#1b1b1b',bg='#fbfbfb',line='#CCCCCC',linew=1,activefg='#5d5d5d',activebg='#f5f5f5',activeline='#e5e5e5',font=('微软雅黑',12),command=None,anchor='nw'):#绘制圆角按钮
    '''
    pos::位置
    text::文本
    fg::文本颜色
    bg::背景颜色
    line::边框颜色
    linew::边框宽度
    activefg::响应时文本颜色
    activebg::响应时背景颜色
    activeline::响应时边框颜色
    font::字体
    command::目标函数,需要接受一个event参数,command(*event)
    anchor::位置点对齐方向
    '''

按钮元素

因为这次样式大改,但主要是样式代码,逻辑代码小小地修改一下就可以了。

先绘制文本,获取其占位空间:

        button=self.create_text(pos,text=text,fill=fg,font=font,anchor=anchor)
        uid='button2-'+str(button)
        self.itemconfig(button,tags=uid)
        x1,y1,x2,y2=self.bbox(button)

边框与圆角

这里,我们使用tkinter画布的polygon元素绘制圆角背景。

注意到我们有边框参数。对于tkinter画布而言,有宽度的元素,一般是边框向两边均延伸。所以说,当我们设置宽度为9时,实际上是向两边延伸了4.5个单位。那么我们的外边框和内边框的宽度查为2,则两者之间自带宽度差为1。

因此,linew要减去一个单位。

        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)

内背景要后于外背景绘制,减少覆盖样式代码。

逻辑代码

这段部分与button几乎一致,看一下就行了。

        def in_button(event):
            self.itemconfig(outline,outline=activeline,fill=activeline)
            self.itemconfig(button,fill=activefg)
        def out_button(event):
            self.itemconfig(back,fill=bg,outline=bg)
            self.itemconfig(outline,outline=line,fill=line)
            self.itemconfig(button,fill=fg)
        def on_click(event):
            self.itemconfig(back,fill=activebg,outline=activebg)
            self.itemconfig(button,fill=activefg)
            self.after(500,lambda : out_button(None))
            if command!=None:
                command(event)    
        #...
        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)

完整代码函数

    def add_button2(self,pos:tuple,text:str,fg='#1b1b1b',bg='#fbfbfb',line='#CCCCCC',linew=1,activefg='#5d5d5d',activebg='#f5f5f5',activeline='#e5e5e5',font=('微软雅黑',12),command=None,anchor='nw'):#绘制圆角按钮
        def in_button(event):
            self.itemconfig(outline,outline=activeline,fill=activeline)
            self.itemconfig(button,fill=activefg)
        def out_button(event):
            self.itemconfig(back,fill=bg,outline=bg)
            self.itemconfig(outline,outline=line,fill=line)
            self.itemconfig(button,fill=fg)
        def on_click(event):
            self.itemconfig(back,fill=activebg,outline=activebg)
            self.itemconfig(button,fill=activefg)
            self.after(500,lambda : out_button(None))
            if command!=None:
                command(event)
        def change_command(new_func):
            nonlocal command
            command=new_func
        def disable(fg='#9d9d9d',bg='#f5f5f5'):
            self.itemconfig(button,state='disable',fill=fg)
            self.itemconfig(back,state='disable',disabledfill=bg)
        def active():
            self.itemconfig(button,state='normal')
            self.itemconfig(back,state='normal')
            out_button(None)
        button=self.create_text(pos,text=text,fill=fg,font=font,anchor=anchor)
        uid='button2-'+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
        return button,back,line,funcs,uid

效果

测试代码

if __name__=='__main__':
    #...
    b.add_button2((1200,180),text='圆角按钮')
    #...

最终效果

在这里插入图片描述

2024-7-7新参数

可指定最小宽度和最大宽度,下图为限制最小宽度minwidth=200
在这里插入图片描述

2024-7-31新参数

本来,button2就像是button的进化版,这次终于迎来了除了样式之外的区别,也是特点,那就是增加了对Segoe Fluent Icons符号的支持。

目前并没有打算给button加上,感受下我精准的刀法。

新增参数icon,使用Unicode编码字符,如\uE79E
参数compound,确定符号相对于文本的位置,值应在'left','right','top','bottom'中。

在这里插入图片描述

2025-2-2新参数

在这里插入图片描述
添加过渡颜色,即鼠标进入和鼠标点击显示两种配色。我也不知道为什么现在才加上来😂
在这里插入图片描述

2025-6-9新样式

在这里插入图片描述

button2改为鼠标松开后执行回调函数,样式恢复逻辑改为鼠标松开

2025-8-16更新

button2延申为accentbuttontoolbutton,用法完全一样,但是在TinUITheme中是单独的。
在这里插入图片描述


github项目

TinUI的github项目地址

pip下载

pip install tinui

结语

大家觉得这个圆角按钮(button2)和方形按钮(button)怎么样呢?

此外,还有一个就是关于TinUI的暂停维护时间段。因为作者学业原因,有一段时间将暂停维护TinUI。

TinUI网站

🔆tkinter创新🔆

### 实现鼠标绘制圆形功能 为了实现鼠标绘制圆形的功能,可以通过监听鼠标事件并结合图形界面库完成此操作。以下是具体说明以及示例代码。 #### 1. 鼠标事件的处理 在图形界面开发中,通常会使用 `MouseDown` 和 `MouseUp` 等事件来捕获用户的输入行为。当用户按下鼠标时记录起始位置,在释放鼠标时计算结束位置,并以此为基础绘制一个圆[^1]。 #### 2. 圆形绘制逻辑 绘制圆形的核心在于确定圆心坐标 `(cx, cy)` 及半径 `r` 的大小。假设起点为 `(x1, y1)`,终点为 `(x2, y2)`,则可以按照以下方式定义: - 圆心:`(cx, cy) = ((x1 + x2)/2, (y1 + y2)/2)` - 半径:`r = sqrt((x2-x1)^2 + (y2-y1)^2) / 2` 随后调用绘图接口完成实际渲染过程。 --- ### 示例代码 以下是一个基于 PythonTkinter 库实现鼠标绘制圆形的例子: ```python import tkinter as tk def start_drawing(event): global start_x, start_y start_x, start_y = event.x, event.y # 记录初始点击位置 def stop_drawing(event): end_x, end_y = event.x, event.y # 获取最终拖动位置 cx = (start_x + end_x) / 2 # 计算圆心横坐标 cy = (start_y + end_y) / 2 # 计算圆心纵坐标 r = max(abs(end_x - start_x), abs(end_y - start_y)) / 2 # 计算半径 canvas.create_oval(cx-r, cy-r, cx+r, cy+r, outline="blue", width=2) root = tk.Tk() canvas = tk.Canvas(root, width=400, height=400) canvas.pack() # 绑定鼠标事件 canvas.bind("<ButtonPress-1>", start_drawing) # 按下左键 canvas.bind("<ButtonRelease-1>", stop_drawing) # 松开左键 root.mainloop() ``` 上述代码实现了如下功能: - 当用户按住鼠标左键时,记录当前指针的位置; - 用户松开鼠标左键后,根据起始点和终止点计算出圆心与半径,并绘制对应的圆。 --- #### 关于事件驱动编程模式 本案例体现了典型事件驱动编程的思想——通过注册回调函数响应特定类型的用户交互(如鼠标按键)。这种方式允许开发者构建灵活的应用程序框架,而无需显式控制每一步流程[^2]。 #### Arduino 中的相关应用 如果目标平台切换至嵌入式领域,则可借助 Arduino 结合触摸屏或 LCD 显示模块达成相似效果。例如,LVGL 图形库支持创建自定义 UI 控件,包括带圆角样式的按钮组件[^3]。不过需要注意的是,由于资源受限,这类方案往往需要额外优化性能表现。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值