"tkinter" —— Tcl/Tk 的 Python 接口
**********************************

**源代码:** Lib/tkinter/__init__.py

======================================================================

"tkinter" 包 ("Tk 接口") 是针对 Tcl/Tk GUI 工具包的标准 Python 接口。
Tk 和 "tkinter" 在大多数 Unix 平台，包括 macOS，以及 Windows 系统上均
可使用。

若在命令行执行 "python -m tkinter"，应会弹出一个简单的 Tk 界面窗口，
表明 "tkinter" 包已安装完成，还会显示当前安装的 Tcl/Tk 版本，以便阅读
对应版本的 Tcl/Tk 文档。

参见:

  * TkDocs
       关于使用 Tkinter 创建用户界面的详细教程。 讲解了关键概念，并介
       绍了使用现代 API 的推荐方式。

  * Tkinter 8.5 参考手册：一种 Python GUI
       详细讲解可用的类、方法和选项的 Tkinter 8.5 参考文档。

  Tcl/Tk 资源:

  * Tk 命令
       有关 Tkinter 所使用的每个底层 Tcl/Tk 命令的完整参考文档。

  * Tcl/Tk 主页
       额外的文档，以及 Tcl/Tk 核心开发相关链接。

  书籍:

  * Modern Tkinter for Busy Python Developers
       Mark Roseman 著。 (ISBN 978-1999149567)

  * Python and Tkinter Programming
       Alan Moore 著。 (ISBN 978-1788835886)

  * Programming Python
       Mark Lutz 著；对 Tkinter 进行了精彩的讲解。 (ISBN
       978-0596158101)

  * Tcl and the Tk Toolkit (2nd edition)
       John Ousterhout ，Tcl/Tk 的创造者，与 Ken Jones 合著；未涉及
       Tkinter。 (ISBN 978-0321336330)


Tkinter 模块
============

对 Tkinter 的支持分布在多个模块中。 大多数应用程序将需要主模块
"tkinter"，以及 "tkinter.ttk" 模块，后者提供了带主题的现代部件集及相应
的 API:

   from tkinter import *
   from tkinter import ttk

class tkinter.Tk(screenName=None, baseName=None, className='Tk', useTk=True, sync=False, use=None)

   构造一个最高层级的 Tk 部件，这通常是一个应用程序的主窗口，并为这个
   部件初始化 Tcl 解释器。 每个实例都有其各自所关联的 Tcl 解释器。

   "Tk" 类通常全部使用默认值来初始化。 不过，目前还可识别下列关键字参
   数:

   *screenName*
      当（作为字符串）给出时，设置 "DISPLAY" 环境变量。 （仅限 X11）

   *baseName*
      预置文件的名称。 在默认情况下，*baseName* 是来自于程序名称
      ("sys.argv[0]")。

   *className*
      控件类的名称。 会被用作预置文件同时也作为 Tcl 唤起的名称
      (*interp* 中的 *argv0*)。

   *useTk*
      如果为 "True"，则初始化 Tk 子系统。 "tkinter.Tcl()" 函数会将其设
      为 "False"。

   *sync*
      如果为 "True"，则同步执行所有 X 服务器命令，以便立即报告错误。
      可被用于调试。 （仅限 X11）

   *use*
      指定嵌入应用程序的窗口 *id*，而不是将其创建为独立的顶层窗口。
      *id* 必须以与顶层控件的 -use 选项值相同的方式来指定（也就是说，
      它具有与 "winfo_id()" 的返回值相同的形式）。

      请注意在某些平台上只有当 *id* 是指向一个启用了 -container 选项的
      Tk 框架或顶层窗口时此参数才能正确生效。

   "Tk" 读取并解释预置文件，其名称为 ".*className*.tcl" 和
   ".*baseName*.tcl"，进入 Tcl 解释器并基于 ".*className*.py" 在
   ".*baseName*.py" 的内容调用 "exec()"。 预置文件的路径为 "HOME" 环境
   变量，或者如果它未被设置，则为 "os.curdir"。

   tk

      通过实例化 "Tk" 创建的 Tk 应用程序对象。 这提供了对 Tcl 解释器的
      访问。 每个被附加到相同 "Tk" 实例的控件都具有相同的 "tk" 属性值
      。

   master

      包含此控件的控件对象。 对于 "Tk"，*master* 将为 "None" 因为它是
      主窗口。 术语 *master* 和 *parent* 是类似的且有时作为参数名称被
      交替使用；但是，调用 "winfo_parent()" 将返回控件名称字符串而
      "master" 将返回控件对象。 *parent*/*child* 反映了树型关系而
      *master*/*slave* 反映了容器结构。

   children

      以 "dict" 表示的此控件的直接下级其中的键为子控件名称而值为子实例
      对象。

tkinter.Tcl(screenName=None, baseName=None, className='Tk', useTk=False)

   "Tcl()" 函数是一个工厂函数，它创建的对象类似于 "Tk" 类创建的，只是
   不会初始化 Tk 子系统。这在调动 Tcl 解释器时最为有用，这时不想创建多
   余的顶层窗口，或者无法创建（比如不带 X 服务的 Unix/Linux 系统）。由
   "Tcl()" 创建的对象可调用 "loadtk()" 方法创建一个顶层窗口（且会初始
   化 Tk 子系统）。

提供 Tk 支持的模块包括:

"tkinter"
   主 Tkinter 模块。

"tkinter.colorchooser"
   让用户选择颜色的对话框。

"tkinter.commondialog"
   本文其他模块定义的对话框的基类。

"tkinter.filedialog"
   允许用户指定文件的通用对话框，用于打开或保存文件。

"tkinter.font"
   帮助操作字体的工具。

"tkinter.messagebox"
   访问标准的 Tk 对话框。

"tkinter.scrolledtext"
   内置纵向滚动条的文本组件。

"tkinter.simpledialog"
   基础对话框和一些便捷功能。

"tkinter.ttk"
   在 Tk 8.5 中引入的带主题的控件集，提供了对应于 "tkinter" 模块中许多
   经典控件的现代替代。

附加模块:

"_tkinter"
   一个包含低层级 Tcl/Tk 接口的二进制模块。 它会被主 "tkinter" 模块自
   动导入，且永远不应被应用程序员所直接使用。 它通常是一个共享库（或
   DLL），但在某些情况下可能被动态链接到 Python 解释器。

"idlelib"
   Python 的集成开发与学习环境（IDLE）。 基于 "tkinter"。

"tkinter.constants"
   当向 Tkinter 调用传入各种形参时可被用来代替字符串的符号常量。 由主
   "tkinter" 模块自动导入。

"tkinter.dnd"
   针对 "tkinter" 的（实验性的）拖放支持。 当以 Tk DND 代替时它将会被
   弃用。

"tkinter.tix"
   （已弃用）一个增加了部分新控件的较老的第三方 Tcl/Tk 包。 对多数人来
   说可以在 "tkinter.ttk" 中找到更好的替代品。

"turtle"
   Tk 窗口中的海龟绘图库。


Tkinter 拾遗
============

This section is not designed to be an exhaustive tutorial on either Tk
or Tkinter.  Rather, it is intended as a stop gap, providing some
introductory orientation on the system.

Credits:

* Tk was written by John Ousterhout while at Berkeley.

* Tkinter was written by Steen Lumholt and Guido van Rossum.

* This Life Preserver was written by Matt Conway at the University of
  Virginia.

* The HTML rendering, and some liberal editing, was produced from a
  FrameMaker version by Ken Manheimer.

* Fredrik Lundh elaborated and revised the class interface
  descriptions, to get them current with Tk 4.2.

* Mike Clarkson converted the documentation to LaTeX, and compiled the
  User Interface chapter of the reference manual.


How To Use This Section
-----------------------

This section is designed in two parts: the first half (roughly) covers
background material, while the second half can be taken to the
keyboard as a handy reference.

When trying to answer questions of the form "how do I do blah", it is
often best to find out how to do "blah" in straight Tk, and then
convert this back into the corresponding "tkinter" call. Python
programmers can often guess at the correct Python command by looking
at the Tk documentation. This means that in order to use Tkinter, you
will have to know a little bit about Tk. This document can't fulfill
that role, so the best we can do is point you to the best
documentation that exists. Here are some hints:

* The authors strongly suggest getting a copy of the Tk man pages.
  Specifically, the man pages in the "manN" directory are most useful.
  The "man3" man pages describe the C interface to the Tk library and
  thus are not especially helpful for script writers.

* Addison-Wesley publishes a book called Tcl and the Tk Toolkit by
  John Ousterhout (ISBN 0-201-63337-X) which is a good introduction to
  Tcl and Tk for the novice.  The book is not exhaustive, and for many
  details it defers to the man pages.

* "tkinter/__init__.py" is a last resort for most, but can be a good
  place to go when nothing else makes sense.


A Simple Hello World Program
----------------------------

   import tkinter as tk

   class Application(tk.Frame):
       def __init__(self, master=None):
           super().__init__(master)
           self.master = master
           self.pack()
           self.create_widgets()

       def create_widgets(self):
           self.hi_there = tk.Button(self)
           self.hi_there["text"] = "Hello World\n(click me)"
           self.hi_there["command"] = self.say_hi
           self.hi_there.pack(side="top")

           self.quit = tk.Button(self, text="QUIT", fg="red",
                                 command=self.master.destroy)
           self.quit.pack(side="bottom")

       def say_hi(self):
           print("hi there, everyone!")

   root = tk.Tk()
   app = Application(master=root)
   app.mainloop()


A (Very) Quick Look at Tcl/Tk
=============================

The class hierarchy looks complicated, but in actual practice,
application programmers almost always refer to the classes at the very
bottom of the hierarchy.

注释：

* These classes are provided for the purposes of organizing certain
  functions under one namespace. They aren't meant to be instantiated
  independently.

* The "Tk" class is meant to be instantiated only once in an
  application. Application programmers need not instantiate one
  explicitly, the system creates one whenever any of the other classes
  are instantiated.

* The "Widget" class is not meant to be instantiated, it is meant only
  for subclassing to make "real" widgets (in C++, this is called an
  'abstract class').

To make use of this reference material, there will be times when you
will need to know how to read short passages of Tk and how to identify
the various parts of a Tk command.   (See section Mapping Basic Tk
into Tkinter for the "tkinter" equivalents of what's below.)

Tk scripts are Tcl programs.  Like all Tcl programs, Tk scripts are
just lists of tokens separated by spaces.  A Tk widget is just its
*class*, the *options* that help configure it, and the *actions* that
make it do useful things.

To make a widget in Tk, the command is always of the form:

   classCommand newPathname options

*classCommand*
   denotes which kind of widget to make (a button, a label, a menu...)

*newPathname*
   is the new name for this widget.  All names in Tk must be unique.
   To help enforce this, widgets in Tk are named with *pathnames*,
   just like files in a file system.  The top level widget, the
   *root*, is called "." (period) and children are delimited by more
   periods.  For example, ".myApp.controlPanel.okButton" might be the
   name of a widget.

*options*
   configure the widget's appearance and in some cases, its behavior.
   The options come in the form of a list of flags and values. Flags
   are preceded by a '-', like Unix shell command flags, and values
   are put in quotes if they are more than one word.

例如：

   button   .fred   -fg red -text "hi there"
      ^       ^     \______________________/
      |       |                |
    class    new            options
   command  widget  (-opt val -opt val ...)

Once created, the pathname to the widget becomes a new command.  This
new *widget command* is the programmer's handle for getting the new
widget to perform some *action*.  In C, you'd express this as
someAction(fred, someOptions), in C++, you would express this as
fred.someAction(someOptions), and in Tk, you say:

   .fred someAction someOptions

Note that the object name, ".fred", starts with a dot.

As you'd expect, the legal values for *someAction* will depend on the
widget's class: ".fred disable" works if fred is a button (fred gets
greyed out), but does not work if fred is a label (disabling of labels
is not supported in Tk).

The legal values of *someOptions* is action dependent.  Some actions,
like "disable", require no arguments, others, like a text-entry box's
"delete" command, would need arguments to specify what range of text
to delete.


Mapping Basic Tk into Tkinter
=============================

Class commands in Tk correspond to class constructors in Tkinter.

   button .fred                =====>  fred = Button()

The master of an object is implicit in the new name given to it at
creation time.  In Tkinter, masters are specified explicitly.

   button .panel.fred          =====>  fred = Button(panel)

The configuration options in Tk are given in lists of hyphened tags
followed by values.  In Tkinter, options are specified as keyword-
arguments in the instance constructor, and keyword-args for configure
calls or as instance indices, in dictionary style, for established
instances.  See section 可选配置项 on setting options.

   button .fred -fg red        =====>  fred = Button(panel, fg="red")
   .fred configure -fg red     =====>  fred["fg"] = red
                               OR ==>  fred.config(fg="red")

In Tk, to perform an action on a widget, use the widget name as a
command, and follow it with an action name, possibly with arguments
(options).  In Tkinter, you call methods on the class instance to
invoke actions on the widget.  The actions (methods) that a given
widget can perform are listed in "tkinter/__init__.py".

   .fred invoke                =====>  fred.invoke()

To give a widget to the packer (geometry manager), you call pack with
optional arguments.  In Tkinter, the Pack class holds all this
functionality, and the various forms of the pack command are
implemented as methods.  All widgets in "tkinter" are subclassed from
the Packer, and so inherit all the packing methods. See the
"tkinter.tix" module documentation for additional information on the
Form geometry manager.

   pack .fred -side left       =====>  fred.pack(side="left")


How Tk and Tkinter are Related
==============================

From the top down:

Your App Here (Python)
   A Python application makes a "tkinter" call.

tkinter (Python Package)
   This call (say, for example, creating a button widget), is
   implemented in the "tkinter" package, which is written in Python.
   This Python function will parse the commands and the arguments and
   convert them into a form that makes them look as if they had come
   from a Tk script instead of a Python script.

_tkinter (C)
   These commands and their arguments will be passed to a C function
   in the "_tkinter" - note the underscore - extension module.

Tk Widgets (C and Tcl)
   This C function is able to make calls into other C modules,
   including the C functions that make up the Tk library.  Tk is
   implemented in C and some Tcl. The Tcl part of the Tk widgets is
   used to bind certain default behaviors to widgets, and is executed
   once at the point where the Python "tkinter" package is imported.
   (The user never sees this stage).

Tk (C)
   The Tk part of the Tk Widgets implement the final mapping to ...

Xlib (C)
   the Xlib library to draw graphics on the screen.


快速参考
========


可选配置项
----------

配置参数可以控制组件颜色和边框宽度等。可通过三种方式进行设置：

在对象创建时，使用关键字参数
      fred = Button(self, fg="red", bg="blue")

在对象创建后，将参数名用作字典索引
      fred["fg"] = "red"
      fred["bg"] = "blue"

利用 config() 方法修改对象的多个属性
      fred.config(fg="red", bg="blue")

关于这些参数及其表现的完整解释，请参阅 Tk 手册中有关组件的 man 帮助页
。

请注意，man 手册页列出了每个部件的“标准选项”和“组件特有选项”。前者是很
多组件通用的选项列表，后者是该组件特有的选项。标准选项在  *options(3)*
man 手册中有文档。

本文没有区分标准选项和部件特有选项。有些选项不适用于某类组件。组件是否
对某选项做出响应，取决于组件的类别；按钮组件有一个 "command" 选项，而
标签组件就没有。

组件支持的选项在其手册中有列出，也可在运行时调用 "config()" 方法（不带
参数）查看，或者通过调用组件的 "keys()" 方法进行查询。这些调用的返回值
为字典，字典的键是字符串格式的选项名（比如 "'relief'"），字典的值为五
元组。

有些选项，比如 "bg" 是全名通用选项的同义词（"bg" 是 “background”的简写
）。向 "config()" 方法传入选项的简称将返回一个二元组，而不是五元组。传
回的二元组将包含同义词的全名和“真正的”选项（比如 "('bg',
'background')"）。

+---------+-----------------------------------+----------------+
| 索引    | 含意                              | 示例           |
|=========|===================================|================|
| 0       | 选项名称                          | "'relief'"     |
+---------+-----------------------------------+----------------+
| 1       | 数据库查找的选项名称              | "'relief'"     |
+---------+-----------------------------------+----------------+
| 2       | 数据库查找的选项类                | "'Relief'"     |
+---------+-----------------------------------+----------------+
| 3       | 默认值                            | "'raised'"     |
+---------+-----------------------------------+----------------+
| 4       | 当前值                            | "'groove'"     |
+---------+-----------------------------------+----------------+

示例:

   >>> print(fred.config())
   {'relief': ('relief', 'relief', 'Relief', 'raised', 'groove')}

当然，输出的字典将包含所有可用选项及其值。这里只是举个例子。


包装器
------

包装器是 Tk 的形状管理机制之一。 形状（geometry ）管理器用于指定多个部
件在容器（共同的 *主* 组件）内的相对位置。与更为麻烦的 *定位器* 相比（
不太常用，这里不做介绍），包装器可接受定性的相对关系—— *上面* 、*左边*
、*填充* 等，并确定精确的位置坐标。

*主* 部件的大小都由其内部的 “从属部件” 的大小决定。包装器用于控制从属
部件在主部件中出现的位置。可以把部件包入框架，再把框架包入其他框架中，
搭建出所需的布局。此外，只要完成了包装，组件的布局就会进行动态调整，以
适应布局参数的变化。

请注意，只有用形状管理器指定几何形状后，部件才会显示出来。忘记设置形状
参数是新手常犯的错误，惊讶于创建完部件却啥都没出现。部件只有在应用了类
似于打包器的 "pack()" 方法之后才会显示在屏幕上。

调用 pack() 方法时可以给出由关键字/参数值组成的键值对，以便控制组件在
其容器中出现的位置，以及主程序窗口大小变动时的行为。下面是一些例子：

   fred.pack()                     # defaults to side = "top"
   fred.pack(side="left")
   fred.pack(expand=1)


包装器的参数
------------

关于包装器及其可接受的参数，更多信息请参阅 man 手册和 John Ousterhout
书中的第 183 页。

anchor
   anchor 类型。 表示包装器要放置的每个从属组件的位置。

expand
   布尔型，"0" 或 "1" 。

fill
   合法值为："'x'" 、"'y'" 、"'both'" 、"'none'"。

ipadx 和 ipady
   距离值，指定从属部件的内边距。

padx 和 pady
   距离值，指定从属部件的外边距。

side
   合法值为："'left'"、 "'right'" 、 "'top'"、 "'bottom'"。


部件与变量的关联
----------------

通过一些特定参数，某些组件（如文本输入组件）的当前设置可直接与应用程序
的变量关联。这些参数包括 "variable" 、 "textvariable" 、 "onvalue" 、
"offvalue"  、 "value"。这种关联是双向的：只要这些变量因任何原因发生变
化，其关联的部件就会更新以反映新的参数值。

不幸的是，在目前 "tkinter" 的实现代码中，不可能通过 "variable" 或
"textvariable" 参数将任意 Python 变量移交给组件。变量只有是 "tkinter"
中定义的 Variable 类的子类，才能生效。

已经定义了很多有用的 Variable 子类： "StringVar" 、 "IntVar" 、
"DoubleVar" 和 "BooleanVar"。调用 "get()" 方法可以读取这些变量的当前值
；调用 "set()" 方法则可改变变量值。只要遵循这种用法，组件就会保持跟踪
变量的值，而不需要更多的干预。

例如：

   import tkinter as tk

   class App(tk.Frame):
       def __init__(self, master):
           super().__init__(master)
           self.pack()

           self.entrythingy = tk.Entry()
           self.entrythingy.pack()

           # Create the application variable.
           self.contents = tk.StringVar()
           # Set it to some value.
           self.contents.set("this is a variable")
           # Tell the entry widget to watch this variable.
           self.entrythingy["textvariable"] = self.contents

           # Define a callback for when the user hits return.
           # It prints the current value of the variable.
           self.entrythingy.bind('<Key-Return>',
                                self.print_contents)

       def print_contents(self, event):
           print("Hi. The current entry content is:",
                 self.contents.get())

   root = tk.Tk()
   myapp = App(root)
   myapp.mainloop()


窗口管理器
----------

Tk 有个实用命令 "wm"，用于与窗口管理器进行交互。"wm" 命令的参数可用于
控制标题、位置、图标之类的东西。在 "tkinter" 中，这些命令已被实现为
"Wm" 类的方法。顶层部件是 "Wm" 类的子类，所以可以直接调用 "Wm" 的这些
方法。

要获得指定部件所在的顶层窗口，通常只要引用该部件的主窗口即可。当然，如
果该部件是包装在框架内的，那么主窗口不代表就是顶层窗口。为了获得任意组
件所在的顶层窗口，可以调用 "_root()" 方法。该方法以下划线开头，表明其
为 Python 实现的代码，而非 Tk 提供的某个接口。

以下是一些典型用法：

   import tkinter as tk

   class App(tk.Frame):
       def __init__(self, master=None):
           super().__init__(master)
           self.pack()

   # create the application
   myapp = App()

   #
   # here are method calls to the window manager class
   #
   myapp.master.title("My Do-Nothing Application")
   myapp.master.maxsize(1000, 400)

   # start the program
   myapp.mainloop()


Tk 参数的数据类型
-----------------

anchor
   合法值是罗盘的方位点：""n"" 、""ne"" 、""e"" 、""se"" 、""s"" 、
   ""sw"" 、""w"" 、""nw""  和 ""center"" 。

bitmap
   内置已命名的位图有八个："'error'"、 "'gray25'" 、"'gray50'" 、
   "'hourglass'"、 "'info'" 、"'questhead'" 、"'question'" 、
   "'warning'" 。若要指定位图的文件名，请给出完整路径，前面加一个 "@"
   ，比如 ""@/usr/contrib/bitmap/gumby.bit""。

boolean
   可以传入整数 0 或 1，或是字符串 ""yes"" 或 ""no""。

callback -- 回调
   指任何无需调用参数的 Python 函数。 例如：

      def print_it():
          print("hi there")
      fred["command"] = print_it

color
   可在 rgb.txt 文件中以颜色名的形式给出，或是 RGB 字符串的形式，4 位
   ：""#RGB"" ，8 位 ：""#RRGGBB""，12 位：""#RRRGGGBBB""，16 位：
   ""#RRRRGGGGBBBB""，其中R、G、B 为合法的十六进制数值。 详见
   Ousterhout 书中的第 160 页。

cursor
   可采用 "cursorfont.h" 中的标准光标名称，去掉 "XC_" 前缀。 比如要获
   取一个手形光标（"XC_hand2"），可以用字符串 ""hand2""。也可以指定自
   己的位图和掩码文件作为光标。参见 Ousterhout 书中的第 179 页。

distance
   屏幕距离可以用像素或绝对距离来指定。像素是数字，绝对距离是字符串，
   后面的字符表示单位："c" 是厘米，"i" 是英寸，"m" 是毫米，"p" 则表示
   打印机的点数。例如，3.5 英寸可表示为 ""3.5i""。

font
   Tk 采用一串名称的格式表示字体，例如 "{courier 10 bold}"。正数的字体
   大小以点为单位，负数的大小以像素为单位。

geometry
   这是一个 "widthxheight" 形式的字符串，其中宽度和高度对于大多数部件
   来说是以像素为单位的（对于显示文本的部件来说是以字符为单位的）。例
   如：fred["geometry"] = "200x100"。

justify
   合法的值为字符串： ""left"" 、 ""center"" 、 ""right"" 和 ""fill""
   。

区域
   这是包含四个元素的字符串，以空格分隔，每个元素是表示一个合法的距离
   值（见上文）。例如：""2 3 4 5"" 、 ""3i 2i 4.5i 2i"" 和 ""3c 2c 4c
   10.43c"" 都是合法的区域值。

relief
   决定了组件的边框样式。 合法值包括：""raised""、 ""sunken"" 、
   ""flat"" 、""groove""  和 ""ridge"" 。

scrollcommand
   这几乎就是带滚动条部件的 "set()" 方法，但也可是任一只有一个参数的部
   件方法。

wrap
   只能是以下值之一：""none"" 、 ""char"" 、 ""word""。


绑定和事件
----------

部件命令中的 bind 方法可觉察某些事件，并在事件发生时触发一个回调函数。
bind 方法的形式是：

   def bind(self, sequence, func, add=''):

其中：

sequence
   is a string that denotes the target kind of event.  (See the bind
   man page and page 201 of John Ousterhout's book for details).

func
   是带有一个参数的 Python 函数，发生事件时将会调用。传入的参数为一个
   Event 实例。（以这种方式部署的函数通常称为 *回调函数*。）

add
   可选项， "''" 或 "'+'" 。传入空字符串表示本次绑定将替换与此事件关联
   的其他所有绑定。传递 "'+'" 则意味着加入此事件类型已绑定函数的列表中
   。

例如：

   def turn_red(self, event):
       event.widget["activeforeground"] = "red"

   self.button.bind("<Enter>", self.turn_red)

请注意，在 "turn_red()" 回调函数中如何访问事件的 widget 字段。该字段包
含了捕获 X 事件的控件。下表列出了事件可供访问的其他字段，及其在 Tk 中
的表示方式，这在查看 Tk 手册时很有用处。

+------+-----------------------+------+-----------------------+
| Tk   | Tkinter 事件字段      | Tk   | Tkinter 事件字段      |
|======|=======================|======|=======================|
| %f   | focus                 | %A   | char                  |
+------+-----------------------+------+-----------------------+
| %h   | height                | %E   | send_event            |
+------+-----------------------+------+-----------------------+
| %k   | keycode               | %K   | keysym                |
+------+-----------------------+------+-----------------------+
| %s   | state                 | %N   | keysym_num            |
+------+-----------------------+------+-----------------------+
| %t   | time                  | %T   | type                  |
+------+-----------------------+------+-----------------------+
| %w   | width                 | %W   | widget                |
+------+-----------------------+------+-----------------------+
| %x   | x                     | %X   | x_root                |
+------+-----------------------+------+-----------------------+
| %y   | y                     | %Y   | y_root                |
+------+-----------------------+------+-----------------------+


index 参数
----------

很多控件都需要传入 index 参数。该参数用于指明 Text 控件中的位置，或指
明 Entry 控件中的字符，或指明 Menu 控件中的菜单项。

Entry 控件的索引（index、view index 等）
   Entry 控件带有索引属性，指向显示文本中的字符位置。这些 "tkinter"
   函数可用于访问文本控件中的这些特定位置：

Text 控件的索引
   Text 控件的索引语法非常复杂，最好还是在 Tk 手册中查看。

Menu 索引（menu.invoke()、menu.entryconfig() 等）
   菜单的某些属性和方法可以操纵特定的菜单项。只要属性或参数需要用到菜
   单索引，就可用以下方式传入：

   * 一个整数，指的是菜单项的数字位置，从顶部开始计数，从 0 开始；

   * 字符串 ""active""，指的是当前光标所在的菜单；

   * 字符串 ""last""，指的是上一个菜单项；

   * 带有 "@" 前缀的整数，比如 "@6"，这里的整数解释为菜单坐标系中的 y
     像素坐标；

   * 表示没有任何菜单条目的字符串 ""none"" 经常与 menu.activate() 一同
     被用来停用所有条目，以及 ——

   * 与菜单项的文本标签进行模式匹配的文本串，从菜单顶部扫描到底部。请
     注意，此索引类型是在其他所有索引类型之后才会考虑的，这意味着文本
     标签为 "last"、"active" 或 "none"  的菜单项匹配成功后，可能会视为
     这些单词文字本身。


图片
----

通过 "tkinter.Image" 的各种子类可以创建相应格式的图片：

* "BitmapImage" 对应 XBM 格式的图片。

* "PhotoImage" 对应 PGM、PPM、GIF 和 PNG 格式的图片。后者自 Tk 8.6 开
  始支持。

这两种图片可通过 "file" 或 "data" 属性创建的（也可能由其他属性创建）。

然后可在某些支持 "image" 属性的控件中（如标签、按钮、菜单）使用图片对
象。这时，Tk 不会保留对图片对象的引用。当图片对象的最后一个 Python 引
用被删除时，图片数据也会删除，并且 Tk 会在用到图片对象的地方显示一个空
白框。

参见:

  The Pillow package adds support for formats such as BMP, JPEG, TIFF,
  and WebP, among others.


文件处理程序
============

Tk 允许为文件操作注册和注销一个回调函数，当对文件描述符进行 I/O 时，Tk
的主循环会调用该回调函数。每个文件描述符只能注册一个处理程序。示例代码
如下：

   import tkinter
   widget = tkinter.Tk()
   mask = tkinter.READABLE | tkinter.WRITABLE
   widget.tk.createfilehandler(file, mask, callback)
   ...
   widget.tk.deletefilehandler(file)

在 Windows 系统中不可用。

由于不知道可读取多少字节，你可能不希望使用 "BufferedIOBase" 或
"TextIOBase" 的 "read()" 或 "readline()" 方法，因为这些方法必须读取预
定数量的字节。 对于套接字，可使用 "recv()" 或 "recvfrom()" 方法；对于
其他文件，可使用原始读取方法或 "os.read(file.fileno(), maxbytecount)"
。

Widget.tk.createfilehandler(file, mask, func)

   注册文件处理程序的回调函数 *func*。 *file* 参数可以是具备
   "fileno()" 方法的对象（例如文件或套接字对象），也可以是整数文件描述
   符。 *mask* 参数是下述三个常量的逻辑“或”组合。回调函数将用以下格式
   调用：

      callback(file, mask)

Widget.tk.deletefilehandler(file)

   注销文件处理函数。

tkinter.READABLE
tkinter.WRITABLE
tkinter.EXCEPTION

   Constants used in the *mask* arguments.
