Python GUI编程之tkinter模块Toplevel控件实现搭建父子窗口

 更新时间:2023年12月30日 09:21:52   作者:Hann Yang  
这篇文章主要介绍了Python使用tkinter模块Toplevel控件搭建父子窗口的实现方法,Tkinter是Python的标准GUI库,Python使用Tkinter可以快速的创建GUI应用程序,用到相关控件的同学可以参考下

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的多种特殊方法、响应事件以及绑定协议。

到此这篇关于Python GUI编程之tkinter模块Toplevel控件实现搭建父子窗口的文章就介绍到这了,更多相关Python Toplevel搭建父子窗口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python机器学习从ResNet到DenseNet示例详解

    Python机器学习从ResNet到DenseNet示例详解

    ResNet极大地改变了如何参数化深层网络中函数的观点。稠密连接网络(DenseNet)在某种程度上是ResNet的逻辑扩展。让我们先从数学上了解下
    2021-10-10
  • Python脚本实现随机数据生成自由详解

    Python脚本实现随机数据生成自由详解

    这篇文章主要为大家详细介绍了Python如何通过脚本实现随机数据生成自由,文中的示例代码讲解详细,感兴趣的小伙伴快跟随小编一起学习一下吧
    2023-12-12
  • 使用Python实现提取快递信息

    使用Python实现提取快递信息

    这篇文章主要为大家详细介绍了如何使用Python调用快递查询API接口,并提取出我们需要的快递信息,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-04-04
  • 使用Python实现桥接模式的代码详解

    使用Python实现桥接模式的代码详解

    桥接模式是一种结构型设计模式,它将抽象部分与其实现部分分离,使它们都可以独立地变化,本文将给大家介绍如何使用Python实现桥接模式,需要的朋友可以参考下
    2024-02-02
  • Python引用传值概念与用法实例小结

    Python引用传值概念与用法实例小结

    这篇文章主要介绍了Python引用传值概念与用法,简单分析了Python引用传值的概念、功能并结合实例形式总结分析了Python引用传值的具体实现与使用方法,需要的朋友可以参考下
    2017-10-10
  • python os.path.isfile 的使用误区详解

    python os.path.isfile 的使用误区详解

    今天小编就为大家分享一篇python os.path.isfile 的使用误区详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • Python使用draw类绘制图形示例讲解

    Python使用draw类绘制图形示例讲解

    这篇文章主要介绍了Python使用draw类绘制图形的哪些函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • python求加权平均值的实例(附纯python写法)

    python求加权平均值的实例(附纯python写法)

    今天小编就为大家分享一篇python求加权平均值的实例(附纯python写法),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • Python pandas删除指定行/列数据的方法实例

    Python pandas删除指定行/列数据的方法实例

    这篇文章主要给大家介绍了关于Python pandas删除指定行/列数据的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • Windows下搭建python开发环境详细步骤

    Windows下搭建python开发环境详细步骤

    这篇文章主要为大家详细介绍了Windows下搭建python开发环境,文中安装步骤介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-05-05

最新评论