tkinter绘制组件(1)——起步

引言

所谓绘制组件,实际上就是虚拟组件,说白了就是依靠一个父组件绘制出来的图案,且具有组件的功能。在tkinter中,每一个组件都拥有自己的句柄,因为它们是实实在在的组件,而绘制组件则没有句柄。

绘制组件有很多优点:

  1. 占用内存小
  2. 样式比普通组件更丰富,这是其创建方式决定的
  3. 创建GUI窗口时更简洁、直观
  4. ……

之所以想要开发一个tkinter的绘制组件,并不是想代替tkinter的原生组件,因为tkinter的自身原因,某些组件功能是无法通过tkinter本身绘制出来的,如scrollbar。但是,开发虚拟组件,可以大大提高窗口运行速度,使界面布局更简单明了,同时也可以使用更加丰富的组件样式。这才是开发tkinter绘制组件的初衷。

因为目前该组件尚处于起步阶段,本篇只简单完成基础框架。

选择父组件

tkinter的画布(Canvas),当之无愧。Canvas是tkinter所有组件中综合功能最强大,也是最复杂的组件(没有之一)。

使用画布,可以很好得达到我们期望的目的。

这个绘制类组件,命名为“TinUI”。

我开发的另一个基于tkinter的富文本兼TinLayout布局渲染器——TinEngine


框架

先来创建一个组件类吧,很简单↓

class TinUI(Canvas):
    """适用于Tin的高级画布组件"""

    def __init__(self,master,**kw):
        self.frame = Frame(master)
        self.vbar = Scrollbar(self.frame)
        self.vbar.pack(side=RIGHT, fill=Y)
        ###
        kw.update({'yscrollcommand': self.vbar.set})
        Canvas.__init__(self, self.frame, **kw)
        self.pack(fill=BOTH, expand=True)
        self.vbar['command'] = self.yview
        ###
        self.hbar=Scrollbar(self.frame,orient='horizontal',command=self.xview)
        self.hbar.pack(side=BOTTOM,fill=X)
        self.config(xscrollcommand=self.hbar.set)
        # Copy geometry methods
        canvas_meths = vars(Canvas).keys()
        methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys()
        methods = methods.difference(canvas_meths)
        for m in methods:
            if m[0] != '_' and m != 'config' and m != 'configure':
                setattr(self, m, getattr(self.frame, m))

这并不是简单地创建一个画布。

可以看到,源码中还加入了滚动条。因为画布应该是能够滚动的,可以使窗口界面更加灵活。

但是,使用滚动条遇到一个重要问题,那就是滚动条与画布结合,必须指定画布的滚动范围。但是,在我们创建或更改虚拟组件时,画布的滚动范围是会改变的。那么,应该怎样然滚动条与画布内容匹配呢?

匹配滚动条

这里给出一个方法。

每隔一小会时间,就判断一次画布的可视范围,然后再绑定的滚动条即可。代码如下。

class TinUI(Canvas):
    """适用于Tin的高级画布组件"""

    def __init__(self,master,**kw):
        #未改变的代码
        self.bind('<MouseWheel>',self.set_y_view)#绑定纵向滚动
        self.init()#初始化一些自身变量
        self.update__()#持续更新滚动条

    def init(self):
        self.title_size={0:20,1:18,2:16,3:14,4:12}
    def set_y_view(self,event):
        self.yview_scroll(int(-1*(event.delta/120)), "units")
    def update__(self):#更新宽高
        try:
            #获取宽和高,绑定的滚动条
            x2,y2=self.bbox('all')[2:]
            self.config(scrollregion=(0,0,x2,y2))
        except:
            pass
        finally:
            #每隔一秒更新一次
            self.after(1000,self.update__)

这样,就完成了即时更新画布的滚动范围。

简单创建

目前,TinUI处于起步阶段,先来几个简单的创建虚拟组件例子。

以下是创建标题和段落的例子,类似Label,但并不全是:

    def add_title(self,pos:tuple,text:str,fg='black',font='微软雅黑',size=1,**kw):#绘制标题
        return self.create_text(pos,text=text,fill=fg,font=(font,self.title_size[size]),anchor='nw',**kw)

    def add_paragraph(self,pos:tuple,text:str,fg='black',font=('微软雅黑',12),side='left',width=500,**kw):#绘制段落
        return self.create_text(pos,text=text,fill=fg,font=font,anchor='nw',justify=side,width=width,**kw)

起步阶段的TinUI

完整代码:

class TinUI(Canvas):
    """适用于Tin的高级画布组件"""

    def __init__(self,master,**kw):
        self.frame = Frame(master)
        self.vbar = Scrollbar(self.frame)
        self.vbar.pack(side=RIGHT, fill=Y)
        ###
        kw.update({'yscrollcommand': self.vbar.set})
        Canvas.__init__(self, self.frame, **kw)
        self.pack(fill=BOTH, expand=True)
        self.vbar['command'] = self.yview
        ###
        self.hbar=Scrollbar(self.frame,orient='horizontal',command=self.xview)
        self.hbar.pack(side=BOTTOM,fill=X)
        self.config(xscrollcommand=self.hbar.set)
        # Copy geometry methods
        canvas_meths = vars(Canvas).keys()
        methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys()
        methods = methods.difference(canvas_meths)
        for m in methods:
            if m[0] != '_' and m != 'config' and m != 'configure':
                setattr(self, m, getattr(self.frame, m))
        self.bind('<MouseWheel>',self.set_y_view)
        self.init()
        self.update__()

    def init(self):
        self.title_size={0:20,1:18,2:16,3:14,4:12}
    def set_y_view(self,event):
        self.yview_scroll(int(-1*(event.delta/120)), "units")
    def update__(self):#更新宽高
        try:
            x2,y2=self.bbox('all')[2:]
            self.config(scrollregion=(0,0,x2,y2))
        except:
            pass
        finally:
            self.after(1000,self.update__)

    def add_title(self,pos:tuple,text:str,fg='black',font='微软雅黑',size=1,**kw):#绘制标题
        return self.create_text(pos,text=text,fill=fg,font=(font,self.title_size[size]),anchor='nw',**kw)

    def add_paragraph(self,pos:tuple,text:str,fg='black',font=('微软雅黑',12),side='left',width=500,**kw):#绘制段落
        return self.create_text(pos,text=text,fill=fg,font=font,anchor='nw',justify=side,width=width,**kw)

测试

测试代码

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')
b.add_title((40,670),'test TinUI scrolled',size=2)
b.add_paragraph((20,300),'''     TinUI是基于tkinter画布开发的界面UI布局方案,作为tkinter拓展和TinEngine的拓展而存在。目前,TinUI尚处于开发阶段。如果想要使用完整的TinUI,敬请期待。''')

a,mainloop()

效果

在这里插入图片描述


github项目

TinUI的github项目地址

结语

目前,TinUI正在开发的初步阶段。今年我要参加中考,估计要到暑假才能够认真地完善。

很好,已经2022-11-12了,现在回过头来看这篇文章,真的大有感慨。TinUI即将在年底左右推出-4.0-版本,届时,TinUI将正式常熟,包含tkinter所有原生控件,以及大量拓展控件。

这是来自2023-11的修改。TinUI-4.5修复了treeview多级元素展开时的样式错误问题,只是一个缝缝补补的小更新,大更新在2024年暑期之前不会到来。不过在此之前,突发奇想,计划由接下来的4.X版本过渡到5.0,然后就想设计一个新图标。这是当前的:
在这里插入图片描述
这是可能会在5.0出现的:
在这里插入图片描述

有兴趣的tkinter爱好者也可以联系我,说说你的想法:smart-space@qq.com。

🔆tkinter创新🔆

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值