偷师 IDLE 源码:Tkinter 如何创建模态、非模态窗口

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012814856/article/details/91365452

一、引言

最近在项目中编写了一些小工具,用到了 Tkinter 界面库。一些简单的界面相关的内容网上都能搜到,但是有关 Tkinter 如何创建一个模态、非模态窗口的资料却比较少(可能是大神都比较会自学吧 T_T)。这里,我通过阅读 Python 自带的 IDE IDLE 的源代码(界面库用的 Tkinter,是最好的 Tkinter 使用范例),找到了 Tkinter 创建模态、非模态窗口的方法。

想要知道如何找到 IDLE 源代码的同学,可以参考我这篇博客:
学习 Tkinter 最好的实例:Python 的 IDLE 源代码获取,以及初步试玩

这里,参考的是 IDLE 中菜单 Help 点击 About IDE 之后跳出来的 About IDE 模态窗口的代码:
1
2
其中源代码位置位于 help_about.py 中(负责 About IDE 模态窗口的创建与布局),macosc.py 负责绑定 About IDE 菜单命令与 help_about.py 中的窗口类的初始化显示触发。感兴趣的同学可以自己去看下这块代码。

以下,我简化这个模型,编写了一份简单易参考的代码,简单描述下 Python Tkinter 如何创建一个模态、非模态窗口。

二、示例

话不多说,直接上代码:

"""
Multi windows.
"""

from tkinter import Tk, Frame, Menu, Toplevel, X
from tkinter.ttk import Label


class Example(Frame):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.master.title("Multi windows")
        
        menubar = Menu(self.master)
        self.master.config(menu=menubar)
        
        fileMenu = Menu(menubar, tearoff=0)
        fileMenu.add_command(label="Modal", command=self.onModal)
        fileMenu.add_command(label="Exit", command=self.onExit)
        menubar.add_cascade(label="File", menu=fileMenu)

    def onModal(self):
        moddal = Modal(root, title="Modal")

    def onExit(self):
        self.quit()


class Modal(Toplevel):
    """
    Modal about dialog for this pragram.
    """
    def __init__(self, parent, title=None):
        """
        Create popup, do not return until widget destroyed.

        parent - parent of this dialog
        title - string which is title of popup dialog
        """
        Toplevel.__init__(self, parent, width=200, height=300)
        self.geometry("100x80+%d+%d" % (parent.winfo_rootx() + 30,
                                  parent.winfo_rooty() + 30))
        self.title(title)
        self.resizable(height=False, width=False)
        self.grab_set()
        self.initUI()

    def initUI(self):
        self.frame = Frame(self)
        self.frame.pack(fill=X, expand=True)

        lbl = Label(self.frame, text="这是模态窗口", width=10)
        lbl.pack(fill=X, padx=5, expand=True)


if __name__ == '__main__':
    root = Tk()
    root.geometry("250x150+300+300")
    app = Example()
    root.mainloop()

这篇博客默认你对 Tkinter 的基本内容有一定的了解,因此一些基本的布局、菜单命令的绑定我也就不谈了。

这块重点讲解 Modal 类,其中 Modal 类继承自 tkinter 库中的 Toplevel 类,用以显示顶层窗口。其中初始化函数 __init__ 参数最终要的是一个 parent 参数,其需要获取到当前窗口的句柄,也就是 root 参数。获取到它之后,使用 self.geometry 即可对模态窗口的位置大小进行设置。使用 self.title 即可实现标题的设置。

其中最重要的莫过于 self.grab_set() 函数,其是实现模态的关键所在,这行代码的含义是使得新建的窗口捕获所有的事件信息,一旦加上了这行代码,父窗口即无法再响应鼠标事件(不信可以尝试下还能否点击到父窗口的 File 菜单),去掉了这行代码,即可实现非模态窗口(即创建了子窗口,父窗口依然可以操作)。

最后,再编写一个 initUI() 函数实现个性化的界面配置,还是比较方便的。

效果如下:
3
完结撒花,希望本篇博客能给你带来一些帮助:)

展开阅读全文

没有更多推荐了,返回首页