.. include:: ../LINKS.rst Tkinter =============== 一、程序库安装 ----------------------- 小白听大伙儿说,Python 安装包虽小,可是却包含了很好的文档 (Battery included),一个内置编辑器 (IDLE)和一个 Tkinter 桌面程序库。小白将信将疑。不信!Really? 试一试。 小白使用的是 Windows 7 操作系统,Python 2.5 软件。他点击 IDLE (Python GUI),打开 Python 内置的编辑器,输入了下面的程序,以测试是否能导入 Tkinter 程序库。:: >>import Tkinter >> 恩!没有报错。说明用 Python + Tkinter 的环境已经配置好了。 下面就可以用 Tkinter 编写通讯录了。但是,从哪里开始呢?小白想,我最需要的是一个可以执行的简单的 Tkinter 程序,了解 Tkinter 程序的基本结构。 然后在这个简单的程序上搭建我的通讯录程序。桌面程序,比我已经写好的 CLI 程序,无非就是多了交互界面。实际的功能部分,例如增加、删除和查找联系人应该都是差不多的。只需要点击界面后,调用我前面写好的功能函数就可以了。 小白对自己这个思路非常陶醉。对!分三步走,简单的入门程序,画交互界面,最后实现界面功能。 二、入门程序,Hello, Tkinter ---------------------------------------------- 小白决定,百度一把,使用 "Python Tkinter" 查了一下。又必应 (bing.com) 搜索了 “Python Tkinter Example”。 果真有好几个简单的 Tkinter 程序。必应第二个搜索结果标题是 Simple GUI Examples (TKinter),来自 ku.edu。 哇 !居然是学校的 Tkinter 课件,还有好多简单的 Tkinter 程序。小白YY中,“学完这个,我应该就可以给MM做好通讯录了”。 小白选了一个有按钮(button)和标签(label)的简单示例。替换了一下里面的文字。“谁不会替换引号里的文字呀?”。换成 "Hello, Tkinter" 吧,应该行!于是小白通过 copy/paste 和简单的修改,得到了下面的代码(参见源代码 tk/HelloTkinter.py)。 .. literalinclude:: ../../src/3_guimala/tk/HelloTkinter.py 点F5看看什么样吧。 .. figure:: ../_static/snap/gui_tk_helloTkinter.png 图1. Hello Tkinter 界面 哇哦!这几行代码,居然是一个完整的程序,并且有文本标签和按钮。看来,Tkinter 应该不难。那么,我们下面开始施工吧。 三、GUI 图纸施工 ----------------------- Tkinter 的基本元素(widget) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 先画一个 GUI 的构想图吧。根据以往使用软件的经验,小白认为,通讯录 GUI主要需要三种基本元素: 按钮 (用于搜索,查找、删除等按钮),输入对话框 (用于输入查询关键词,输入联系人基本信息等。),和文本标签。 根据上一节简单的示例,小白知道按钮应该是用 Button ,文本标签是 Label。输入对话框应该怎么做呢? 于是小白搜索了"Python Tkinter widget",发现 Tkinter 具有这些基本元素(widget):Toplevel, Frame(帧), Button(按钮), Checkbutton(多选按钮), Entry(输入框), Label(文本标签), Listbox(列表框), OptionMenu(选项菜单), Photoimage(图片), Radiobutton(单选按钮), Scale Menu(菜单), Menubutton(菜单按钮), Scrollbar(滚动条). 啊哈!输入对话框应该是 Entry 啦。我的通讯录应该只需要 Label, Entry, Button 这三个 widgets。其它的暂时不管了,以后需要的时候,再查询怎么用。 Tkinter 的布局管理(Layout manager) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 构建界面的元素已经明白了。怎么摆放这些元素呢?“知之为知之,不知必应知!” 搜一下,“Tkinter 布局” 和"tkinter layout manager"。 经过搜索,小白发现,原来 Tkinter 有三种布局管理器,pack、grid 和 place。作为学习笔记,小白将资料整理如下: - pack() pack 采用块地方式组织各种元素。pack 适用于快速生成界面,代码量最少。pack 将元素以自上往下地方式添加到 父组件中去。 使用 pack()布局的通用公式为: WidgetObject.pack(option, …) - grid() grid 采用类似表格的方式组织元素。grid 比较适合设计带对话框和滚动条的窗体。grid 通过行列参数确定元素摆放位置。 使用 grid()布局的通用公式为: WidgetObject.grid(option, …) - place() place 直接指定元素放置的具体位置。使用 place() 布局的通用公式为: WidgetObject.place(x,y,anchor) 那我们就选个最简单的吧。用 pack 来摆放元素。小白前面已经找到了三个元素的方法,Entry, Label 和 Button.于是在 HelloTkinter.py 的基础上修改。得了一个新建联系人的对话框。代码如下 (参见源代码tk/TkLayoutManager.py)。 .. literalinclude:: ../../src/3_guimala/tk/TkLayoutManager.py 点F5看看什么样吧。 .. figure:: ../_static/snap/gui_tk_TkLayoutManager.png 图2. 新建联系人界面,展示Tkinter的布局管理器 Tkinter的事件处理(Event and Bindings) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 上面的TkLayoutManager.py已经是一个完整地添加新的联系人的界面了。可是现在它还不能保存输入的联系人信息。点击“保存”按钮,没有任何反应。我们需要程序对用户输入,点击等动作做出反应。这被称为事件处理。小白还没有接触过事件处理,但是猜测这应该不难。因为他已经做好了界面,以前写的CLI通讯录的保存联系人信息的函数应该改改就可以了。现在唯一需要做的就是,在点击“保存”按钮和保存联系人信息的函数(savefile)之间建议联系。 Tkinter事件处理的方法为: widget.bind(event, handler) widget为事件触发者,比如,一个Button。event为事件,handler为处理事件的函数。 小白想,“何不做一个简单的程序,测试一下事件处理吧。”于是,小白修改了一下前面的HelloTkinter.py,使新的程序,可以点击一个按钮后呈现"Hello Tkinter".代码如下(参见源代码tk/HelloTkinterEventBinding.py) .. literalinclude:: ../../src/3_guimala/tk/HelloTkinterEventBinding.py 点F5看看什么样吧。 .. figure:: ../_static/snap/gui_tk_HelloTkinterEventBinding.png 图3. Hello Tkinter界面,展示Tkinter的事件处理 完善通讯录 ^^^^^^^^^^^^^^^^^^^^^^^ 对于小白正在做的新建联系人的界面,widget为保存按钮save,event为点击事件,handler就是保存联系人信息的函数savefile。“原来这么简单呀!”小白想,“这应该通过一两行代码就可以完成事件处理了”。小白试了试,应该在TkLayoutManager.py中增加下面这一行代码,save.bind("", savefile)这样应该就可以了。 下面,应该修改一下做CLI的通讯录时写的savefile函数,应该就可以了。不过,在保存联系人信息之前,小白还得想办法获取输入框Entry内的信息才行。 这个不难!搜一下“tkinter entry value”,很容易就可以看到如何获取Entry widget的输入值 。 经过搜索,小白发现widgetName.get()就可以得到一个widget的值。不过我们的软件需要支持中文,小白回顾了一下以前第二章时写下的中文处理的笔记,终于解决了中文的问题。widgetName.get().encode('utf-8')就可以得到Entry widget输入的中文内容。 小白在TkLayoutManager.py的基础上修改,为save 按钮增加了事件处理(save.bind("", savefile)),然后修改了以前在写CLI通讯录时的savefile函数,很轻松地完成了创建新联系人的软件。 代码如下(源代码请见tk/TkCreateContact.py)。 .. literalinclude:: ../../src/3_guimala/tk/TkCreateContact.py 点F5看看什么样吧。 .. figure:: ../_static/snap/gui_tk_TkCreateContact.png 图4. 新建联系人界面,展示Tkinter的事件处理 上面的代码是一个完整地可以创建新联系人的程序。不过小白并不满意。因为这个通讯录还缺少搜索和删除联系人功能。而且代码也没有实现模块化 (下一节,在讲wxPython时,我们会以制作通讯录的主界面为示例。读者也可以在下一节学习如何实现主界面和模块化)。 不过,这些对小白都不算太难了。因为他已经能够完整地写一个tkinter界面程序了。搜索和删除功能,也就是重复上面的,设计界面和实现事件绑定了。事件绑定部分,他可以利用CLI通讯录中的search和deletefile函数。 经过数小时的奋战,小白成功地完成了基于tkinter的通讯录。 他把代码放在了tk/AddressBookGUIzh.py。您也去看看他写的代码吧? .. figure:: ../_static/snap/gui_tk_Addressbookzh.png 图5. 通讯录界面