Python tkinter 初探Toplevel控件搭建父子窗口
创始人
2025-01-09 15:33:48
0

目录

Toplevel控件搭建父子窗口

最简明的父子窗口框架

改进一:屏蔽和开放按钮

改进二:子窗口始终在主窗口之上

改进三:增加子窗口的关闭协议

改进四:使子窗口长获焦点

总结


Toplevel控件搭建父子窗口

最近,用Python给单位里用的“智慧食堂”系统编制了一个餐卡充值文件生成器,自动匹配餐卡号并快速生成导入数据用的Excel表格,截图如下:

使用tkinter Toplevel控件弹出子窗口,用作设置备注的子窗口。在编程过程中,边学边写探索到不少新知识,简单介绍如下:

最简明的父子窗口框架

创建一个主窗口、一个子窗口,各放一个按钮,代码如下:

import win32api, tkinter as tk  def _toplevel():     top = tk.Toplevel(root)     top.title("Toplevel Window")     W,H=400,300     top.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')      btn_Close = tk.Button(top, text="Close", command=top.destroy)     btn_Close.pack()    if __name__=='__main__':          # 创建主窗口     root = tk.Tk()     root.title("Main Window")     # 获取windows系统桌面分辨率     X,Y=win32api.GetSystemMetrics(0),win32api.GetSystemMetrics(1)     W,H=600,480     root.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')      # 创建一个打开Toplevel窗口的按钮     btn_Open = tk.Button(root, text="Open Toplevel", command=_toplevel)     btn_Open.pack()      # 运行Tkinter事件循环     root.mainloop()

上述代码的缺点是主窗口上的Open按钮可以反复点击打开多个子窗口,要想办法按需要来屏蔽它的点击功能。

改进一:屏蔽和开放按钮

以下代码可以调整按钮的使用状态:tk.DISABLED、tk.NORMAL

button.config(state=tk.DISABLED)
button.config(state=tk.NORMAL)

打开子窗口时,Open按钮的状态改为tk.DISABLED,此时已无法点击了。

import win32api, tkinter as tk    class TopWindow:     def __init__(self, parent):           top = self.top = tk.Toplevel(parent)         top.title("Toplevel Window")         W,H=400,300         top.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')         btn_Close = tk.Button(top, text="Close", command=self.on_close)         btn_Close.pack()     def on_close(self):         btn_Open.config(state=tk.NORMAL)         self.top.destroy()  def on_open():     TopWindow(root)     btn_Open.config(state=tk.DISABLED)  if __name__=='__main__':        root = tk.Tk()       root.title("Main Window")       X,Y=win32api.GetSystemMetrics(0),win32api.GetSystemMetrics(1)     W,H=600,480     root.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')      btn_Open = tk.Button(root, text="Open Toplevel", command=on_open)     btn_Open.pack()     root.mainloop()

改进二:子窗口始终在主窗口之上

top.transient(root)  # 设置Toplevel窗口始终在主窗口root的上方

import win32api, tkinter as tk    class TopWindow:     def __init__(self, parent):           top = self.top = tk.Toplevel(parent)         top.title("Toplevel Window")         W,H=400,300         top.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')         top.transient(root) # 设置Toplevel窗口始终在主窗口上方         btn_Close = tk.Button(top, text="Close", command=self.on_close)         btn_Close.pack()     def on_close(self):         btn_Open.config(state=tk.NORMAL)         self.top.destroy()  def on_open():     TopWindow(root)     btn_Open.config(state=tk.DISABLED)  if __name__=='__main__':        root = tk.Tk()       root.title("Main Window")       X,Y=win32api.GetSystemMetrics(0),win32api.GetSystemMetrics(1)     W,H=600,480     root.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')      btn_Open = tk.Button(root, text="Open Toplevel", command=on_open)     btn_Open.pack()     root.mainloop() 

另外一种方法也能设置子窗口永远在前:

top.wm_attributes('-topmost', True)  # 设置Toplevel窗口在所有窗口的上方

两种方法的区别在于后者是全局的设置,它使得子窗口在操作系统中所有窗口的上面,包括其它应用程序的窗口。

如下图,请比较一下与上一张截图的效果有啥区别:

改进三:增加子窗口的关闭协议

如下图,直接点击子窗口右上关闭按钮,只触发窗口默认的top.destroy事件。这样关闭子窗口后,主窗口的按钮状态并不能恢复;以下代码使得子窗口的"WM_DELETE_WINDOW"关闭协议绑定了自定义的关闭事件self.onclose:

top.protocol("WM_DELETE_WINDOW", self.on_close)

完整代码如下:

import win32api, tkinter as tk    class TopWindow:     def __init__(self, parent):           top = self.top = tk.Toplevel(parent)         top.title("Toplevel Window")         W,H=400,300         top.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')         top.transient(root)         top.protocol("WM_DELETE_WINDOW", self.on_close)         btn_Close = tk.Button(top, text="Close", command=self.on_close)         btn_Close.pack()     def on_close(self):         btn_Open.config(state=tk.NORMAL)         self.top.destroy()  def on_open():     TopWindow(root)     btn_Open.config(state=tk.DISABLED)  if __name__=='__main__':        root = tk.Tk()       root.title("Main Window")       X,Y=win32api.GetSystemMetrics(0),win32api.GetSystemMetrics(1)     W,H=600,480     root.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')      btn_Open = tk.Button(root, text="Open Toplevel", command=on_open)     btn_Open.pack()     root.mainloop() 

改进四:使子窗口长获焦点

top.grab_set()  # 确保Toplevel窗口长获焦点

使用这个方法,前面提到的按钮状态的切换以及子窗口绑定关闭协议的代码都不需要了,非常简洁。top.grab_set() 配合 top.transient(root) 共同使用(如下标注红色部分),效果最佳:

import win32api, tkinter as tk 

class TopWindow:
    def __init__(self, parent):  
        top = self.top = tk.Toplevel(parent)
        top.title("Toplevel Window")
        W,H=400,300
        top.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')
        top.grab_set()
        top.transient(root)

        btn_Close = tk.Button(top, text="Close", command=top.destroy)
        btn_Close.pack()

def on_open():
    TopWindow(root)

if __name__=='__main__':  

    root = tk.Tk()  
    root.title("Main Window")  
    X,Y=win32api.GetSystemMetrics(0),win32api.GetSystemMetrics(1)
    W,H=600,480
    root.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')

    btn_Open = tk.Button(root, text="Open Toplevel", command=on_open)
    btn_Open.pack()
    root.mainloop()


源代码复制框如下:

import win32api, tkinter as tk    class TopWindow:     def __init__(self, parent):           top = self.top = tk.Toplevel(parent)         top.title("Toplevel Window")         W,H=400,300         top.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')         top.grab_set()         top.transient(root)         btn_Close = tk.Button(top, text="Close", command=top.destroy)         btn_Close.pack()  def on_open():     TopWindow(root)  if __name__=='__main__':        root = tk.Tk()       root.title("Main Window")       X,Y=win32api.GetSystemMetrics(0),win32api.GetSystemMetrics(1)     W,H=600,480     root.geometry(f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}')      btn_Open = tk.Button(root, text="Open Toplevel", command=on_open)     btn_Open.pack()     root.mainloop()

总结

通过对toplevel控件的编程操练,掌握了tkinter子窗口的调用方法,了解了topleve的多种特殊方法、响应事件以及绑定协议。

相关内容

热门资讯

黑科技中牌率(扑克时间)微扑克... 1、黑科技中牌率(扑克时间)微扑克机器人切实是有挂!太实锤了其实是真的有挂(2023已更新)(哔哩哔...
2分钟了解!微扑克必胜技巧,越... 2分钟了解!微扑克必胜技巧,越乡游斗牛怎么开挂,我来教教你(证实有挂)-哔哩哔哩1、用户打开应用后不...
黑科技科技(Wepoke盈利)... 1、黑科技科技(Wepoke盈利)poker总是是有挂!太夸张了原生有挂(2026已更新)(哔哩哔哩...
2分钟了解!微扑克ai辅助器,... 2分钟了解!微扑克ai辅助器,闲逸棋牌挂,扑克教程(有挂技巧)-哔哩哔哩1、这是跨平台的闲逸棋牌挂黑...
黑科技实锤(德扑之星刷数据)w... 《黑科技实锤(德扑之星刷数据)wpk德州扑克都是真的是有挂!太离谱了原来有挂(2026已更新)(哔哩...
第9分钟了解!wpk智能ai,... 第9分钟了解!wpk智能ai,吉祥麻将跑得快怎么拿好牌,德州论坛(果真有挂)-哔哩哔哩;1、吉祥麻将...
黑科技好牌(德扑查数据)aap... aapoKER新手教程相关信息汇总(需添加指定威信136704302获取下载链接);黑科技好牌(德扑...
7分钟了解!微扑克有辅助挂吗,... 7分钟了解!微扑克有辅助挂吗,波特互娱有挂吗,AI教程(有挂教学)-哔哩哔哩;进入游戏-大厅左侧-新...
黑科技好牌(线上德州ai机器人... 黑科技好牌(线上德州ai机器人)wepoker原本是真的有挂!太夸张了往昔存在有挂(2024已更新)...
1分钟了解!红龙扑克发牌有问题... 1分钟了解!红龙扑克发牌有问题,掌心麻将圈软挂神器,安装教程(了解有挂)-哔哩哔哩1、在红龙扑克发牌...