首页 > Python基础教程 > Tkinter
阅读:3,081
Python Tkinter自定义对话框(模式和非模式)
从前面章节的介绍可以看到,不管是使用 SimpleDialog 还是 Dialog,整个对话框的布局都是比较固定的,开发者只能为其指定 title、text 等选项,如果希望在对话框中添加其他组件,这就很难实现了。另外,SimpleDialog 和 Dialog 都是模式的。
如果开发者需要使用自定义的对话框,包括定制模式和非模式行为,则可通过继承 Toplevel 来实现。如果打算通过这种方式来实现自定义对话框,有两点要注意:
下面程序示范了自定义模式和非模式对话框:
至于 MyDialog 类中的 ok_click、cancel_click,则是程序为对话框按钮所绑定的事件处理方法。这不是固定的,程序下方有几个按钮,通常就需要为几个按钮绑定事件处理方法。
上面程序通过 MyDialog 创建了模式对话框和非模式对话框。运行该程序,单击界面上的“模式对话框”按钮,程序弹出如图 1 所示的自定义对话框。

图 1 模式对话框
在该模式对话框没有关闭的情况下,该程序的主窗口将无法与用户交互,主窗口无法获得焦点。
如果单击界面上的“非模式对话框”按钮,程序也弹出类似于图 1 所示的自定义对活框,但这个对话框是非模式对话框,即使在该对话框没有关闭的情况下,用户也依然可以与程序的主窗口交互,主窗口可以获得焦点。
如果开发者需要使用自定义的对话框,包括定制模式和非模式行为,则可通过继承 Toplevel 来实现。如果打算通过这种方式来实现自定义对话框,有两点要注意:
- 继承 Toplevel 来实现自定义对话框同样需要为对话框指定 master。
- 程序可调用 Toplevel 的 grab_set() 方法让该对话框变成模式对话框,否则就是非模式对话框。
下面程序示范了自定义模式和非模式对话框:
from tkinter import *
# 导入ttk
from tkinter import ttk
from tkinter import messagebox
# 自定义对话框类,继承Toplevel
class MyDialog(Toplevel):
# 定义构造方法
def __init__(self, parent, title = None, modal=True):
Toplevel.__init__(self, parent)
self.transient(parent)
# 设置标题
if title: self.title(title)
self.parent = parent
self.result = None
# 创建对话框的主体内容
frame = Frame(self)
# 调用init_widgets方法来初始化对话框界面
self.initial_focus = self.init_widgets(frame)
frame.pack(padx=5, pady=5)
# 调用init_buttons方法初始化对话框下方的按钮
self.init_buttons()
# 根据modal选项设置是否为模式对话框
if modal: self.grab_set()
if not self.initial_focus:
self.initial_focus = self
# 为"WM_DELETE_WINDOW"协议使用self.cancel_click事件处理方法
self.protocol("WM_DELETE_WINDOW", self.cancel_click)
# 根据父窗口来设置对话框的位置
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
print( self.initial_focus)
# 让对话框获取焦点
self.initial_focus.focus_set()
self.wait_window(self)
# 通过该方法来创建自定义对话框的内容
def init_widgets(self, master):
# 创建并添加Label
Label(master, text='用户名', font=12,width=10).grid(row=1, column=0)
# 创建并添加Entry,用于接受用户输入的用户名
self.name_entry = Entry(master, font=16)
self.name_entry.grid(row=1, column=1)
# 创建并添加Label
Label(master, text='密 码', font=12,width=10).grid(row=2, column=0)
# 创建并添加Entry,用于接受用户输入的密码
self.pass_entry = Entry(master, font=16)
self.pass_entry.grid(row=2, column=1)
# 通过该方法来创建对话框下方的按钮框
def init_buttons(self):
f = Frame(self)
# 创建"确定"按钮,位置绑定self.ok_click处理方法
w = Button(f, text="确定", width=10, command=self.ok_click, default=ACTIVE)
w.pack(side=LEFT, padx=5, pady=5)
# 创建"确定"按钮,位置绑定self.cancel_click处理方法
w = Button(f, text="取消", width=10, command=self.cancel_click)
w.pack(side=LEFT, padx=5, pady=5)
self.bind("<Return>", self.ok_click)
self.bind("<Escape>", self.cancel_click)
f.pack()
# 该方法可对用户输入的数据进行校验
def validate(self):
# 可重写该方法
return True
# 该方法可处理用户输入的数据
def process_input(self):
user_name = self.name_entry.get()
user_pass = self.pass_entry.get()
messagebox.showinfo(message='用户输入的用户名: %s, 密码: %s'
% (user_name , user_pass))
def ok_click(self, event=None):
print('确定')
# 如果不能通过校验,让用户重新输入
if not self.validate():
self.initial_focus.focus_set()
return
self.withdraw()
self.update_idletasks()
# 获取用户输入数据
self.process_input()
# 将焦点返回给父窗口
self.parent.focus_set()
# 销毁自己
self.destroy()
def cancel_click(self, event=None):
print('取消')
# 将焦点返回给父窗口
self.parent.focus_set()
# 销毁自己
self.destroy()
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
# 创建2个按钮,并为之绑定事件处理函数
ttk.Button(self.master, text='模式对话框',
command=self.open_modal # 绑定open_modal方法
).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='非模式对话框',
command=self.open_none_modal # 绑定open_none_modal方法
).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
def open_modal(self):
d = MyDialog(self.master, title='模式对话框') # 默认是模式对话框
def open_none_modal(self):
d = MyDialog(self.master, title='非模式对话框', modal=False)
root = Tk()
root.title("颜色对话框测试")
App(root)
root.mainloop()
上面程序定义了一个父类为 Toplevel 的 MyDialog 类,该类就是一个自定义对话框类,读者以后完全可以复用这个 MyDialog 类。该对话框的主体包含两个方法:
- init_widgets:该方法用于初始化对话框的主体界面组件。
- init_buttons:该方法用于初始化对话框下方的多个按钮组件。
至于 MyDialog 类中的 ok_click、cancel_click,则是程序为对话框按钮所绑定的事件处理方法。这不是固定的,程序下方有几个按钮,通常就需要为几个按钮绑定事件处理方法。
上面程序通过 MyDialog 创建了模式对话框和非模式对话框。运行该程序,单击界面上的“模式对话框”按钮,程序弹出如图 1 所示的自定义对话框。

图 1 模式对话框
在该模式对话框没有关闭的情况下,该程序的主窗口将无法与用户交互,主窗口无法获得焦点。
如果单击界面上的“非模式对话框”按钮,程序也弹出类似于图 1 所示的自定义对活框,但这个对话框是非模式对话框,即使在该对话框没有关闭的情况下,用户也依然可以与程序的主窗口交互,主窗口可以获得焦点。
所有教程
- socket
- Python基础教程
- C#教程
- MySQL函数
- MySQL
- C语言入门
- C语言专题
- C语言编译器
- C语言编程实例
- GCC编译器
- 数据结构
- C语言项目案例
- C++教程
- OpenCV
- Qt教程
- Unity 3D教程
- UE4
- STL
- Redis
- Android教程
- JavaScript
- PHP
- Mybatis
- Spring Cloud
- Maven
- vi命令
- Spring Boot
- Spring MVC
- Hibernate
- Linux
- Linux命令
- Shell脚本
- Java教程
- 设计模式
- Spring
- Servlet
- Struts2
- Java Swing
- JSP教程
- CSS教程
- TensorFlow
- 区块链
- Go语言教程
- Docker
- 编程笔记
- 资源下载
- 关于我们
- 汇编语言
- 大数据
- 云计算
- VIP视频