Python 图形界面框架TkInter(第三篇:root window的理解)

前言

    我们每次创建Tkinter中的控件对象时,总需要为其指定一个master对象,它也称容器对象,表示控件需要放在哪个容器对象的内部,此举也防止了创建的控件对象被GC回收!

    如果你仔细观察,会发现控件对象的第一个默认值参数master也可以什么都不传,此时的控件同样会默认放置在表示当然窗口的Tk对象中,这是为什么呢?让我们从代码中一探究竟!

创建Button对象时,没有指定master

import tkinter

root_window = tkinter.Tk()

first_btn = tkinter.Button(text="第一个按钮")
first_btn.pack()

second_btn = tkinter.Button(text="第二个按钮")
second_btn.pack()

root_window.mainloop()

输出结果:

     两个Button可以在根窗口中正常显示

创建Button对象,指定放置在根窗口

…………省略…………
first_btn = tkinter.Button(root_window, text="第一个按钮")
…………省略…………
second_btn = tkinter.Button(root_window, text="第二个按钮")
…………省略…………

    为每个Button对象传入表示窗口的Tk对象,这才是正常创建Button的代码,但是为什么没有传递Tk对象的控件,也会默认放在根窗口上呢?我们继续试验……

先创建Button对象,后创建根窗口Tk对象会怎么样?

import tkinter

first_btn = tkinter.Button(text="第一个按钮")
first_btn.pack()
root_window = tkinter.Tk()

root_window.mainloop()

    这次我先创建的Button对象,然后才创建的Tk对象(表示 Root Window),那么tkinter会不会崩溃呢?

输出结果:

     哇塞,竟然创建了2个窗口?这是为什么?我们必须深入到源码中,一探究竟……

Button对象的创建

    def __init__(self, master=None, cnf={}, **kw):

        Widget.__init__(self, master, 'button', cnf, kw)

    首先是Button对象的__init__()方法被自动调用,在__init__()方法的内部它又调用了父类Widget的__init__()方法,我们马上看下Widget的__init__()方法做了什么?

    def __init__(self, master, widgetName, cnf={}, kw={}, extra=()):
          
            …………省略代码…………

        BaseWidget._setup(self, master, cnf)

            …………省略代码…………            

    省略了一部分无关代码,我们发现又调用了Widget的父类BaseWidget的_setup()方法,我们再进去看看这个_setup()方法做了什么?

    def _setup(self, master, cnf):
        if _support_default_root:
            global _default_root
            if not master:
                if not _default_root:
                    _default_root = Tk()
                master = _default_root
        self.master = master
         
        …………省略很多代码…………
    

    我把关键的代码贴出来了

1、首先检查是否支持默认root_window

全局变量_support_default_root的默认值是1,说明支持默认的root_window

2、检查是否指定了容器对象

如果没有指定master,会执行这段代码

                if not _default_root:
                    _default_root = Tk()
                master = _default_root

    注意,此时它首先判断全局变量_default_root是否已经创建Tk对象,如果没有创建Tk对象的话,它会执行Tk()创建一个新的根窗口Tk对象,这个全局变量_default_root在哪创建的?我们去Tk的代码中一探究竟

3、将_defulat_root赋值给局部变量master

4、局部变量master再将值赋值给实例变量master(这个实例变量,就是平时我们创建Button时指定的容器对象)

创建Tk对象(根窗口)

    def __init__(self, screenName=None, baseName=None, className='Tk',
                 useTk=1, sync=0, use=None):

        …………省略很多代码…………

        if useTk:
            self._loadtk()

        …………省略很多代码…………

    useTk这个默认值参数的默认值为1,所以接下来会调用一个当前实例方法_loadtk(),我们进去看看这个方法的实现

    def _loadtk(self):

        …………省略很多源码…………

        if _support_default_root and not _default_root:
            _default_root = self

        self.protocol("WM_DELETE_WINDOW", self.destroy)

    全局变量_support_default_root值为1,且_default_root还是指向一个None,注意接下来执行的一段代码

            _default_root = self

    果然我们的创建的Tk对象,会赋值给全局变量_default_root!原来_default_root指向的值是在我们创建Tk对象的时赋值的……

总结

1、如果我们先创建Tk()对象,此时没有指定容器对象的控件,比如Button(),Button会自动放置在全局变量_default_root指向的Tk对象里面,这个Tk对象是我们创建的。

结论:适用于所有的控件,创建控件对象时没有指定master,控件会默认放置在根窗口里面

2、如果我们先创建Button()对象,后创建一个Tk()对象,此时由于_default_root指向的是None,在Button的代码中会默认创建1个新的Tk()对象作为根窗口,此时我们会看到两个窗口同时显示,1个是Button中新创建的Tk对象,另一个是我们自己的创建的TK()对象(该条适用于所有的控件)

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值