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.mzph.cn/news/672724.shtml

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

相关文章

DAC调节DCDC输出电压的电路方案分析

BUCK型电源芯片的调压方式分析 1、前题 BUCK型的电源芯片非常多&#xff0c;常用的如LM2576、LM2596等等&#xff0c;这种芯片优点很多&#xff0c;比如功率大、体积小、效率高等。这种芯片一般都可以通过电阻分压的方式设定反馈脚VFB的电压来改变电源芯片的输出电压。但最近…

Ubuntu22.04切换系统cuda版本

由于最近项目要求的cuda版本有差异&#xff0c;而在Ubuntu中可以通过切换cuda来满足需求&#xff0c;现记录如下。 1、按照 Ubuntu22.04与深度学习配置 中的cuda安装章节&#xff0c;将需要的cuda版本下载到本地并进行安装。 2、cuda安装完成后修改bashrc文件内容 sudo gedit …

kmp算法板子及例题

对板子的详细解释见&#xff1a;pecco:kmp 板子 void get_pmt(const string& p) {//求pmt数组for (int i 1, j 0;i < p.size();i) {while (j && p[i] ! p[j])j pmt[j - 1];if (p[i] p[j])j;pmt[i] j;} }void kmp(const string& s, const string&…

Java之网络编程

什么是计算机网络 是指将地理位置不同的具有独立功能的计算机设备通过通信连接起来&#xff0c;在网络操作系统、网络管理软件及网络通讯协议的管理与协调下&#xff0c;实现资源共享与信息传递的计算机系统 网络通讯的两个要素 通讯双方的网络地址 1.ip 2.端口号 通过ip端…

DAY14之二叉树理论基础及递归遍历和迭代遍历

理论基础 满二叉树 满二叉树&#xff1a;如果一棵二叉树只有度为0的结点和度为2的结点&#xff0c;并且度为0的结点在同一层上&#xff0c;则这棵二叉树为满二叉树。 如图所示&#xff1a; 这棵二叉树为满二叉树&#xff0c;也可以说深度为k&#xff0c;有2^k-1个节点的二叉…

CX341A 安装驱动与刷固件

参考 驱动安装1 DPDK编译&#xff1a;支持Mellanox 25Gbps网卡 - 知乎 NVIDIA Mellanox CX网卡固件、驱动系列操作 - 知乎 驱动安装2 Mellanox网卡驱动安装指南 Mellanox OFED_崇尚匀速 追求极致的技术博客_51CTO博客 驱动与固件&#xff1a; 家用万兆网络指南 6 - 比…

深度学习入门笔记(二)神经元的结构

神经网络的基本单元是神经元&#xff0c;本节我们介绍神经元的结构。 2.1 神经元 一个神经元是由下面 5 部分组成的&#xff1a; 输入&#xff1a;x1,x2,…,xk。权重&#xff1a;w1,w2,…,wk。权重的个数与神经元输入的个数相同。偏移项&#xff1a;可省略。激活函数&#…

【已解决】onnx转换为rknn置信度大于1,图像出现乱框问题解决

前言 环境介绍&#xff1a; 1.编译环境 Ubuntu 18.04.5 LTS 2.RKNN版本 py3.8-rknn2-1.4.0 3.单板 迅为itop-3568开发板 一、现象 采用yolov5训练并将pt转换为onnx&#xff0c;再将onnx采用py3.8-rknn2-1.4.0推理转换为rknn出现置信度大于1&#xff0c;并且图像乱框问题…

MySQL之建表操作

华子目录 表操作创建表数据类型文本类型数值类型日期/时间类型Bit数据类型常见数据类型 MySQL存储引擎创建表的三个操作创建表时指定存储引擎&#xff0c;字符集&#xff0c;校对规则&#xff0c;行格式 查看表显示数据库中所有表显示数据库中表的信息&#xff08;表结构&#…

函数的连续与间断【高数笔记】

【连续】 分类&#xff0c;分几个&#xff1f;每类特点&#xff1f; 连续条件&#xff0c;是同时满足还是只需其一&#xff1f; 【间断】 分类&#xff0c;分几个大类&#xff0c;又分几个小类&#xff1f;每类特点&#xff1f; 间断条件&#xff0c;是同时满足还是只需其一&am…

芯片设计方法学之--握手

1.面向对象 本文主要介绍握手的基本概念&#xff0c;读者可通过该篇文章对握手有个基本概念。也借此机会发表下自己对流水线中的握手反压的一些愚见。更深的理解可期待后续更新&#xff1b; 2. 握手简介 举个简单例子&#xff1b; 上图中sender拉高vld发送有效的数据给recei…

44、WEB攻防——通用漏洞RCE代码执行多层面检测利用

文章目录 RCE分类&#xff1a; REC代码执行&#xff1a;引用脚本代码解析执行。例如&#xff0c;eval(phpinfo();)以php脚本解析phpinfo();。RCE命令执行&#xff1a;脚本调用操作系统命令。例如&#xff0c;system(ver)&#xff0c;命令执行能执行系统命令。 RCE漏洞对象&am…

相机图像质量研究(6)常见问题总结:光学结构对成像的影响--对焦距离

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

Linux的打包压缩与解压缩---tar、xz、zip、unzip

最近突然用到了许久不用的压缩解压缩命令&#xff0c;真的陌生&#xff0c; 哈哈&#xff0c;记录一下&#xff0c;后续就不用搜索了。 tar的打包 tar -cvf 压缩有的文件名称 需要压缩的文件或文件夹tar -cvf virtualbox.tar virtualbox/ tar -zcvf virtualbox.tar virtualbo…

家政小程序开发,重塑家政服务体验

随着科技的飞速发展&#xff0c;小程序已经成为我们日常生活中不可或缺的一部分。而家政服务作为社会生活的重要环节&#xff0c;其数字化转型也正在逐步加速。本文将探讨家政小程序开发的重要性、功能特点以及如何提升用户体验。 一、家政小程序开发的重要性 家政服务行业在…

IDEA生成可执行jar包

1. 进入需要打包的项目&#xff0c;选择 最上方菜单栏的 File → Project Structure 2. 选择 左侧菜单栏 Artifacts → 加号 → JAR → from modules with dependencies 3. 选择入口类 Main Class&#xff08;点击文件夹图标可以快速选择&#xff09;&#xff0c;点击 OK&#…

Vue3.4+element-plus2.5 + Vite 搭建教程整理

一、 Vue3Vite 项目搭建 说明&#xff1a; Vue3 最新版本已经基于Vite构建&#xff0c;关于Vite简介&#xff1a;Vite 下一代的前端工具链&#xff0c;前端开发与构建工具-CSDN博客 1.安装 并 创建Vue3 应用 npm create vuelatest 创建过程可以一路 NO 目前推荐使用 Vue R…

springboot 拦截器

定义 拦截器类似于javaweb中filter 功能 注意: 只能拦截器controller相关的请求 作用 举一个例子&#xff0c;例如我们在Controller中都有一段业务逻辑&#xff0c;这样我们就可以都统一放在拦截器中 因此拦截器的作用就是将controller中共有代码放入到拦截器中执行,减少co…

游戏开发中的残影效果

引言 游戏开发中的残影效果 大家好&#xff0c;相信大家都玩过三国战纪这款游戏&#xff0c;二十年经典街机,青春重燃! 它里面人物在爆气的时候&#xff0c;移动速度会加快&#xff0c;从而产生一种移形换影的感觉。 残影效果作为一种常见的视觉特效&#xff0c;在增强游戏…