2. tkinter二次开发控件

背景

本人不是处女座,但有着处女座的‘坏毛病’。tkinter原生的控件美感让我十分苦恼,于是我决定二次封装一些调用方便并且相对美观的控件。

1. LabelEntry(带标签的输入框)

本人最近开发tkinter可视化开发工具时,需要写一个实时改变控件属性的页面,其中就需要若干个Label+Entry(或者Button)阵列。简单而直接的办法就是Grid方法进行排列,但是调试过程十分麻烦,比如调边距、对齐方式、Entry的快捷输入等等。

于是就用一个Frame封装了Label、Entry、Button,可以将一个单键字典{“key”:"value"}传入,并保存value的数据类型,如果value是int型或float型,鼠标放到Entry控件中滚动,还可以调节值的大小。

上代码

from tkinter import Label,Entry,Frame,Tk,StringVar,Button
from tkinter.font import Font
from tkinter.colorchooser import askcolor

class LabelEntry():
    def __init__(self,master, key,value,scrollChooser=True,colorChooser=False):
        '''
        :param master:
        :param key: 键
        :param value: 键值
        :param callback: (func,args)元组,传递函数和参数
        :param scrollChoose: 是否通过滚动鼠标来增加或减少数值
        :param colorChooser: 是否添加颜色选择按钮
        '''
        self.__key_type=type(key).__name__
        self.__value_type=type(value).__name__
        self.__key=key
        self.__callback=None
        self.__value=StringVar(value=str(value))
        self._frame=Frame(master)
        self.__value_range=[-1000000,1000000,1]
        self._label=Label(self._frame,text=str(key))
        self._entry=Entry(self._frame,textvariable=self.__value,state='disabled')
        self._btn = Button(self._frame, text='...')
        self.style_config(colorChooser=colorChooser)
        self.place = self.place_configure = self._frame.place
        if scrollChooser:
            self._entry.bind('<MouseWheel>',self.__scroll_change_value)
        if colorChooser:
            self._btn.config(command=self.__choose_color)
            self._entry.unbind('<MouseWheel>')


    def style_config(self,bg_l='#888888',bg_e='#A0A0A0',fg_l='black',fg_e='black',fontsize=13,w_l=80,w_e=100,height=25,anchor='w',colorChooser=True):
        # 控件属性
        self._frame.config(bg=bg_l,relief='solid',bd=1)
        self._label.config(bg=bg_l,fg=fg_l,font=Font(family='等线',size=fontsize,weight='bold'),anchor=anchor)
        self._entry.config(bg=bg_e,fg=fg_e,font=Font(size=fontsize),relief='solid',bd=1)
        # 位置属性
        self._frame.place_configure(height=height+2,width=w_l+w_e+2)
        self._label.place_configure(x=0,y=0,height=height,width=w_l)
        self._entry.place_configure(x=w_l,y=0,height=height,width=w_e)
        self._btn.config(bg=bg_l,fg='black',relief='groove',bd=0)
        if colorChooser:
            self._btn.place_configure(x=w_l+w_e-1,y=0,height=height,width=20)
            self._frame.place_configure(height=height + 2, width=w_l + w_e + 22)

    def bind_func(self,callback=None):
        self.__callback=callback

    # 颜色选择函数
    def __choose_color(self):
        color=askcolor()[1]
        self.__value.set(color)
        self._entry.config(state='normal',bg=color)
        if callable(self.__callback):
            self.__callback()


    # 通过鼠标滚轮改变输入框的值
    def __scroll_change_value(self,event):
        now_value=self.key_value[str(self.__key)]
        if event.delta>0 and now_value<self.__value_range[1]:
            self.__value.set(now_value+self.__value_range[2])
            if callable(self.__callback):
                self.__callback()
        elif event.delta<0 and now_value>self.__value_range[0]:
            self.__value.set(now_value - self.__value_range[2])
            if callable(self.__callback):
                self.__callback()

    @property
    def key_value(self):
        return {eval(self.__key_type)(self.__key):eval(self.__value_type)(self.__value.get())}

    @key_value.setter
    def key_value(self,value):
        self.__value.set(value)

    def valueRange(self,_min=0,_max=10,step=1):
        self.__value_range=[_min,_max,step]

if __name__ == '__main__':
    root=Tk()
    root.geometry('400x100')
    lb=LabelEntry(root,'width',200,colorChooser=False)
    lb.valueRange(200,250)
    lb.bind_func(lambda :lb.place_configure(cnf=lb.key_value))
    lb.place(x=10,y=30)
    root.mainloop()

可以复制下来,自己尝试下,挺好用的

2. ScrollFrame(可以滚动页面的Frame)

这是一个嵌套Frame的Frame,内置了捕获滚动事件函数,以及限制滚动区域函数。

注意点:目前仅支持place方法布局,pack和grid方法不可用。

上代码

from tkinter import Frame,Tk,Label,X


class ScrollFrame(Frame):
    def __init__(self,master,step=10,innerheight=500):
        self._outFrame=Frame(master,bg='yellow')
        Frame.__init__(self,self._outFrame,bg='black')
        self.bind_all('<MouseWheel>', self.__scroll_func)
        self.__step=step
        self._inner_place(height=innerheight)

    def scroll_page(self, length):
        if length>0:
            if self.winfo_y()+length>0:
                self._inner_place(x=0,y=0)
            else:
                self._inner_place(x=0,y=self.winfo_y()+length)
        elif length<0:
            if self.winfo_y()+self.winfo_height()+length>self._outFrame.winfo_height():
                self._inner_place(x=0,y=self.winfo_y()+length)

    def __scroll_func(self,event):
        def digui(widget):
            if hasattr(widget,'scroll_page'):
                widget.scroll_page(event.delta / abs(event.delta) * self.__step)
                return True
            elif hasattr(widget,'master'):
                if hasattr(widget.master,'scroll_page'):
                    widget.master.scroll_page(event.delta/abs(event.delta)*self.__step)
                    return True
                else:
                    digui(widget.master)
            else:
                return False
        digui(event.widget)

    def config(self, **kw):
        self.configure(cnf=kw)

    def place(self,**kw):
        self._outFrame.place_configure(cnf=kw)
        self._inner_place(x=0,y=0,width=kw['width'])

    def _inner_place(self,cnf:dict=None, **kw):
        self.tk.call(
            ('place', 'configure', self._w)
            + self._options(cnf, kw))


if __name__ == '__main__':
    root=Tk()
    frm=ScrollFrame(root,innerheight=300)
    frm.place(x=10,y=10,width=100,height=200)
    [Label(frm,text=str(x),bg='gray').pack(pady=10,fill=X) for x in range(10)]
    root.mainloop()

同样的,测试代码也写好了,复制粘贴直接运行即可

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值