文章目录
- 继承Frame
- 点击事件
- Add函数
tkinter系列:
- GUI初步💎布局💎绑定变量💎绑定事件💎消息框💎文件对话框
- Frame控件💎PanedWindow和notebook控件
- 扫雷小游戏💎强行表白神器
和其他成熟的GUI库相比,tkinter的组件并不是太多,但在自定义组件这一点上,并不逊色于其他框架,接下来就自定义一个Expander控件。
继承Frame
Expander控件说穿了也很简单,就是一个长条形的按钮,按钮下装着一个普通的Frame就可以。为了实现这个功能,新建一个Frame的子类,像下面这样
import tkinter as tk
import tkinter.ttk as ttkclass Expander(ttk.Frame):def __init__(self, master, title, **options):super().__init__(master, **options)self.pack()self.initWidgets(title)def initWidgets(self, title):self.btn = ttk.Button(self, text=title, command=self.Click)self.btn.pack(side=tk.TOP, fill=tk.X, expand=tk.YES)self.content = ttk.Frame(self)self.content.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES)def Click(self):pass
其中,initWidgets用于初始化控件,上面是一个长条形的按钮,下面是一个Frame,用于添加新组件。Click是点击按钮时的响应函数,目前还没有完成。
下面稍微演示一下
root = tk.Tk()
ex = Expander(root, "expander")
ex.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES)
root.mainloop()
效果如下
点击事件
接下来就实现Expander的核心功能,点击按钮改变内容的可见情况。众所周知,在tkinter中,可以通过pack来把某个控件塞到父控件里。那么如果想把这个控件隐藏,只要将其从父控件中拿出来就可以了,用到的函数是pack_forget,非常形象。
而内容Frame的显隐,则需要一个标记,记作self.collapsed,那么Click函数可以写为
def Click(self):if self.collapsed:self.content.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES) else:self.content.pack_forget()self.collapsed = not self.collapsed
即如果已经折叠了,那就打开content,否则就关闭。然后折叠标记取反。
由于新增了一个全局变量self.collapsed,故而需要修改initWidgets函数
def initWidgets(self, title):self.btn = ttk.Button(self, text=title, command=self.Click)self.btn.pack(side=tk.TOP, fill=tk.X, expand=tk.YES)self.content = ttk.Frame(self)self.collapsed = Trueself.Click()
至此,理论上就实现了一个Expander,下面演示一下
root = tk.Tk()
ex = Expander(root, "expander")
ex.pack(side=tk.TOP, fill=tk.X)
tk.Label(ex.content, text="Label").pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES)
root.mainloop()
需要注意的是,tk.Label的父控件并不是ex,而是ex.content。效果如下
Add函数
ex.content毕竟是内部变量,给暴露出去并不太好,所以最好构造一个Add函数,用来添加新控件,这种东西对于函数式编程来说可谓手到擒来
def Add(self, Child, **options):return Child(self.content, **options)
然后测试函数可写为
root = tk.Tk()
ex = Expander(root, "expander")
ex.pack(side=tk.TOP, fill=tk.X)
L = ex.Add(tk.Label, text="Label")
L.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES)
root.mainloop()