tkinter绘制组件(41)——菜单按钮

tkinter绘制组件(41)——菜单按钮

  • 引言
  • 布局
    • 函数结构
    • 按钮部分
    • 菜单显示
    • 完整代码函数
  • 效果
    • 测试代码
    • 最终效果
  • github项目
  • pip下载
  • 结语

引言

TinUI5的新控件,菜单按钮,menubutton

这是一个与TinUI菜单(menubar)相关联的控件,可以当作按钮(button2)放置在窗口的任意位置。只需要单击就可以展开菜单。

在TinUI中,菜单按钮有两种展开方式,由参数side=x/y决定,稍后会详细说明。当然,两种对齐方式在超出显示屏时,均会做出调整,以便全部可见。

我才知道,在WinUI3里,像菜单、选择器、浮窗这些脱离窗口的控件,叫“浮出控件(ContextFlyout)”。不过在tkinter里无法实现,原理决定了。


布局

函数结构

def add_menubutton(self,pos:tuple,text:str,side='y',fg='#1b1b1b',bg='#fbfbfb',line='#CCCCCC',linew=1,activefg='#5d5d5d',activebg='#f5f5f5',activeline='#e5e5e5',font=('微软雅黑',12),cont=(('command',print),'-'),tran='#01FF11'):#绘制按钮展开菜单
'''
此段略过,样式是从button2挪过来的,cont是menubar的
side - 展开方向。y在下方展开,x在右侧展开
'''

按钮部分

说实话,menubar就是一个“缝合怪”,TinUI样式部分就是button2。

但是情况有变,为了给menubar提供新的样式,button2也在事件绑定等方面做出了调整,不过在这里体现不大,可以直接照抄。

        def in_button(event):self.itemconfig(outline,outline=activeline,fill=activeline)self.itemconfig(uid+'button',fill=activefg)def out_button(event):self.itemconfig(back,fill=bg,outline=bg)self.itemconfig(outline,outline=line,fill=line)self.itemconfig(uid+'button',fill=fg)def on_click(event):self.itemconfig(back,fill=activebg,outline=activebg)self.itemconfig(uid+'button',fill=activefg)self.after(500,lambda : out_button(None))show(event)#从menu那偷过来的    ...def disable(fg='#9d9d9d',bg='#f5f5f5'):self.itemconfig(uid+'button',state='disable',fill=fg)self.itemconfig(back,state='disable',disabledfill=bg)self.itemconfig(outline,state='disable')def active():self.itemconfig(uid+'button',state='normal')self.itemconfig(back,state='normal')self.itemconfig(outline,state='normal')out_button(None)button=self.create_text(pos,text=text,fill=fg,font=font,anchor='nw')uid='menubutton'+str(button)self.itemconfig(button,tags=(uid,uid+'button'))x1,y1,x2,y2=self.bbox(uid)if side=='y':self.create_text((x2+5,(y1+y2)/2),text='\uE70D',fill=fg,font='{Segoe Fluent Icons} 12',anchor='w',tags=(uid,uid+'button'))elif side=='x':self.create_text((x2+5,(y1+y2)/2),text='\uE76C',fill=fg,font='{Segoe Fluent Icons} 12',anchor='w',tags=(uid,uid+'button'))...#创建菜单menu=self.add_menubar(uid,'<Button-1>',font=font,fg=fg,bg=bg,line=line,activefg=activefg,activebg=activebg,cont=cont,tran=tran)[0]self.tag_unbind(uid,'<Button-1>')#重新绑定事件...

引用自己很久以前写的代码,但现在应该写不出来的……

按钮主体代码不是重点。

在创建完uid后,有对于side的判断。这里是严格的判断,只接受小写字母x和y,默认为y。

然后是菜单部分(menu=...),没错,这次不仅是抄,而且干脆直接调用。不过需要注意,因为菜单在创建的时候会自动绑定参数给的事件,因此我们需要对这个事件(<Button-1>)解绑。

菜单显示

然后才是重点。注意到on_click函数的最后一行,有show(event),就代表我们需要重写菜单的显示方式,为什么呢?因为,我们需要菜单像滚动选择框(picker)那样在按钮周边展开,要么下方,要么在右侧。

那么问题来了,TinUI的控件是函数式创建,如何重写菜单的显示方式呢?

很简单,直接在menubar的第一个返回值,menu窗口添加一个属性wind,记录窗口数据。

反正我是TinUI开发者,内部代码想怎么改就怎么改,毕竟这个属性又不用提供该使用TinUI的人。

menu修改代码见最新TinUI库。

通过在picker里的积累,在元素周围展现浮出窗口并不难。只是需要浅浅地判断一下side的方向就行了。

        def unshow(event):#重写菜单menu.withdraw()menu.unbind('<FocusOut>')def show(event):#显示的起始位置#初始位置maxx,maxy,winw,winh=menu.wind.datasx,sy=event.x_root,event.y_root#maxx,maxy,winw,winh=menu.wind.databbox=self.bbox(uid)scx,scy=event.x_root,event.y_root#屏幕坐标if side=='y':dx,dy=round(self.canvasx(event.x,)-bbox[0]),round(self.canvasy(event.y)-bbox[3])#画布坐标差值elif side=='x':dx,dy=round(self.canvasx(event.x,)-bbox[2]),round(self.canvasy(event.y)-bbox[1])#画布坐标差值sx,sy=scx-dx,scy-dy#...

完整代码函数

    def add_menubutton(self,pos:tuple,text:str,side='y',fg='#1b1b1b',bg='#fbfbfb',line='#CCCCCC',linew=1,activefg='#5d5d5d',activebg='#f5f5f5',activeline='#e5e5e5',font=('微软雅黑',12),cont=(('command',print),'-'),tran='#01FF11'):#绘制按钮展开菜单#Segoe Fluent Icons x右侧展开\uE76B \uE76C,y下方展开\uE70D \uE70E,默认ydef in_button(event):self.itemconfig(outline,outline=activeline,fill=activeline)self.itemconfig(uid+'button',fill=activefg)def out_button(event):self.itemconfig(back,fill=bg,outline=bg)self.itemconfig(outline,outline=line,fill=line)self.itemconfig(uid+'button',fill=fg)def on_click(event):self.itemconfig(back,fill=activebg,outline=activebg)self.itemconfig(uid+'button',fill=activefg)self.after(500,lambda : out_button(None))show(event)#从menu那偷过来的def unshow(event):#重写菜单menu.withdraw()menu.unbind('<FocusOut>')def show(event):#显示的起始位置#初始位置maxx,maxy,winw,winh=menu.wind.datasx,sy=event.x_root,event.y_root#maxx,maxy,winw,winh=menu.wind.databbox=self.bbox(uid)scx,scy=event.x_root,event.y_root#屏幕坐标if side=='y':dx,dy=round(self.canvasx(event.x,)-bbox[0]),round(self.canvasy(event.y)-bbox[3])#画布坐标差值elif side=='x':dx,dy=round(self.canvasx(event.x,)-bbox[2]),round(self.canvasy(event.y)-bbox[1])#画布坐标差值sx,sy=scx-dx,scy-dy#if sx+winw>maxx:x=sx-winwelse:x=sxif sy+winh>maxy:y=sy-winhelse:y=symenu.geometry(f'{winw+15}x{winh+15}+{x}+{y}')menu.attributes('-alpha',0)menu.deiconify()menu.focus_set()for i in [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]:menu.attributes('-alpha',i)menu.update()time.sleep(0.05)menu.bind('<FocusOut>',unshow)def disable(fg='#9d9d9d',bg='#f5f5f5'):self.itemconfig(uid+'button',state='disable',fill=fg)self.itemconfig(back,state='disable',disabledfill=bg)self.itemconfig(outline,state='disable')def active():self.itemconfig(uid+'button',state='normal')self.itemconfig(back,state='normal')self.itemconfig(outline,state='normal')out_button(None)button=self.create_text(pos,text=text,fill=fg,font=font,anchor='nw')uid='menubutton'+str(button)self.itemconfig(button,tags=(uid,uid+'button'))x1,y1,x2,y2=self.bbox(uid)if side=='y':self.create_text((x2+5,(y1+y2)/2),text='\uE70D',fill=fg,font='{Segoe Fluent Icons} 12',anchor='w',tags=(uid,uid+'button'))elif side=='x':self.create_text((x2+5,(y1+y2)/2),text='\uE76C',fill=fg,font='{Segoe Fluent Icons} 12',anchor='w',tags=(uid,uid+'button'))x1,y1,x2,y2=self.bbox(uid+'button')linew-=1outline_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)#创建菜单menu=self.add_menubar(uid,'<Button-1>',font=font,fg=fg,bg=bg,line=line,activefg=activefg,activebg=activebg,cont=cont,tran=tran)[0]self.tag_unbind(uid,'<Button-1>')#重新绑定事件self.tag_bind(uid+'button','<Button-1>',on_click)self.tag_bind(uid+'button','<Enter>',in_button)self.tag_bind(uid+'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.tag_bind(outline,'<Button-1>',on_click)self.tag_bind(outline,'<Enter>',in_button)self.tag_bind(outline,'<Leave>',out_button)self.tkraise(uid+'button')funcs=FuncList(2)funcs.disable=disablefuncs.active=activereturn uid+'button',back,outline,funcs,uid

效果

测试代码

b.add_menubutton((1500,50),'menubutton',cont=(('command',print),('menu',test1),'-',('TinUI文本移动',test)))

最终效果

在这里插入图片描述


github项目

TinUI的github项目地址

pip下载

pip install tinui

结语

后续,menubutton或许会和menubar混合联用。

🔆tkinter创新🔆

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法之双指针系列1

目录 一&#xff1a;双指针的介绍 1&#xff1a;快慢指针 2&#xff1a;对撞指针 二&#xff1a;对撞指针例题讲述 一&#xff1a;双指针的介绍 在做题中常用两种指针&#xff0c;分别为对撞指针与快慢指针。 1&#xff1a;快慢指针 简称为龟兔赛跑算法&#xff0c;它的基…

上海泗博HART转ModbusTCP网关HME-635应用案例之组态王和超声波液位计通信

如今工业现场的应用也逐渐把现场的不同应用协议转换成以太网&#xff0c;以此来提升现场的通信速度和质量。Modbus TCP是工业以太网协议的一种&#xff0c;也是现场应用中最常使用的。本应用案例是基于Modbus TCP的组态王和基于HART的超声波液位计之间数据通讯的具体应用。 应用…

STM32F407 CAN参数配置 500Kbps

本篇CAN参数适用 芯片型号&#xff1a;STM32F407xx系统时钟&#xff1a;168MHz&#xff0c;CAN挂载总线APB1为42M波 特 率 &#xff1a;500Kpbs引脚使用&#xff1a;TX_PB9&#xff0c;RX_PB8&#xff1b;修改为PA11PA12后&#xff0c;参数不变。 步骤一、打勾开启CAN&#xf…

vector类的模拟实现

实现基本的vector框架 参考的是STL的一些源码&#xff0c;实现的vector也是看起来像是一个简略版的&#xff0c;但是看完能对vector这个类一些接口函数更好的认识。 我们写写成员变量&#xff0c;先来看看STL的成元变量是那些 namespace tjl {template<class T>class …

无损音乐下载,最新音乐下载,mp3格式音乐下载,一键下载mp3格式音乐,我只用这个软件,歌曲资源丰富,全网音乐免费下载,稳定运行,告别收费

一、软件简介 现在很多支持一键下载mp3音乐/无损音质音乐的音乐播放器通常都是解析接口套了一个壳&#xff0c;一旦解析接口失效&#xff0c;软件就不能下载音乐了&#xff0c;因此一个稳定的解析接口是这类软件最大的保障。本次小编推荐的音乐下载软件接口非常稳定&#xff0…

C语言:函数

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; 一、函数的概念 数学中我们见过函数的概念&#xff0c;例如ykxb&#xff0c;k和b都是常数&#xff0c;给任意一个x就可以得到y 而C语言也引入了函数&#xff08;function&#xff09;这个概念&#xff0c;C语…

利用LLM大模型生成sql的深入应用探究

Chat2DB 是一款有开源免费的多数据库客户端工具,和传统的数据库客户端软件Navicat、DBeaver 相比 Chat2DB 集成了 AIGC 的能力&#xff0c;能够将自然语言转换为 SQL&#xff0c;也可以将 SQL 转换为自然语言&#xff0c;可以给出研发人员 SQL 的优化建议&#xff0c;极大地提升…

初识C语言·预处理详解

目录 1 预定义符号 2 define定义常量 3 #define定义宏 4 带有副作用的宏 5 宏替换的规则 6 宏和函数的对比 7 # 和 ## i) #运算符 ii) ##运算符 8 命名约定 9 命令行定义 10 条件编译 条件编译1&#xff1a; 条件编译2&#xff1a; 条件编译3&#xff1a; 条件…

单片机学习笔记---LED点阵屏的工作原理

目录 LED点阵屏分类 LED点阵屏显示原理 74HC595的介绍 一片74HC595的工作原理 多片级联工作原理 总结 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种公共场合&#xff0c;如汽…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之ScrollBar组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之ScrollBar组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、ScrollBar组件 鸿蒙&#xff08;HarmonyOS&#xff09;滚动条组件ScrollBar&…

Logback - 日志框架

引言 在当今的企业级应用开发中&#xff0c;日志管理是一个不可或缺的部分。它不仅帮助我们进行错误跟踪&#xff0c;还能有效监控应用程序的运行状态&#xff0c;为性能优化提供数据支撑。Spring Boot作为一个简化Spring应用开发的框架&#xff0c;自带了强大的日志管理功能。…

如何用python进行数据分析?

前言 很多人可能会有这样的疑问&#xff0c;数据分析Excel挺强大的&#xff0c;会Excel就行&#xff0c;为什么还要去学python&#xff1f; 是的&#xff0c;Excel和python对于数据分析而言&#xff0c;这两者都只是不同的工具而已。 但&#xff0c;有一点我们要考虑&#x…

iOS 需求 多语言(国际化)App开发 源码

一直觉得自己写的不是技术&#xff0c;而是情怀&#xff0c;一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的&#xff0c;希望我的这条路能让你们少走弯路&#xff0c;希望我能帮你们抹去知识的蒙尘&#xff0c;希望我能帮你们理清知识的脉络&#xff0…

路由器、路由器的构成、交换结构

目录 1 路由器 1.1 路由器的结构 “转发”和“路由选择”的区别 1.1.1 输入端口对线路上收到的分组的处理 1.1.2 输出端口将交换结构传送来的分组发送到线路 2.2 交换结构 2.2.1 通过存储器 2.2.2 通过总线 2.2.3 通过纵横交换结构 (crossbar switch fabric) 1 路由器…

BUGKU-WEB 留言板

题目描述 题目无需登录后台&#xff01;需要xss平台接收flag&#xff0c; http协议需要http协议的xss平台打开场景后界面如下&#xff1a; 解题思路 看到此类的题目&#xff0c;应该和存储型xss有关&#xff0c;也就是将恶意代码保存到服务器端即然在服务器端&#xff0c;那就…

CSS 闪电按钮效果

<template><view class="const"><div class="voltage-button"><button>闪电按钮</button><svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox=&q…

简易计算器的制作(函数指针数组的实践)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a; 我要学编程(ಥ_ಥ)-CSDN博客 前期思路&#xff08;菜单的制作等&#xff09;&#xff1a;利用C语言的分支循环少量的函数知识写一个猜数字的小游戏-CSDN博客 计算器的制作其实与游…

使用ChatGpt和文心一言辅助文章创作

近期在写数字水浒系列文章&#xff0c;使用了ChatGpt和文心一言进行辅助创作&#xff0c;整体感受不错&#xff0c;提高了工作效率。 在使用过程中&#xff0c;感觉文心的中文能力更强一些&#xff0c;主要体现在&#xff1a; 1 语料库更大&#xff0c;比如对水浒传了解的更多…

Postman(接口测试工具),什么是Postman接口

目录 一.基本介绍 Postman 是什么Postman 快速入门快速入门需求说明 二.Postman 完成 Controller 层测试 需要的代码&#xff1a; Java类request.jspsuccess.jsp1. 完成请求2. 完成请求3. 完成请求4. 完成请求5. 完成请求 三.发送join 目录 一.基本介绍 Postman 是什么 …

微信小程序解决华为手机保存图片到相册失败

1.新增隐私设置 2.优化代码 新增uni.authorize判断 _saveCode() {let that this;console.log(点击了保存图片)console.log(this.result)uni.authorize({scope: scope.writePhotosAlbum,success(e) {console.log(e)if (this.result ! "") {uni.saveImageToPhotosAlb…