python 的GUI封装
功能扩展点
进度条控件:
增加对 ttk.Progressbar 的支持,用于展示进度。列表框控件:
提供 Listbox 的创建方法,用于展示和选择多项数据。
复选框和单选按钮:Checkbutton 和 Radiobutton 控件的支持。
画布和图形支持:
提供 Canvas 控件,用于绘制图形或复杂的布局。布局管理器:
增加对 pack 和 grid 布局的支持,进一步简化界面布局。
动态更新方法:
为控件增加动态更新内容的方法,比如 update_text 和 update_value。
import tkinter
import tkinter.messagebox
from tkinter.ttk import Progressbar, Combobox
class GuiBase:
"""基础类,提供窗口的初始化和控制"""
def __init__(self):
self.root = tkinter.Tk() # 初始化窗口
self.tk = tkinter
self.controls = {} # 存放控件
def show(self):
"""显示窗口"""
self.root.mainloop()
def quit(self):
"""关闭窗口"""
self.root.quit()
class GuiAttributes(GuiBase):
"""窗口属性类,提供窗口属性设置方法"""
def set_title(self, title):
"""设置窗口标题"""
self.root.title(title)
def set_icon(self, path):
"""设置窗口图标"""
self.root.iconbitmap(path)
def get_screen_size(self):
"""获取屏幕大小"""
return self.root.maxsize()
def set_geometry(self, width, height, x=None, y=None):
"""设置窗口大小和位置"""
if x is None or y is None:
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
x = (screen_width - width) // 2
y = (screen_height - height) // 2
geometry = f"{width}x{height}+{x}+{y}"
self.root.geometry(geometry)
def set_bg_color(self, color):
"""设置背景颜色"""
self.root.configure(background=color)
def set_resizable(self, width=False, height=False):
"""设置是否可拉伸"""
self.root.resizable(width=width, height=height)
def set_topmost(self, topmost=True):
"""设置窗口置顶"""
self.root.wm_attributes('-topmost', topmost)
def hide_title_bar(self):
"""隐藏窗口标题栏"""
self.root.overrideredirect(True)
class GuiControl(GuiBase):
"""控件类,提供常用控件的创建方法"""
def create_label(self, text, x, y, font=('黑体', 15), fg='black'):
"""创建标签"""
label = self.tk.Label(self.root, text=text, font=font, fg=fg)
label.place(x=x, y=y)
return label
def create_button(self, text, command, x, y, font=('宋体', 12), fg='black', relief='groove', cursor='hand2'):
"""创建按钮"""
button = self.tk.Button(self.root, text=text, font=font, fg=fg, relief=relief, cursor=cursor, command=command)
button.place(x=x, y=y)
return button
def create_entry(self, x, y, show=None, font=('黑体', 15), width=20, fg='black'):
"""创建输入框"""
entry = self.tk.Entry(self.root, font=font, fg=fg, width=width, show=show)
entry.place(x=x, y=y)
return entry
def create_combobox(self, x, y, values, default_value=None, font=('黑体', 12)):
"""创建下拉框(Combobox)"""
combobox = Combobox(self.root, values=values, font=font)
combobox.place(x=x, y=y)
if default_value:
combobox.set(default_value)
return combobox
def create_multiselect_combobox(self, x, y, values, width=20, height=5, font=('黑体', 12)):
"""创建多选下拉框"""
# 创建容器框架
frame = self.tk.Frame(self.root)
frame.place(x=x, y=y)
# 创建显示框
entry_var = self.tk.StringVar()
entry = self.tk.Entry(frame, textvariable=entry_var, font=font, state='readonly', width=width)
entry.pack(side=self.tk.TOP, fill=self.tk.X)
# 创建下拉框
listbox = self.tk.Listbox(frame, selectmode='multiple', font=font, height=height, width=width)
for value in values:
listbox.insert(self.tk.END, value)
# 切换下拉框显示
def toggle_listbox(event=None):
if listbox.winfo_ismapped():
listbox.pack_forget() # 隐藏下拉框
else:
listbox.pack(side=self.tk.BOTTOM, fill=self.tk.X) # 显示下拉框
# 更新选中的值
def update_selection(event=None):
selected_items = [listbox.get(i) for i in listbox.curselection()]
entry_var.set(", ".join(selected_items))
listbox.pack_forget() # 隐藏下拉框
# 绑定事件
entry.bind("<Button-1>", toggle_listbox) # 点击显示/隐藏下拉框
listbox.bind("<<ListboxSelect>>", update_selection) # 选择后更新值
return listbox, entry_var
def create_checkbox(self, text, x, y, var=None, font=('黑体', 12)):
"""创建复选框"""
if var is None:
var = self.tk.BooleanVar()
checkbox = self.tk.Checkbutton(self.root, text=text, font=font, variable=var)
checkbox.place(x=x, y=y)
return checkbox, var
def create_radiobutton(self, text, x, y, value, var=None, font=('黑体', 12)):
"""创建单选按钮"""
if var is None:
var = self.tk.StringVar()
def toggle_selection():
if var.get() == value:
var.set("") # 清空选择
radiobutton = self.tk.Radiobutton(
self.root,
text=text,
font=font,
value=value,
variable=var,
# command=toggle_selection
)
radiobutton.place(x=x, y=y)
return radiobutton, var
def create_listbox(self, x, y, width=20, height=10, font=('黑体', 12)):
"""创建列表框"""
listbox = self.tk.Listbox(self.root, font=font, width=width, height=height)
listbox.place(x=x, y=y)
return listbox
def create_progressbar(self, x, y, length=200, mode='determinate', max_value=100):
"""创建进度条"""
progressbar = Progressbar(self.root, length=length, mode=mode, maximum=max_value)
progressbar.place(x=x, y=y)
return progressbar
def create_canvas(self, x, y, width=400, height=300, bg='white'):
"""创建画布"""
canvas = self.tk.Canvas(self.root, width=width, height=height, bg=bg)
canvas.place(x=x, y=y)
return canvas
def create_menu(self, menu_items):
"""创建菜单"""
menubar = self.tk.Menu(self.root)
for menu_name, commands in menu_items.items():
menu = self.tk.Menu(menubar, tearoff=0)
for command_name, command_func in commands.items():
menu.add_command(label=command_name, command=command_func)
menubar.add_cascade(label=menu_name, menu=menu)
self.root.config(menu=menubar)
def show_message(self, title, message, message_type='warning'):
"""显示提示框"""
if message_type == 'info':
self.tk.messagebox.showinfo(title=title, message=message)
elif message_type == 'error':
self.tk.messagebox.showerror(title=title, message=message)
else:
self.tk.messagebox.showwarning(title=title, message=message)
class Gui(GuiAttributes, GuiControl):
"""综合类,继承属性类和控件类"""
pass
class DemoApp(Gui):
"""综合示例应用"""
def update_progress(self, progressbar):
"""更新进度条"""
for i in range(101):
progressbar['value'] = i
self.root.update_idletasks()
def show_image(self):
"""展示图片"""
img = self.tk.PhotoImage(file="path_to_your_image.png")
label = self.create_label('', 50, 50)
label.config(image=img)
label.image = img # 防止图片被垃圾回收
def toggle_password_visibility(self):
"""切换密码明文/密文显示"""
entry = self.controls.get("password")
button = self.controls.get("toggle_button")
if entry.cget('show') == '*':
entry.configure(show='') # 明文显示
button.configure(text='●') # 更改按钮文字
else:
entry.configure(show='*') # 密文显示
button.configure(text='○') # 更改按钮文字
def setup_ui(self):
"""设置UI布局"""
self.create_label("请输入账号和密码:", x=50, y=20)
self.create_label("账号:", x=50, y=60)
self.create_label("密码:", x=50, y=100)
username_entry = self.create_entry(x=100, y=60)
self.controls["username"] = username_entry
password_entry = self.create_entry(x=100, y=100, show='*')
self.controls["password"] = password_entry
toggle_button = self.create_button("●", self.toggle_password_visibility, x=280, y=100)
self.controls["toggle_button"] = toggle_button
self.create_button("登录", self.submit, x=50, y=150)
self.create_button("退出", self.quit, x=200, y=150)
progressbar = self.create_progressbar(x=50, y=200)
self.create_button("开始进度", lambda: self.update_progress(progressbar), x=200, y=200)
checkbox, var = self.create_checkbox("记住我", x=50, y=250)
self.controls["remember_me"] = var
gender_var = self.tk.StringVar()
# 创建两个单选按钮,共享同一个变量
radiobutton1, _ = self.create_radiobutton("男", x=50, y=300, value="male", var=gender_var)
radiobutton2, _ = self.create_radiobutton("女", x=150, y=300, value="female", var=gender_var)
self.controls["gender"] = gender_var
# 下拉框
self.create_label("单选择您的城市:", x=210, y=250)
city_combobox = self.create_combobox(x=210, y=300, values=["北京", "上海", "广州", "深圳"], default_value="北京")
self.controls["city"] = city_combobox
listbox = self.create_listbox(x=50, y=350)
for item in ["选项A", "选项B", "选项C"]:
listbox.insert('end', item)
self.controls["options"] = listbox
self.create_label("多选您的兴趣:", x=210, y=350)
multiselect, selected_values = self.create_multiselect_combobox(
x=250, y=380, values=["音乐", "运动", "阅读", "旅行"], width=20
)
self.create_button(
"提交兴趣", lambda: self.show_message("兴趣", f"选中兴趣: {selected_values.get()}", "info"), x=50, y=550
)
# 菜单
self.create_menu({
"文件": {"新建": lambda: self.show_message('提示', '新建文件', 'info'),
"退出": self.quit},
"帮助": {"关于": lambda: self.show_message('关于', '这是一个示例应用', 'error')}
})
def submit(self):
"""提交按钮事件"""
username = self.controls.get("username").get()
password = self.controls.get("password").get()
if username == "admin" and password == "admin":
self.show_admin_page()
else:
self.show_message('错误', '账号或密码错误', 'error')
def show_admin_page(self):
"""显示管理员页面"""
self.root.destroy() # 销毁当前窗口
admin_app = Gui()
admin_app.set_title("管理员页面")
admin_app.set_geometry(400, 300)
admin_app.create_label("欢迎进入管理员页面", x=50, y=50)
admin_app.create_button("退出", admin_app.quit, x=50, y=150)
admin_app.show()
def show_admin_page(self):
"""展示管理员页面"""
# 清空现有窗口
for widget in self.root.winfo_children():
widget.destroy()
# 布局新的管理员页面
self.create_label("欢迎进入管理员页面", x=100, y=50, font=('黑体', 20))
self.create_button("退出", self.quit, x=150, y=150)
def main(self):
"""主入口"""
self.set_title("综合示例应用")
self.set_geometry(500,700)
self.set_bg_color("#f0f0f0")
self.set_resizable(False, False)
self.setup_ui()
self.show()
if __name__ == '__main__':
DemoApp().main()
运行效果
可以根据里面代码,进行定制化开发