tkinter绘制组件(10)——组合框/下拉框

  • 引言
  • 构思
    • 样式与功能(初次构想)
    • 样式与功能(二次构想)
  • 布局
    • 函数结构
    • 闭合状态下拉框
    • 选项框
    • 整合选项框
    • 展开与闭合
    • 完整代码函数
  • 效果
    • 测试代码
    • 最终效果
  • 2021-7-29新样式
  • github项目
  • pip下载
  • 结语

引言

组合框?你一个绘制类型的TinUI框架,也想通过整合其它的个体组件来创造一个复合组件?

好吧,TinUI是不会尝试绘制可以gird或pack布局的组件的(因为tkinter画布的限制)。本篇文章想要讲的组件,是combobox。

combobox是“组合框”英译名称,而在Windows操作系统中,“combobox”有下拉框、下拉列表的含义,通常作为想给出既定选项,又不希望像单选框一样占用的一定的位置而与用户交互的组件。这次,TinUI将实现该组件。

(剧透) TinUI实现combobox挺费劲的,是TinUI目前最复杂的个体组件。


构思

因为下拉框使用画布绘制比较复杂,先来想一下该如何实现下拉框。

样式与功能(初次构想)

基本与系统下拉框对齐(除不能够直接输入外),要基本实现以下部分:

  1. 初始化时有一个文本显示框和下拉提示框
  2. 文本显示框中应该有初始文字
  3. 下拉提示框响应鼠标单击动作,其文本型提示应该与下拉框的“闭合”、“展开”状态相符合
  4. 下拉提示框响应鼠标进入与离开动作
  5. 展开下拉框后,应出现只能够单选若干选项
  6. 各选项响应鼠标进入与离开动作
  7. 各选项响应鼠标单击动作,文本显示框显示选中文本,并将选中文本作为参数回调指定函数
  8. ……

额- - -,好像要求有点高,但是远不止这些。还有:各选项维持选定状态、下拉框响应焦点状态、文本显示框的动态更新……

先不管了,一个组件的绘制要求不能这么严格,应该从基础开始,我们就先实现这些功能……

但,还是好复杂啊…(⊙_⊙;)…(引出下文)

样式与功能(二次构想)

我认为,因为TinUI已经有了一定的规模,我们应该尝试运用以往的经验和技巧来简化下拉框的绘制。这样,才能够让之前的只是运用到我们现在要解决的问题。

combobox的整体结构我们是改不了的,但是下拉提示框可以使用add_button替代,并且实例化其中的按钮文本和按钮背景。

下拉框的响应动作还是得自己写。

展开状态的选项列表可用借鉴add_radiobutton的相关代码。

以下,就是绘制下拉框的新(简)版方法:

  1. 文本显示框和按钮
  2. 单选框

完事。现在开始绘制下拉框。


布局

函数结构

def add_combobox(self,pos:tuple,width:int=200,text='',content:tuple=(),fg='black',bg='white',activefg='#757F87',activebg='#CCE4F7',font=('微软雅黑',12),command=None):#绘制组合框'''pos::位置width::文本显示框宽度text::初始文本content::各个选项组成的元组fg::文本、边框颜色bg::背景色activefg::响应鼠标的文本、边框颜色activebg::响应鼠标的背景色font::字体command::回调函数。必须有一个参数:被选中的选项文本'''

闭合状态下拉框

下拉框在常规状态下,由文本显示框和下拉提示框组成。其中,下拉提示框我们会使用TinUI的按钮替代。

main=self.create_text(pos,text=text,font=font,fill=fg,anchor='nw')
bbox=self.bbox(main)
x1,y1,x2,y2=bbox[0]-3,bbox[1]-3,bbox[0]+width+3,bbox[3]+3
back=self.create_rectangle((x1,y1,x2,y2),fill=bg,outline=fg)
self.tkraise(main)
#下拉提示框
button_text,button_back=self.add_button((x2+3,y1+3),'∨',fg,bg,activefg,activebg,font=font,command=open_box)

其中,函数open_box对应了展开和闭合选项框的操作,后面再讲。

选项框

下面的代码借鉴了TinUI单选框的绘制代码。

def button_in(_tag):self.itemconfig(_tag,fill=activebg,outline=activefg)
def button_out(_tag):self.itemconfig(_tag,fill=bg,outline=fg)
start_x=bbox[0]#起始x位置height=bbox[3]+3#变量y位置for i in content:choice=self.create_text((start_x+2,height+2),text=i,fill=fg,font=(font[0],10),anchor='nw',width=width-4)pos=self.bbox(choice)h=pos[3]-pos[1]+4cho_back=self.create_rectangle((start_x,height,start_x+width,height+h),outline=fg,fill=bg)self.tkraise(choice)height+=h+2self.tag_bind(choice,'<Enter>',lambda event,back=cho_back:button_in(back))self.tag_bind(choice,'<Leave>',lambda event,back=cho_back:button_out(back))self.tag_bind(cho_back,'<Enter>',lambda event,back=cho_back:button_in(back))self.tag_bind(cho_back,'<Leave>',lambda event,back=cho_back:button_out(back))self.tag_bind(choice,'<Button>',lambda event,_text=i,back=cho_back:choose_this(back,_text))self.tag_bind(cho_back,'<Button>',lambda event,_text=i,back=cho_back:choose_this(back,_text))

这段代码取自于TinUI的radiobutton绘制代码,有删改。

这段代码的含义在TinUI绘制单选框中提到,这里不再阐述。

函数choose_this代表响应鼠标的选中动作。届时,文本显示框将显示选中的文本。

def choose_this(back,word):self.itemconfig(main,text=word)if command!=None:command(word)

整合选项框

在之后的操作中,我们需要对所有选项框进行统一操作,因此我们将为它们建立一个一致的tag名称。为了避免tag名称重复,我们将使用文本显示框和下拉提示框的组件id进行tag命名。

start_x=bbox[0]#起始x位置
height=bbox[3]+3#变量y位置
box_tagname='combobox>'+str(main)+'>'+str(back)#绑定独立的tag名称
for i in content:#...self.addtag_withtag(box_tagname,choice)self.addtag_withtag(box_tagname,cho_back)

展开与闭合

这个动作均有open_box函数进行操作。我们可以通过按钮的文本,来判断当前下拉框的状态。

首先,那些选项框本身是闭合的。

#...
for i in content:#...
self.itemconfig(box_tagname,state='hidden')

那么,函数的操作如下:

def open_box(event):if self.itemcget(button_text,'text')=='∨':self.itemconfig(button_text,text='∧',fill=activefg)self.itemconfig(box_tagname,state='normal')else:self.itemconfig(button_text,text='∨',fill=activefg)self.itemconfig(box_tagname,state='hidden')

OK,可以去吃饭了。

完整代码函数

def add_combobox(self,pos:tuple,width:int=200,text='',content:tuple=(),fg='black',bg='white',activefg='#757F87',activebg='#CCE4F7',font=('微软雅黑',12),command=None):#绘制组合框def button_in(_tag):self.itemconfig(_tag,fill=activebg,outline=activefg)def button_out(_tag):self.itemconfig(_tag,fill=bg,outline=fg)def open_box(event):if self.itemcget(button_text,'text')=='∨':self.itemconfig(button_text,text='∧',fill=activefg)self.itemconfig(box_tagname,state='normal')else:self.itemconfig(button_text,text='∨',fill=activefg)self.itemconfig(box_tagname,state='hidden')def choose_this(back,word):self.itemconfig(main,text=word)if command!=None:command(word)main=self.create_text(pos,text=text,font=font,fill=fg,anchor='nw')bbox=self.bbox(main)x1,y1,x2,y2=bbox[0]-3,bbox[1]-3,bbox[0]+width+3,bbox[3]+3back=self.create_rectangle((x1,y1,x2,y2),fill=bg,outline=fg)self.tkraise(main)button_text,button_back=self.add_button((x2+3,y1+3),'∨',fg,bg,activefg,activebg,font=font,command=open_box)start_x=bbox[0]#起始x位置height=bbox[3]+3#变量y位置box_tagname='combobox>'+str(main)+'>'+str(back)#绑定独立的tag名称for i in content:choice=self.create_text((start_x+2,height+2),text=i,fill=fg,font=(font[0],10),anchor='nw',width=width-4)pos=self.bbox(choice)h=pos[3]-pos[1]+4cho_back=self.create_rectangle((start_x,height,start_x+width,height+h),outline=fg,fill=bg)self.tkraise(choice)height+=h+2self.tag_bind(choice,'<Enter>',lambda event,back=cho_back:button_in(back))self.tag_bind(choice,'<Leave>',lambda event,back=cho_back:button_out(back))self.tag_bind(cho_back,'<Enter>',lambda event,back=cho_back:button_in(back))self.tag_bind(cho_back,'<Leave>',lambda event,back=cho_back:button_out(back))self.tag_bind(choice,'<Button>',lambda event,_text=i,back=cho_back:choose_this(back,_text))self.tag_bind(cho_back,'<Button>',lambda event,_text=i,back=cho_back:choose_this(back,_text))self.addtag_withtag(box_tagname,choice)self.addtag_withtag(box_tagname,cho_back)self.itemconfig(box_tagname,state='hidden')return main,back,box_tagname

效果

测试代码

def test(event):a.title('TinUI Test')b.add_paragraph((50,150),'这是TinUI按钮触达的事件函数回显,此外,窗口标题也被改变、首行标题缩进减小')b.coords(m,100,5)
def test1(word):print(word)
def test2(event):ok1()
def test3(event):ok2()if __name__=='__main__':a=Tk()a.geometry('700x700+5+5')b=TinUI(a,bg='white')b.pack(fill='both',expand=True)m=b.add_title((600,0),'TinUI is a test project for futher tin using')m1=b.add_title((0,680),'test TinUI scrolled',size=2,angle=24)b.add_paragraph((20,290),'''     TinUI是基于tkinter画布开发的界面UI布局方案,作为tkinter拓展和TinEngine的拓展而存在。目前,TinUI尚处于开发阶段。如果想要使用完整的TinUI,敬请期待。''',angle=-18)b.add_paragraph((20,100),'下面的段落是测试画布的非平行字体显示效果,也是TinUI的简单介绍')b.add_button((250,450),'测试按钮',activefg='white',activebg='red',command=test,anchor='center')b.add_checkbutton((80,430),'允许TinUI测试',command=test1)b.add_label((10,220),'这是由画布TinUI绘制的Label组件')b.add_entry((250,300),350,30,'这里用来输入')b.add_separate((20,200),600)b.add_radiobutton((50,480),300,'sky is blue, water is blue, too. So, what is your heart',('red','blue','black'),command=test1)b.add_link((400,500),'TinGroup知识库','http://tinhome.baklib-free.com/')_,ok1=b.add_waitbar1((500,220),bg='lightgreen')b.add_button((500,270),'停止等待动画',activefg='cyan',activebg='black',command=test2)bu1=b.add_button((700,200),'停止点状滚动条',activefg='white',activebg='black',command=test3)[1]bu2=b.add_button((700,250),'nothing button 2')[1]bu3=b.add_button((700,300),'nothing button 3')[1]b.add_labelframe((bu1,bu2,bu3),'box buttons')_,_,ok2=b.add_waitbar2((600,400),fg='blue')b.add_combobox((600,550),text='你有多大可能去珠穆朗玛峰',content=('20%','40%','60%','80%','100%','1000%'))a.mainloop()

最终效果


2021-7-29新样式


github项目

TinUI的github项目地址

pip下载

pip install tinui

结语

确实,TinUI的下拉框相比于系统下拉框还有细节上的不足,但是TinUI的下拉框提供了较多的自定义选项,而且不会影响使用效果。

中考考完,居然就直接写了这一篇8000+字的说明文……

欢迎到github上完善TinUI。

tkinter绘制组件(10)——组合框/下拉框相关推荐

  1. 自绘制HT For Web ComboBox下拉框组件

    传统的HTML5的下拉框select只能实现简单的文字下拉列表,而HT for Web通用组件中ComboBox不仅能够实现传统HTML5下拉框效果,而且可以在文本框和下拉列表中添加自定义的小图标,让 ...

  2. 下拉框的value值怎么设置为变量_自绘制HT For Web ComboBox下拉框组件

    传统的HTML5的下拉框select只能实现简单的文字下拉列表,而HT for Web通用组件中ComboBox不仅能够实现传统HTML5下拉框效果,而且可以在文本框和下拉列表中添加自定义的小图标,让 ...

  3. tkinter绘制组件(9)——点状等待框

    tkinter绘制组件(9)--点状等待框 引言 布局 函数结构 背景 移动点 动画样式 组件与单点控制 单点移动 结束函数 完整代码函数 效果 测试代码 最终效果 2021-7-30新样式 gith ...

  4. html5日期不联动下拉框,下拉框联动问题 赋值时候失效

    我想将三个下拉框变成一个组件 初始是没问题的 下拉福州市可以读取接口获取福州市的几个区 然后选区 查到街道 但是直接传值的时候一次性把三个都传进去导致第一个读取了 后面两个被重置了 一个一个传又破坏了 ...

  5. js 实现多选框(复选框) 和单选框,下拉框功能完整示例代码附效果图

    <!DOCTYPE html> <html><head><meta charset="utf-8" /><script src ...

  6. jquery获取单选框复选框下拉框值

    jquery获取单选框(radio)复选框(checkbox)下拉框(select)的值,亲测可用.有什么疑问可以留言 效果图: html代码: <!DOCTYPE html> <h ...

  7. php select下拉框,下拉框处理(select)

    在UI自动化测试过程中,经常会遇到一些下拉框,我们有三种可选方式来操作下拉框. 第一种方法 基于webdriver的两次click,很容易出现问题,不建议使用.(由于部分下拉框在点击一次后,失去焦点再 ...

  8. python 下拉列表单选框怎么获取元素_JS获取文本框,下拉框,单选框的值的简单实例...

    1.文本框 1.1 通过var t=document.getElementById("test").value把值赋给变量t, 1.2 当然也可以反过来把已知的变量值赋给文本框,例 ...

  9. vue可视化拖拽组件模板,vue自定义下拉框组件

    怎样利用Vue动态生成form表单 . $formCreate参数rules 表单生成规则[inputRule,selectRule,...]options 初始化配置参数(详细见底部createOp ...

最新文章

  1. 信息检索报告_读者信息素养状况问卷调查分析报告来啦
  2. 按部就班——图解配置IIS5的SSL安全访问
  3. php 重定向到https,php - 如何从HTTPS重定向到HTTP? - SO中文参考 - www.soinside.com
  4. oracle串连接,Oracle中串连接符||的使用心得(个人见解)
  5. java拆分任意五位数_五位数拆分出各位 - osc_foo7glsg的个人空间 - OSCHINA - 中文开源技术交流社区...
  6. 华为上半年收入4540亿元;GitHub服务中断,已恢复​;Python 3.8.4发布|极客头条
  7. 如何通过索引从列表中删除元素?
  8. linux执行sh文件 查进程,linux – 用于检查进程是否已在运行的Shell脚本,如果是,则退出...
  9. css布局的漂浮、position定位
  10. 华铭智能属于芯片概念吗_华铭智能:子公司1个亿参股边缘计算独角兽九次方大数据!...
  11. 英特尔开源技术中心招收ROS2高手两名
  12. 新汽车行业的中台实践
  13. 英语中学生测试软件,初中生免费学英语的软件哪个好
  14. java进阶知识思维导图
  15. 七层网络性能基准测试中的协调遗漏问题--Coordinated Omission
  16. 抓包工具charles实践分享
  17. 【自然语言处理】【检索】GENER:自回归实体检索
  18. Java面试问题总结归纳
  19. GMS(Google Mobile Service)
  20. 笔记本计算机名称PC2019,2019值得推荐的13寸笔记本电脑汇总

热门文章

  1. ajax所需的js文件,ajax 需要的js文件
  2. c语言用价格统计图书信息,C语言图书信息管理系统代码.doc
  3. 英语里面关于钱数量的单词有哪些
  4. 游戏主循环(Game Loop)的详细解析
  5. ABAPA实现二维码打印
  6. 解决SpringSecurity登入后跳转报错
  7. 软件配置部分——从无到有自主搭建视觉惯性VI-SLAM(vins-mono)平台
  8. golang excel导出 style样式和所有流程
  9. C#WebBrowser控件使用教程与技巧收集--苏飞收集
  10. 质量评估模型助力风险决策水平提升