当前位置:   article > 正文

tkinter绘制组件(6)——单选框_tkinter canvas创建单选框

tkinter canvas创建单选框

引言

在tkinter中,单选框即Radiobutton控件,可以允许使用者在GUI界面上选择其需要选择文字提示,以此来丰富界面的交互功能。

但是,tkinter.ttk的单选框来源于系统原生组件,Windows10原生的单选框组件看起来不太大气,而且tkinter自身的单选框样式有点粗糙。那么现在,让我们用画布绘制一个现代化外观的单选框集合组件——radiobutton


概念

整体概念

使用TinUI创建的单选框,实际上不是单独的一个组件,而是由两部分组成。

第一部分是组件开头的文本提示部分。

第二部分是多个单选框组成的集合体,拥有该组件的真正交互功能。

外观概念

为了使视觉效果更佳,TinUI中的单选框选中提示是整个选择元素变成提示颜色,而不只是前面的选中标记改变形式。


实现

定义函数

在TinUI中,使用add_radiobutton绘制单选框集合体。

def add_radiobutton(self,pos:tuple,width,text='',choices=('choose me'),fg='black',bg='white',font=('微软雅黑',12),command=None):#绘制单选框
    """
    pos::位置
    width::整体宽度
    text::提示文字
    choices::选择项的文字
    fg::文本颜色和边框颜色
    bg::选项背景色
    font::字体
    command::回调函数,必须有且仅有一个参数,即对应选项的文本(str)
    """
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

绘制文段提示

因为已经有了前面几个TinUI组件开发的基础,这里直接绘制文本段提示:

word=self.create_text(pos,text=text,fill=fg,font=font,anchor='nw',width=width)
  • 1

绘制选项元素

在TinUI中,单选框集合体采用竖式排列。因此,我们采用循环体代码绘制:

for i in choices:
    #绘制代码
  • 1
  • 2

每一个选项,对应一个边框(背景)矩形和选项文字,并且有以下要求:

  1. 矩形要完全包含文字
  2. 选项间有一定的间隔

针对第一个问题,因为已经有了前面绘制按钮和Label的经验,很容易实现:

for i in choices:
    choice=self.create_text(pos,text=i,fill=fg,font=font,anchor='nw',width=width-4)
    bbox=self.bbox(choice)
    back=self.create_rectangle((bbox[0]-2,bbox[1],bbox[2]+2,bbox[3]),outline=fg,fill=bg)
    self.tkraise(choice)
  • 1
  • 2
  • 3
  • 4
  • 5

针对第二个问题,需要考虑到整个画布的元素布局。经过一定的计算,对元素绘制进行如下修改:

start_x=pos[0]#起始x位置
height=self.bbox(word)[3]+3#变量y位置
for i in choices:
    #文本缩进
    choice=self.create_text((start_x+2,height+2),text=i,fill=fg,font=font,anchor='nw',width=width-4)
    bbox=self.bbox(choice)
    h=bbox[3]-bbox[1]+4#覆盖高度
    #文本覆盖
    back=self.create_rectangle((start_x,height,start_x+width,height+h),outline=fg,fill=bg)
    self.tkraise(choice)
    height+=h+2#下一个y位置
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

相应鼠标

因为之前完成了按钮以及复选框的绘制,有了一定的经验:

def button_in(tag):
    self.itemconfig(tag,fill='#E5F1FB',outline='#82BDEB')
def button_out(_tag):
    self.itemconfig(_tag,fill=bg,outline=fg)
def go_func(tag,_text):
    command(_text)
#...
for i in choices:
    #...
    self.tag_bind(choice,'<Enter>',lambda event,back=back:button_in(back))
    self.tag_bind(choice,'<Leave>',lambda event,back=back:button_out(back))
    self.tag_bind(back,'<Enter>',lambda event,back=back:button_in(back))
    self.tag_bind(back,'<Leave>',lambda event,back=back:button_out(back))
    self.tag_bind(choice,'<Button>',lambda event,_text=i,back=back:go_func(back,_text))
    self.tag_bind(back,'<Button>',lambda event,_text=i,back=back:go_func(back,_text))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

选中

当选项被选中时,不再变换样式,直到选中同组内下一个选项。

在TinUI中,使用动态列表与标准列表相结合的方式,来完成选项选中时的样式变化。

def button_in(tag):
    #...
def button_out(_tag):
    for tag in back_list:
        self.itemconfig(tag,fill=bg,outline=fg)
def go_func(tag,_text):
    for i in choices_back:#判断是否为当前选中
        if i not in back_list:
            back_list.append(i)
            button_out(tag)
    back_list.remove(tag)
    self.itemconfig(tag,fill='#E5F1FB',outline='#82BDEB')
    command(_text)
#...
choices_list=[]
choices_back=[]#标准列表
for i in choices:
    #...
    choices_list.append(choice)
    choices_back.append(back)
    #...
back_list=list(choices_back)#动态列表
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

完整代码函数

下面是绘制单选框的完成函数:

def add_radiobutton(self,pos:tuple,width,text='',choices=('choose me'),fg='black',bg='white',font=('微软雅黑',12),command=None):#绘制单选框
    def button_in(tag):
        self.itemconfig(tag,fill='#E5F1FB',outline='#82BDEB')
    def button_out(_tag):
        for tag in back_list:
            self.itemconfig(tag,fill=bg,outline=fg)
    def go_func(tag,_text):
        for i in choices_back:#判断是否为当前选中
            if i not in back_list:
                back_list.append(i)
                button_out(tag)
        back_list.remove(tag)
        self.itemconfig(tag,fill='#E5F1FB',outline='#82BDEB')
        command(_text)
    word=self.create_text(pos,text=text,fill=fg,font=font,anchor='nw',width=width)
    start_x=pos[0]#起始x位置
    height=self.bbox(word)[3]+3#变量y位置
    choices_list=[]
    choices_back=[]
    for i in choices:
        choice=self.create_text((start_x+2,height+2),text=i,fill=fg,font=font,anchor='nw',width=width-4)
        bbox=self.bbox(choice)
        h=bbox[3]-bbox[1]+4
        back=self.create_rectangle((start_x,height,start_x+width,height+h),outline=fg,fill=bg)
        self.tkraise(choice)
        height+=h+2
        choices_list.append(choice)
        choices_back.append(back)
        self.tag_bind(choice,'<Enter>',lambda event,back=back:button_in(back))
        self.tag_bind(choice,'<Leave>',lambda event,back=back:button_out(back))
        self.tag_bind(back,'<Enter>',lambda event,back=back:button_in(back))
        self.tag_bind(back,'<Leave>',lambda event,back=back:button_out(back))
        self.tag_bind(choice,'<Button>',lambda event,_text=i,back=back:go_func(back,_text))
        self.tag_bind(back,'<Button>',lambda event,_text=i,back=back:go_func(back,_text))
    back_list=list(choices_back)
    return word,choices_list
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

效果

测试代码

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):
    pass

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),'测试按钮',command=test)
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)

a.mainloop()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

最终效果

在这里插入图片描述

2022-2-10新样式

在这里插入图片描述

2024-6-13新样式

在这里插入图片描述


github项目

TinUI的github项目地址

结语

TinUI现在已经可以用于简单的窗口主体创建了。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】

推荐阅读
相关标签