引言
开关组件实际上类似于复选框组件,但是两者的用途是有区别的。复选框用于在大部分的选项中选定,而开关组件则是用在开启或关闭功能上,因此有必要在TinUI增加开关组件(OnOffButton)。
关于开关组件的样式,本来打算仿造如今UWP中的开关组件,但是遇到了一个问题:在Windows平台下,tkinter绘制曲线会产生影响视觉效果的锯齿形状,而且无法消除。然而开关组件的两侧就是半圆形,显然在TinUI中无法使用这个样式。那么我们直接使用新的开关组件样式算了。
如果你是在Mac或Linux平台上运行,你可以自行修改TinUI在github上绘制开关组件的代码。
布局
函数结构
def add_onoff(self,pos:tuple,fg='#333333',bg='#FFFFFF',onfg='#FFFFFF',onbg='#4258CC',font=('微软雅黑',12),command=None):#绘制开关控件
'''
pos::位置
fg::关闭状态下的文本和边框颜色
bg::关闭状态下的背景颜色
onfg::开启状态下的文本颜色
onbg::开启状态下的边框和背景颜色
font::字体
command::响应开关时调用函数,必须接受一个参数:True(开启)或False(关闭)
'''
样式
TinUI绘制的开关组件大概是这个样子的:
_____________________
/ \
/ on \
\ off /
\ /
—————————————————————
因为是文本符号标识,所以有一点粗糙。
文本绘制
这个命名很简单,但是为什么要着重强调呢?
因为文本的绘制,关系到背景样式的绘制。背景样式的绘制需要依靠文本的覆盖尺寸,通过这些数据进行计算,然后才能够得出背景的绘制范围。
state=self.create_text(pos,anchor='nw',text=state,fill=fg,font=font)
bbox=self.bbox(state)
d=int(bbox[3]-bbox[1])#获得绘制半径
width=bbox[2]-bbox[0]#获取绘制宽度
#将文本移到最大高度位置
self.move(state,d,0)
背景绘制
通过文本的绘制,我们得到并执行了以下数据操作:
- 获取背景两侧的各三个关键折点
- 将文本移动到符合的位置
因为背景是一个对称的六边形,因此我们不再使用画布的标准图形绘制的了,我们将直接使用create_polygon函数绘制这一个多边形。
通过计算得到六个关键点的坐标:
(pos[0]+d,pos[1],#左上折点
pos[0],pos[1]+d/2,#左折点
pos[0]+d,pos[1]+d,#左下折点
pos[0]+d+width,pos[1]+d,#右下折点
pos[0]+d*2+width,pos[1]+d/2,#右折点
pos[0]+d+width,pos[1],#右上这点
pos[0]+d,pos[1])#重新回到左上折点
接着就是绘制多边形的代码:
back=self.create_polygon((pos[0]+d,pos[1],pos[0],pos[1]+d/2,pos[0]+d,pos[1]+d,pos[0]+d+width,pos[1]+d,pos[0]+d*2+width,pos[1]+d/2,pos[0]+d+width,pos[1],pos[0]+d,pos[1]),fill=bg,outline=fg,width=2,joinstyle='miter')
self.tkraise(state)
响应开关
在开关组件的响应事件中,我们通过三个函数实现开关的响应:
def __on():
#开启时响应函数调用
def __off():
#关闭时响应函数调用
def __on_click(event):
#判断开关状态,并重绘开关样式
主要问题是判断开关的状态,根据之前的经验,我们可以通过画布对象样式判断开关的状态,并且重绘样式和执行相应的操作。
def __on():
if command!=None:
command(True)
def __off():
if command!=None:
command(False)
def __on_click(event):
if self.itemcget(state,'fill')==fg:#开关关闭,开启
self.itemconfig(state,fill=onfg,text='on')
self.move(state,width//10,0)
self.itemconfig(back,fill=onbg,outline=onbg)
__on()
else:#开关开启,关闭
self.itemconfig(state,fill=fg,text='off')
self.move(state,0-width//10,0)
self.itemconfig(back,fill=bg,outline=fg)
__off()
然后再为两个画布对象绑定响应事件:
self.tag_bind(state,'<Button-1>',__on_click)
self.tag_bind(state,'<Button-1>',__on_click)
完事。
完整代码函数
def add_onoff(self,pos:tuple,fg='#333333',bg='#FFFFFF',onfg='#FFFFFF',onbg='#4258CC',font=('微软雅黑',12),command=None):#绘制开关控件
def __on():
if command!=None:
command(True)
def __off():
if command!=None:
command(False)
def __on_click(event):
if self.itemcget(state,'fill')==fg:
self.itemconfig(state,fill=onfg,text='on')
self.move(state,width//10,0)
self.itemconfig(back,fill=onbg,outline=onbg)
__on()
else:
self.itemconfig(state,fill=fg,text='off')
self.move(state,0-width//10,0)
self.itemconfig(back,fill=bg,outline=fg)
__off()
state=self.create_text(pos,anchor='nw',text=state,fill=fg,font=font)
bbox=self.bbox(state)
d=int(bbox[3]-bbox[1])#获得绘制半径
width=bbox[2]-bbox[0]#获取绘制宽度
self.move(state,d,0)
back=self.create_polygon((pos[0]+d,pos[1],pos[0],pos[1]+d/2,pos[0]+d,pos[1]+d,pos[0]+d+width,pos[1]+d,pos[0]+d*2+width,pos[1]+d/2,pos[0]+d+width,pos[1],pos[0]+d,pos[1]),fill=bg,outline=fg,width=2,joinstyle='miter')
self.tkraise(state)
self.tag_bind(state,'<Button-1>',__on_click)
self.tag_bind(state,'<Button-1>',__on_click)
return state,back
效果
测试代码
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()
def test4(event):
from time import sleep
for i in range(1,101):
sleep(0.02)
progressgoto(i)
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='#CCCCCC')
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))
b.add_combobox((600,550),text='你有多大可能去珠穆朗玛峰',content=('20%','40%','60%','80%','100%','1000%'))
b.add_button((600,480),text='测试进度条(无事件版本)',command=test4)
_,_,_,progressgoto=b.add_progressbar((600,510))
b.add_table((180,630),data=(('a','space fans over the world','c'),('you\ncan','2','3'),('I','II','have a dream, then try your best to get it!')))
b.add_paragraph((300,810),text='上面是一个表格')
b.add_onoff((600,100))
a.mainloop()
最终效果
2022-8-24新样式
这哪是新样式,这分明是重写了
onoff
元素控件:
- 使用winui样式以及圆角
- 添加相关方法,也就是
funcs
返回值
github项目
pip下载
pip install tinui
结语
TinUI能够实现目前这些组件的绘制已经很不错了,并且TinUI是能够运用到tkinter窗口组件绘制上的。
下面是TinGroup应用中TinUpgrader使用TinUI绘制前后的差别。
之前的TinUpgrader
使用TinUI的TinUpgrader
从对比上也可以看出TinUI对tkinter界面视觉效果有很大改善。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。