0%

你好, Tkinter

废话不多说,直接上代码。

写过代码都知道,第一个肯定就是Hello-world了。先来一个简单的。

我们的第一个代码helloworld.py

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python
#tk/helloworld.py
# -*- coding: UTF-8 -*-
import tkinter

root = tkinter.Tk()

w = tkinter.Label(root, text='你好,Tkinter!')
w.pack()

root.mainloop()

运行示例

如何运行呢,与python程序一样,如下所述:

1
$ python helloworld.py

如果一些顺利,你会看到下面的一幅图片:

Hello Tkinter

如果希望停止该程序,直接点击关闭按钮即可。

细节

首先第一行,我们看到需要导入tkinter模块。

该模块包含所有的类,函数和其他Tk工具运行所需要的一切。
大多数情况下,你可以简单地导入Tkinter的所有到你的模块空间。

1
import tkinter

初始化tkinter,我们需要创建一个Tk根组件。
根组件包含一个title bar和由窗口管理器提供的装饰组件。
对于每一个程序创建一个根组件即可,并且需要在所有的组件之前创建。

1
root = tkinter.Tk()

接下来,我们创建一个根组件的Label子组件。

1
2
w = tkinter.Label(root, text="Hello, world!")
w.pack()

Label组件可以使用文本、图标和其他图像显示。
在这个示例中,我们使用文本显示。

然后,我们使用pack方法来将文本显示到组件上。不过直到我们使用Tkinter的事件主循环,我们才能看到这个窗口。

1
root.mainloop()

在我们关闭窗口前,程序将一直处在事件循环中。这个事件循环不仅仅接收来自用户(比如鼠标🖱点击和键盘⌨️输入)和系统(比如重绘事件和窗口配置信息)的事件,也会处理Tkinter本身的事件。

比如串口重绘或者配置等。这也就意味着如果不进入这个事件循环,之前的程序窗口是无法显示出来的。

你好,Tkinter2

如果程序写的大了,一般需要把代码包装到一个或许多类里面。

第二个Hello程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/python
#tk/helloworld_class.py
# -*- coding: UTF-8 -*-

from tkinter import *

class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()

self.button = Button(frame, text='Quit', foreground='red', background='blue', command=frame.quit)
self.button.pack(side=LEFT)

self.hi_there = Button(frame, text='Hello', command=self.say_hi)
self.hi_there.pack(side=LEFT)

def say_hi(self):
print('Hi there, welcome to tkinter!')

root = Tk()

app = App(root)

root.mainloop()
root.destroy() # optional; see description below

运行程序

运行这个程序,将会出现下面的这个窗口。

Hello

点击Hello按钮,终端输出信息 “Hi there, welcome to tkinter!”,如果点击Quit按钮,程序将退出。

注意:有些程序可能不会按照上面介绍的运行,这个时候就要检查下Tkinter的说明文档了,看看操作环境相关的配置,然后debug。

细节

这个示例,我们使用了class方法。初始化init方法创建一个继承自master的容器frame

1
2
3
4
5
class App:

def init(self, master):
frame = Frame(master)
frame.pack()

frame实例存储为局部变量,创建这个组建后,调用pack方法使之可见。

然后创建2个按钮组件,为frame的子组件。

1
2
3
4
5
self.button = Button(frame, text='Quit', foreground='red', background='blue', command=frame.quit)
self.button.pack(side=LEFT)

self.hi_there = Button(frame, text='Hello', command=self.say_hi)
self.hi_there.pack(side=LEFT)

这次,我们传递了一定数量的选项给结构器,第一个按钮被标记为 “QUIT”,前景色为红色 (其中fg 是foreground的简称)。第二个标记为 “Hello”。两个按钮都有一个command选项,这个选项指定了一个函数或者方法,在按钮被点击的时候调用。

按钮实例存储在实例属性组中。side=LEFT 参数表示这两个按钮在帧中将被分开放置;第一个按钮被放置
在帧的左边缘,第二个被放在第一个的右边(帧的左边缘仍保留着空格)。默认情况下,部件的放置都是相对
于它们的父亲(frame 部件相对于 masterbutton 相对于 frame)。如果 side 选项没指定,side 默认
值为 TOP

“hello” 按钮的回调函数如下所示,每次点击的时候都会在终端打印一条消息:

1
2
def say_hi(self):
print('Hi there, welcome to tkinter!')

最后,我们使用一些脚本来创建 Tk root 部件和一个App的实例(使用root作为它的父类):

1
2
3
4
5
6
root = Tk()

app = App(root)

root.mainloop()
root.destroy()

关于部件引用

1
Button(frame, text="Hello", command=self.hello).pack(side=LEFT)

如果不需要对一个窗口部件进行引用,可以用单独的一行创建并且进行包装,如上所述。

但是如果需要对其进行调用,就需要分开了,如下所示:

1
2
w = Button(frame, text="Hello", command=self.hello)
w.pack(side=LEFT)

关于部件名字

在上述实例中,我们使用的button或者hi_there都是部件的引用,而不是部件实际的名字,实际的名字大部分是由一系列数字组成的,这个有Tkinter自动为这些新部件赋值。

比如,我们可以打印出来名字如下所示:

1
2
>>> print str(ok)
.1428748.1432920

Tkinter 窗口组件类

Tkinter支持下列15种核心组件:

Button按钮

按钮,用于执行命令或其他操作。

Canvas画布

结构化的graphics。这个组件用于绘制graphs 和 plots,创建图像编辑器,部署其他组件。

Checkbutton复选按钮

有两个值,通过激活按钮来切换。

Entry 输入框

用于输入文本。

Frame

一个容器窗口部件。帧可以有边框和背景,当创建一个应用程序或 dialog(对话)版面时,帧被用来组织其它 的窗口部件。

Label 标签

用于显示文本或者图像。

Listbox

显示供选方案的一个列表。listbox 能够被配置来得到 radiobutton 或 checklist 的状态

菜单条,用来实现下拉或者弹出式菜单

菜单按钮,用来实现下拉式菜单,目前基本可以使用Menu来实现

Message

显示文本。与 label 窗口部件类似,但是能够自动地调整文本到给定的宽度或比率。

Radiobutton

代表一个变量,为多个值中的一个。点击它将为这个变量设置值,并且清除与这同一变量相关的其它
radiobutton。

Scale

允许你通过滑块来设置一数字值

Scrollbar

配合canvas, entry, listbox, and text窗口部件使用的标准滚动条。

Text

格式化文本显示。允许你用不同的样式和属性来显示和编辑文本。同时支持内嵌图象和窗口。

Toplevel

一个容器窗口部件,作为一个单独的、最上面的窗口显示。

在Python 2.3 (Tk 8.4),增加了下述组件:

LabelFrame

A variant of the Frame widget that can draw both a border and a title.

PanedWindow

A container widget that organizes child widgets in resizable panes.

Spinbox

A variant of the Entry widget for selecting values from a range or an ordered set.

Also note that there’s no widget class hierarchy in Tkinter; all widget classes are siblings in the inheritance tree.

所有这些窗口部件提供了 Misc 和几何管理方法、配置管理方法和部件自己定义的另外的方法。此外,Toplevel
类也提供窗口管理接口。这意味一个典型的窗口部件类提供了大约 150 种方法。

Mixins

The Tkinter module provides classes corresponding to the various widget types in Tk, and a number of mixin and other helper classes (a mixin is a class designed to be combined with other classes using multiple inheritance). When you use Tkinter, you should never access the mixin classes directly.

Implementation mixins

The Misc class is used as a mixin by the root window and widget classes. It provides a large number of Tk and window related services, which are thus available for all Tkinter core widgets. This is done by delegation; the widget simply forwards the request to the appropriate internal object.

The Wm class is used as a mixin by the root window and Toplevel widget classes. It provides window manager services, also by delegation.

Using delegation like this simplifies your application code: once you have a widget, you can access all parts of Tkinter using methods on the widget instance.

Geometry mixins

The Grid, Pack, and Place classes are used as mixins by the widget classes. They provide access to the various geometry managers, also via delegation.

Grid
The grid geometry manager allows you to create table-like layouts, by organizing the widgets in a 2-dimensional grid. To use this geometry manager, use the grid method.
Pack
The pack geometry manager lets you create a layout by “packing” the widgets into a parent widget, by treating them as rectangular blocks placed in a frame. To use this geometry manager for a widget, use the pack method on that widget to set things up.
Place
The place geometry manager lets you explicitly place a widget in a given position. To use this geometry manager, use the place method.

Widget configuration management

The Widget class mixes the Misc class with the geometry mixins, and adds configuration management through the cget and configure methods, as well as through a partial dictionary interface. The latter can be used to set and query individual options, and is explained in further detail in the next chapter.

组件配置

我们通常使用选项而不是方法来控制组件的显示。
标准的选项包括文本、颜色、大小、命令回调等。
为了处理这些选项,所有的核心组件都提供了相同的配置接口:

配置接口

1
widgetclass(master, option=value, …) => widget

其中widgetclass为上一节提到的组件类

创建这个窗口部件的一个实例,这个实例作为给定的 master 的孩子,并且使用给定的选项。所有的选项都有
默认值,因此在简单的情况下,你仅需要指定这个 master。如果你想的话,你也可以不指定 master;Tkinter这时会使用最近创建的 root 窗口作为 master。注意这个 name 选项仅能 在窗口部件被创建时设置。

cget(“option”) => string

返回一个选项的当前值。选项的名字和返回值都是字符串。要得到 name 选项,使用 str(widget)代替。

config(option=value, …)

configure(option=value, …)

设置一个或多个选项(作为关键字参数给定)。
注意一些选项的名字与 Python 中的保留字相同(class,from 等)。要使用这些作为关键字参数,仅需要在
这些选项名后添加一下划线(class_,from_)。注意你不能用此方法来设置 name 选项;name 选项只能在窗
口部件被创建时设置。

为了方便起见,窗口部件也实现一个局部的字典接口。 setitem 方法映射 configure,而
__getitem__方法映射 cget。你可以使用下面的语法来设置和查询选项:

value = widget[“option”]
widget[“option”] = value

注意每个赋值都导致一个对 Tk 的调用。如果你希望去改变多个选项,单独地调用(config 或 configure)
去改变它们是一个好的主意。

这下面的字典方法也适用于窗口部件

keys() => list

返回窗口部件中所有可以被设置的选项的一个列表。name 选项不包括在这个列表中(它不能通过字典接口被
查询或修改)

向后兼容性

关键字参数在 Python1.3时被引入。之前,使用原始的 Python 字典将选项传递给窗口构造器和 configure
方法。原代码类似如下:

1
2
self.button = Button(frame, {"text": "QUIT", "fg": "red", "command": frame.quit})
self.button.pack({"side": LEFT})

关键字参数语法更优雅和少容易发生错误。但是为了与存在的代码兼容,Tkinter 仍支持老的语法。在新的程
序中你不应再用老的语法,即使是在某些情况下是很有吸引力的。例如,如果你创建了一个定制的窗口部件,
它需要沿它的父类传递配置选项,你的代码可能如下:

1
2
def __init__(self, master, **kw):
Canvas.__init__(self, master, kw) # kw is a dictionary

上面的代码在当前版本的 Tkinter 下工作的很好,但是它在将来的版本下可能不工作。一个通常的办法是使
用 apply 函数:

1
2
def __init__(self, master, **kw):
apply(Canvas.__init__, (self, master), kw)

这个 apply 函数使用了一个函数(一个未约束的方法),一个带参数的元组(它必须包括 self,因为我们调
用一个未约束的方法),一个可选的,提供了关键字参数的字典。

组件样式

所有的Tkinter标准组件都提供了最基础的样式选项,这些选项可以用来修改诸如颜色、字体和其他显示信息。

颜色

大多数组件允许你指定组件和文本的颜色,可以使用 backgroundforeground 选项。为了指定颜色,可以使用颜色的名字,比如red,或者RGB参数,比如FF0000。

颜色名

Tkinter 包括一个颜色数据库,它将颜色名映射到相应的 RGB 值。这个数据库包括了通常的名称如 Red,
Green, Blue, Yellow, 和 LightBlue,也可使用外来的如 Moccasin,PeachPuff 等等。

在 X window系统上,颜色名由 X server 定义。你能够找到 一个名为 xrgb.txt 的文件,它包含了一个由颜色名和相应
RGB 值组成的列表。在 Windows 和 Macintosh 系统上,颜色名表内建于 Tk 中。

在 Windows 下,你可以使用 Windows 系统颜色(用户可以通过控制面板来改变这些颜色):

SystemActiveBorder, SystemActiveCaption, SystemAppWorkspace, SystemBackground, SystemButtonFace, SystemButtonHighlight, SystemButtonShadow, SystemButtonText, SystemCaptionText, SystemDisabledText, SystemHighlight, SystemHighlightText, SystemInactiveBorder, SystemInactiveCaption, SystemInactiveCaptionText, SystemMenu, SystemMenuText, SystemScrollbar, SystemWindow, SystemWindowFrame, SystemWindowText.

在 Macintosh 上,下面的系统颜色是有效的:

SystemButtonFace, SystemButtonFrame, SystemButtonText, SystemHighlight, SystemHighlightText, SystemMenu, SystemMenuActive, SystemMenuActiveText, SystemMenuDisabled, SystemMenuText, SystemWindowBody.

颜色名是大小写不敏感的。许多颜色(并不是所有的颜色)名词与词之间有无格都有效。例如”lightblue”, “light blue”, 和”Light Blue”都是同一颜色。

RGB 格式

如果你需要显式地指定颜色名,你可以使用如下格式的字符串

1
#RRGGBB

RR, GG, BB 分别是 red,green 和 blue 值的十六进制表示。下面的例子演示了如何将一个颜色三元组转换 为 一个 Tk 颜色格式:

1
tk_rgb = "#%02x%02x%02x" % (128, 192, 200)

Tk 也支持用形如”#RGB”和”rrrrggggbbbb”去分别指定16和65536程度之间的值。

你可以使用窗口部件的 winfo_rgb 方法来将一个代表颜色的字符串(名字或 RGB 格式)转换为一个三元组:

1
2
rgb = widget.winfo_rgb("red")
red, green, blue = rgb[0]/256, rgb[1]/256, rgb[2]/256

注意 winfo_rgb 返回16位的 RGB 值,范围在065535之间。要将它们映射到更通用的0255范围内,你必
须将每个值都除以256(或将它们向右移8位)。

字体

窗口部件允许你显示文本和指定所使用的字体。所有的窗口部件都提供了合理的默认值,你很少需要去为简单 元素如标签和按钮指定字体。

字体通常使用 font 窗口部件选项指定。Tkinter 支持一定数量的不同字体描述类型:

  • Font descriptors
  • User-defined font names
  • System fonts
  • X font descriptors

Tk8.0以前的版本仅X font描述被支持。
Font descriptors #

Starting with Tk 8.0, Tkinter supports platform independent font descriptors. You can specify a font as tuple containing a family name, a height in points, and optionally a string with one or more styles. Examples:

(“Times”, 10, “bold”)
(“Helvetica”, 10, “bold italic”)
(“Symbol”, 8)

To get the default size and style, you can give the font name as a single string. If the family name doesn’t include spaces, you can also add size and styles to the string itself:

“Times 10 bold”
“Helvetica 10 bold italic”
“Symbol 8”

Here are some families available on most Windows platforms:

Arial (corresponds to Helvetica), Courier New (Courier), Comic Sans MS, Fixedsys, MS Sans Serif, MS Serif, Symbol, System, Times New Roman (Times), and Verdana:

Note that if the family name contains spaces, you must use the tuple syntax described above.

The available styles are normal, bold, roman, italic, underline, and overstrike.

Tk 8.0 automatically maps Courier, Helvetica, and Times to their corresponding native family names on all platforms. In addition, a font specification can never fail under Tk 8.0; if Tk cannot come up with an exact match, it tries to find a similar font. If that fails, Tk falls back to a platform-specific default font. Tk’s idea of what is “similar enough” probably doesn’t correspond to your own view, so you shouldn’t rely too much on this feature.

Tk 4.2 under Windows supports this kind of font descriptors as well. There are several restrictions, including that the family name must exist on the platform, and not all the above style names exist (or rather, some of them have different names).

Font names

In addition, Tk 8.0 allows you to create named fonts and use their names when specifying fonts to the widgets.

The tkFont module provides a Font class which allows you to create font instances. You can use such an instance everywhere Tkinter accepts a font specifier. You can also use a font instance to get font metrics, including the size occupied by a given string written in that font.

tkFont.Font(family=”Times”, size=10, weight=tkFont.BOLD)
tkFont.Font(family=”Helvetica”, size=10, weight=tkFont.BOLD,
slant=tkFont.ITALIC)
tkFont.Font(family=”Symbol”, size=8)

If you modify a named font (using the config method), the changes are automatically propagated to all widgets using the font.

The Font constructor supports the following style options (note that the constants are defined in the tkFont module):

family

Font family.

size

Font size in points. To give the size in pixels, use a negative value.

weight

Font thickness. Use one of NORMAL or BOLD. Default is NORMAL.

slant

Font slant. Use one of NORMAL or ITALIC. Default is NORMAL.

underline

Font underlining. If 1 (true), the font is underlined. Default is 0 (false).

overstrike

Font strikeout. If 1 (true), a line is drawn over text written with this font. Default is 0 (false).

System fonts

Tk also supports system specific font names. Under X, these are usually font aliases like fixed, 6x10, etc.

Under Windows, these include ansi, ansifixed, device, oemfixed, system, and systemfixed:

On the Macintosh, the system font names are application and system.

Note that the system fonts are full font names, not family names, and they cannot be combined with size or style attributes. For portability reasons, avoid using these names wherever possible.

X Font Descriptors

X Font Descriptors are strings having the following format (the asterisks represent fields that are usually not relevant. For details, see the Tk documentation, or an X manual):

--family-weight-slant--size----*-charset

The font family is typically something like Times, Helvetica, Courier or Symbol.

The weight is either Bold or Normal. Slant is either R for “roman” (normal), I for italic, or O for oblique (in practice, this is just another word for italic).

Size is the height of the font in decipoints (that is, points multiplied by 10). There are usually 72 points per inch, but some low-resolution displays may use larger “logical” points to make sure that small fonts are still legible. The character set, finally, is usually ISO8859-1 (ISO Latin 1), but may have other values for some fonts.

The following descriptor requests a 12-point boldface Times font, using the ISO Latin 1 character set:

--Times-Bold-R--120----*-ISO8859-1

If you don’t care about the character set, or use a font like Symbol which has a special character set, you can use a single asterisk as the last component:

--Symbol----80-

A typical X server supports at least Times, Helvetica, Courier, and a few more fonts, in sizes like 8, 10, 12, 14, 18, and 24 points, and in normal, bold, and italic (Times) or oblique (Helvetica, Courier) variants. Most servers also support freely scaleable fonts. You can use programs like xlsfonts and xfontsel to check which fonts you have access to on a given server.

This kind of font descriptors can also be used on Windows and Macintosh. Note that if you use Tk 4.2, you should keep in mind that the font family must be one supported by Windows (see above).

Text Formatting

While text labels and buttons usually contain a single line of text, Tkinter also supports multiple lines. To split the text across lines, simply insert newline characters (\n) where necessary.

By default, the lines are centered. You can change this by setting the justify option to LEFT or RIGHT. The default value is CENTER.

You can also use the wraplength option to set a maximum width, and let the widget wrap the text over multiple lines all by itself. Tkinter attempts to wrap on whitespace, but if the widget is too narrow, it may break individual words across lines.

Borders

All Tkinter widgets have a border (though it’s not visible by default for some widgets). The border consists of an optional 3D relief, and a focus highlight region.
Relief #

The relief settings control how to draw the widget border:

borderwidth (or bd)

This is the width of the border, in pixels. Most widgets have a default borderwidth of one or two pixels. There’s hardly any reason to make the border wider than that.

relief

This option controls how to draw the 3D border. It can be set to one of SUNKEN, RAISED, GROOVE, RIDGE, and FLAT.

Focus Highlights

The highlight settings control how to indicate that the widget (or one of its children) has keyboard focus. In most cases, the highlight region is a border outside the relief. The following options control how this extra border is drawn:

highlightcolor

This option is used to draw the highlight region when the widget has keyboard focus. It’s usually black, or some other distinct contrast color.

highlightbackground

This option is used to draw the highlight region when the widget doesn’t have focus. It’s usually same as the widget background.

highlightthickness

This option is the width of the highlight region, in pixels. It is usually one or two pixels for widgets that can take keyboard focus.

Cursors

cursor

This option controls which mouse cursor to use when the mouse is moved over the widget.

If this option isn’t set, the widget uses the same mouse pointer as its parent.

Note that some widgets, including the Text and Entry widgets, set this option by default.

事件和绑定

As was mentioned earlier, a Tkinter application spends most of its time inside an event loop (entered via the mainloop method). Events can come from various sources, including key presses and mouse operations by the user, and redraw events from the window manager (indirectly caused by the user, in many cases).

Tkinter provides a powerful mechanism to let you deal with events yourself. For each widget, you can bind Python functions and methods to events.

1
widget.bind(event, handler)

If an event matching the event description occurs in the widget, the given handler is called with an object describing the event.

Here’s a simple example:

Capturing clicks in a window

1
2
3
4
5
6
7
8
9
10
11
12
from Tkinter import *

root = Tk()

def callback(event):
print "clicked at", event.x, event.y

frame = Frame(root, width=100, height=100)
frame.bind("<Button-1>", callback)
frame.pack()

root.mainloop()

In this example, we use the bind method of the frame widget to bind a callback function to an event called . Run this program and click in the window that appears. Each time you click, a message like “clicked at 44 63” is printed to the console window.

Keyboard events are sent to the widget that currently owns the keyboard focus. You can use the focus_set method to move focus to a widget:

Capturing keyboard events

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Tkinter import *

root = Tk()

def key(event):
print "pressed", repr(event.char)

def callback(event):
frame.focus_set()
print "clicked at", event.x, event.y

frame = Frame(root, width=100, height=100)
frame.bind("<Key>", key)
frame.bind("<Button-1>", callback)
frame.pack()

root.mainloop()

If you run this script, you’ll find that you have to click in the frame before it starts receiving any keyboard events.

Events

Events are given as strings, using a special event syntax:

The type field is the most important part of an event specifier. It specifies the kind of event that we wish to bind, and can be user actions like Button, and Key, or window manager events like Enter, Configure, and others. The modifier and detail fields are used to give additional information, and can in many cases be left out. There are also various ways to simplify the event string; for example, to match a keyboard key, you can leave out the angle brackets and just use the key as is. Unless it is a space or an angle bracket, of course.

Instead of spending a few pages on discussing all the syntactic shortcuts, let’s take a look on the most common event formats:

Event Formats

A mouse button is pressed over the widget. Button 1 is the leftmost button, button 2 is the middle button (where available), and button 3 the rightmost button. When you press down a mouse button over a widget, Tkinter will automatically “grab” the mouse pointer, and subsequent mouse events (e.g. Motion and Release events) will then be sent to the current widget as long as the mouse button is held down, even if the mouse is moved outside the current widget. The current position of the mouse pointer (relative to the widget) is provided in the x and y members of the event object passed to the callback.

You can use ButtonPress instead of Button, or even leave it out completely: <Button-1>, <ButtonPress-1>, and <1> are all synonyms. For clarity, I prefer the <Button-1> syntax.
The mouse is moved, with mouse button 1 being held down (use B2 for the middle button, B3 for the right button). The current position of the mouse pointer is provided in the x and y members of the event object passed to the callback.
Button 1 was released. The current position of the mouse pointer is provided in the x and y members of the event object passed to the callback.
Button 1 was double clicked. You can use Double or Triple as prefixes. Note that if you bind to both a single click (<Button-1>) and a double click, both bindings will be called.
The mouse pointer entered the widget (this event doesn’t mean that the user pressed the Enter key!).
The mouse pointer left the widget.
Keyboard focus was moved to this widget, or to a child of this widget.
Keyboard focus was moved from this widget to another widget.
The user pressed the Enter key. You can bind to virtually all keys on the keyboard. For an ordinary 102-key PC-style keyboard, the special keys are Cancel (the Break key), BackSpace, Tab, Return(the Enter key), Shift_L (any Shift key), Control_L (any Control key), Alt_L (any Alt key), Pause, Caps_Lock, Escape, Prior (Page Up), Next (Page Down), End, Home, Left, Up, Right, Down, Print, Insert, Delete, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, Num_Lock, and Scroll_Lock.
The user pressed any key. The key is provided in the char member of the event object passed to the callback (this is an empty string for special keys).

a

The user typed an “a”. Most printable characters can be used as is. The exceptions are space (<space>) and less than (<less>). Note that 1 is a keyboard binding, while <1> is a button binding.
The user pressed the Up arrow, while holding the Shift key pressed. You can use prefixes like Alt, Shift, and Control.
The widget changed size (or location, on some platforms). The new size is provided in the width and height attributes of the event object passed to the callback.

The Event Object

The event object is a standard Python object instance, with a number of attributes describing the event.

Event Attributes

widget

The widget which generated this event. This is a valid Tkinter widget instance, not a name. This attribute is set for all events.

x, y

The current mouse position, in pixels.

x_root, y_root

The current mouse position relative to the upper left corner of the screen, in pixels.

char

The character code (keyboard events only), as a string.

keysym

The key symbol (keyboard events only).

keycode

The key code (keyboard events only).

num

The button number (mouse button events only).

width, height

The new size of the widget, in pixels (Configure events only).

type

The event type.

For portability reasons, you should stick to char, height, width, x, y, x_root, y_root, and widget. Unless you know exactly what you’re doing, of course…

Instance and Class Bindings

The bind method we used in the above example creates an instance binding. This means that the binding applies to a single widget only; if you create new frames, they will not inherit the bindings.

But Tkinter also allows you to create bindings on the class and application level; in fact, you can create bindings on four different levels:

the widget instance, using bind.

the widget’s toplevel window (Toplevel or root), also using bind.

the widget class, using bind_class (this is used by Tkinter to provide standard bindings).

the whole application, using bind_all.

For example, you can use bind_all to create a binding for the F1 key, so you can provide help everywhere in the application. But what happens if you create multiple bindings for the same key, or provide overlapping bindings?

First, on each of these four levels, Tkinter chooses the “closest match” of the available bindings. For example, if you create instance bindings for the and events, only the second binding will be called if you press the Enter key.

However, if you add a binding to the toplevel widget, both bindings will be called. Tkinter first calls the best binding on the instance level, then the best binding on the toplevel window level, then the best binding on the class level (which is often a standard binding), and finally the best available binding on the application level. So in an extreme case, a single event may call four event handlers.

A common cause of confusion is when you try to use bindings to override the default behavior of a standard widget. For example, assume you wish to disable the Enter key in the text widget, so that the users cannot insert newlines into the text. Maybe the following will do the trick?

def ignore(event):
pass
text.bind(““, ignore)

or, if you prefer one-liners:

text.bind(““, lambda e: None)

(the lambda function used here takes one argument, and returns None)

Unfortunately, the newline is still inserted, since the above binding applies to the instance level only, and the standard behavior is provided by a class level bindings.

You could use the bind_class method to modify the bindings on the class level, but that would change the behavior of all text widgets in the application. An easier solution is to prevent Tkinter from propagating the event to other handlers; just return the string “break” from your event handler:

def ignore(event):
return “break”
text.bind(““, ignore)

or

text.bind(““, lambda e: “break”)

By the way, if you really want to change the behavior of all text widgets in your application, here’s how to use the bind_class method:

top.bind_class(“Text”, ““, lambda e: None)

But there are a lot of reasons why you shouldn’t do this. For example, it messes things up completely the day you wish to extend your application with some cool little UI component you downloaded from the net. Better use your own Text widget specialization, and keep Tkinter’s default bindings intact:

class MyText(Text):
def init(self, master, **kw):
apply(Text.init, (self, master), kw)
self.bind(““, lambda e: “break”)

Protocols

In addition to event bindings, Tkinter also supports a mechanism called protocol handlers. Here, the term protocol refers to the interaction between the application and the window manager. The most commonly used protocol is called WM_DELETE_WINDOW, and is used to define what happens when the user explicitly closes a window using the window manager.

You can use the protocol method to install a handler for this protocol (the widget must be a root or Toplevel widget):

widget.protocol(“WM_DELETE_WINDOW”, handler)

Once you have installed your own handler, Tkinter will no longer automatically close the window. Instead, you could for example display a message box asking the user if the current data should be saved, or in some cases, simply ignore the request. To close the window from this handler, simply call the destroy method of the window:

Capturing destroy events

from Tkinter import *
import tkMessageBox

def callback():
if tkMessageBox.askokcancel(“Quit”, “Do you really wish to quit?”):
root.destroy()

root = Tk()
root.protocol(“WM_DELETE_WINDOW”, callback)

root.mainloop()

Note that even you don’t register an handler for WM_DELETE_WINDOW on a toplevel window, the window itself will be destroyed as usual (in a controlled fashion, unlike X). However, as of Python 1.5.2, Tkinter will not destroy the corresponding widget instance hierarchy, so it is a good idea to always register a handler yourself:

top = Toplevel(…)

make sure widget instances are deleted

top.protocol(“WM_DELETE_WINDOW”, top.destroy)

Future versions of Tkinter will most likely do this by default.

Other Protocols

Window manager protocols were originally part of the X window system (they are defined in a document titled Inter-Client Communication Conventions Manual, or ICCCM). On that platform, you can install handlers for other protocols as well, like WM_TAKE_FOCUS and WM_SAVE_YOURSELF. See the ICCCM documentation for details.

Application Windows

Base Windows

In the simple examples we’ve used this far, there’s only one window on the screen; the root window. This is automatically created when you call the Tk constructor, and is of course very convenient for simple applications:

from Tkinter import *

root = Tk()

create window contents as children to root…

root.mainloop()

If you need to create additional windows, you can use the Toplevel widget. It simply creates a new window on the screen, a window that looks and behaves pretty much like the original root window:

from Tkinter import *

root = Tk()

create root window contents…

top = Toplevel()

create top window contents…

root.mainloop()

There’s no need to use pack to display the Toplevel, since it is automatically displayed by the window manager (in fact, you’ll get an error message if you try to use pack or any other geometry manager with a Toplevel widget).

Tkinter provides a special widget type for menus. To create a menu, you create an instance of the Menu class, and use add methods to add entries to it:

add_command(label=string, command=callback) adds an ordinary menu entry.

add_separator() adds an separator line. This is used to group menu entries.

add_cascade(label=string, menu=menu instance) adds a submenu (another Menu instance). This is either a pull-down menu or a fold-out menu, depending on the parent.

Here’s an example:

Creating a small menu

from Tkinter import *

def callback():
print “called the callback!”

root = Tk()

create a menu

menu = Menu(root)
root.config(menu=menu)

filemenu = Menu(menu)
menu.add_cascade(label=”File”, menu=filemenu)
filemenu.add_command(label=”New”, command=callback)
filemenu.add_command(label=”Open…”, command=callback)
filemenu.add_separator()
filemenu.add_command(label=”Exit”, command=callback)

helpmenu = Menu(menu)
menu.add_cascade(label=”Help”, menu=helpmenu)
helpmenu.add_command(label=”About…”, command=callback)

mainloop()

In this example, we start out by creating a Menu instance, and we then use the config method to attach it to the root window. The contents of that menu will be used to create a menubar at the top of the root window. You don’t have to pack the menu, since it is automatically displayed by Tkinter.

Next, we create a new Menu instance, using the menubar as the widget parent, and the add_cascade method to make it a pulldown menu. We then call add_command to add commands to the menu (note that all commands in this example use the same callback), and add_separator to add a line between the file commands and the exit command.

Finally, we create a small help menu in the same fashion.

Toolbars

Many applications place a toolbar just under the menubar, which typically contains a number of buttons for common functions like open file, print, undo, etc.

In the following example, we use a Frame widget as the toolbar, and pack a number of ordinary buttons into it.
Creating a simple toolbar

from Tkinter import *

root = Tk()

def callback():
print “called the callback!”

create a toolbar

toolbar = Frame(root)

b = Button(toolbar, text=”new”, width=6, command=callback)
b.pack(side=LEFT, padx=2, pady=2)

b = Button(toolbar, text=”open”, width=6, command=callback)
b.pack(side=LEFT, padx=2, pady=2)

toolbar.pack(side=TOP, fill=X)

mainloop()

The buttons are packed against the left side, and the toolbar itself is packed against the topmost side, with the fill option set to X. As a result, the widget is resized if necssary, to cover the full with of the parent widget.

Also note that I’ve used text labels rather than icons, to keep things simple. To display an icon, you can use the PhotoImage constructor to load a small image from disk, and use the image option to display it.

Status Bars

Finally, most applications sport a status bar at the bottom of each application window. Implementing a status bar with Tkinter is trivial: you can simply use a suitably configured Label widget, and reconfigure the text option now and then. Here’s one way to do it:

status = Label(master, text=””, bd=1, relief=SUNKEN, anchor=W)
status.pack(side=BOTTOM, fill=X)

If you wish to be fancy, you can use the following class instead. It wraps a label widget in a convenience class, and provides set and clear methods to modify the contents.

A Status Bar Class (File: tkSimpleStatusBar.py)

class StatusBar(Frame):

def __init__(self, master):
    Frame.__init__(self, master)
    self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
    self.label.pack(fill=X)

def set(self, format, *args):
    self.label.config(text=format % args)
    self.label.update_idletasks()

def clear(self):
    self.label.config(text="")
    self.label.update_idletasks()

The set method works like C’s printf function; it takes a format string, possibly followed by a set of arguments (a drawback is that if you wish to print an arbitrary string, you must do that as set(“%s”, string)). Also note that this method calls the update_idletasks method, to make sure pending draw operations (like the status bar update) are carried out immediately.

But the real trick here is that we’ve inherited from the Frame widget. At the cost of a somewhat awkward call to the frame widget’s constructor, we’ve created a new kind of custom widget that can be treated as any other widget. You can create and display the status bar using the usual widget syntax:

status = StatusBar(root)
status.pack(side=BOTTOM, fill=X)

We could have inherited from the Label widget itself, and just extended it with set and clear methods. This approach have a few drawbacks, though:

It makes it harder to maintain the status bar’s integrity. Some team members may cheat, and use config instead of set. That’s not a big deal, until the day you decide to do some extra processing in the set method. Or the day you decide to use a Canvas widget to implement a fancier status bar.

It increases the risk that your additional methods conflict with attributes or methods used by Tkinter. While the Frame and Toplevel widgets have relatively few methods, other widgets can have several dozens of widget specific attributes and methods.

Future versions of Tkinter may use factory functions rather than class constructors for most widgets. However, it’s more or less guaranteed that such versions will still provide Frame and Toplevel classes. Better safe than sorry, in other words.

Standard Dialogs

Before we look at what to put in that application work area, let’s take a look at another important part of GUI programming: displaying dialogs and message boxes.

Starting with Tk 4.2, the Tk library provides a set of standard dialogs that can be used to display message boxes, and to select files and colors. In addition, Tkinter provides some simple dialogs allowing you to ask the user for integers, floating point values, and strings. Where possible, these standard dialogs use platform-specific mechanisms, to get the right look and feel.

Message Boxes

The tkMessageBox module provides an interface to the message dialogs.

The easiest way to use this module is to use one of the convenience functions: showinfo, showwarning, showerror, askquestion, askokcancel, askyesno, or askretrycancel. They all have the same syntax:

tkMessageBox.function(title, message [, options]).

The title argument is shown in the window title, and the message in the dialog body. You can use newline characters (\n) in the message to make it occupy multiple lines. The options can be used to modify the look; they are explained later in this section.

The first group of standard dialogs is used to present information. You provide the title and the message, the function displays these using an appropriate icon, and returns when the user has pressed OK. The return value should be ignored.

Here’s an example:

try:
    fp = open(filename)
except:
    tkMessageBox.showwarning(
        "Open file",
        "Cannot open this file\n(%s)" % filename
    )
    return

The showinfo dialog
The showwarning dialog
The showerror dialog

The second group is used to ask questions. The askquestion function returns the strings “yes” or “no” (you can use options to modify the number and type of buttons shown), while the others return a true value of the user gave a positive answer (ok, yes, and retry, respectively).

if tkMessageBox.askyesno("Print", "Print this report?"):
    report.print()

The askquestion dialog
The askokcancel dialog
The askyesno dialog
The askretrycancel dialog

[Screenshots made on a Swedish version of Windows 95. Hope you don’t mind…]

Message Box Options

If the standard message boxes are not appropriate, you can pick the closest alternative (askquestion, in most cases), and use options to change it to exactly suit your needs. You can use the following options (note that message and title are usually given as arguments, not as options).

default constant

Which button to make default: ABORT, RETRY, IGNORE, OK, CANCEL, YES, or NO (the constants are defined in the tkMessageBox module).

icon (constant)

Which icon to display: ERROR, INFO, QUESTION, or WARNING

message (string)

The message to display (the second argument to the convenience functions). May contain newlines.

parent (widget)

Which window to place the message box on top of. When the message box is closed, the focus is returned to the parent window.

title (string)

Message box title (the first argument to the convenience functions).

type (constant)

Message box type; that is, which buttons to display: ABORTRETRYIGNORE, OK, OKCANCEL, RETRYCANCEL, YESNO, or YESNOCANCEL.

Python GUI编程(Tkinter)

Python 提供了很多个图形开发界面的库,其中Tkinter模块是(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口。 Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里。Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。

Tkinter 编程

Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。

由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、而且 IDLE 也是用 Tkinter 编写而成、对于简单的图形界面 Tkinter 还是能应付自如。

注意:Python3.x 版本使用的库名为 tkinter,即首写字母 T 为小写。

1
import tkinter

创建一个GUI程序

  1. 导入 Tkinter 模块
  2. 创建控件
  3. 指定这个控件的 master, 即这个控件属于哪一个
  4. 告诉 GM(geometry manager) 有一个控件产生了。

实例:

1
2
3
4
5
6
7
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import Tkinter
top = Tkinter.Tk()
# 进入消息循环
top.mainloop()

实例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/python
# -*- coding: UTF-8 -*-

from Tkinter import * # 导入 Tkinter 库
root = Tk() # 创建窗口对象的背景色
# 创建两个列表
li = ['C','python','php','html','SQL','java']
movie = ['CSS','jQuery','Bootstrap']
listb = Listbox(root) # 创建两个列表组件
listb2 = Listbox(root)
for item in li: # 第一个小部件插入数据
listb.insert(0,item)

for item in movie: # 第二个小部件插入数据
listb2.insert(0,item)

listb.pack() # 将小部件放置到主窗口中
listb2.pack()
root.mainloop() # 进入消息循环

Tkinter 组件

Tkinter的提供各种控件,如按钮,标签和文本框,一个GUI应用程序中使用。这些控件通常被称为控件或者部件。

目前有15种Tkinter的部件。我们提出这些部件以及一个简短的介绍,在下面的表:

控件 描述
Button 按钮控件;在程序中显示按钮。
Canvas 画布控件;显示图形元素如线条或文本
Checkbutton 多选框控件;用于在程序中提供多项选择框
Entry 输入控件;用于显示简单的文本内容
Frame 框架控件;在屏幕上显示一个矩形区域,多用来作为容器
Label 标签控件;可以显示文本和位图
Listbox 列表框控件;在Listbox窗口小部件是用来显示一个字符串列表给用户
Menubutton 菜单按钮控件,由于显示菜单项。
Menu 菜单控件;显示菜单栏,下拉菜单和弹出菜单
Message 消息控件;用来显示多行文本,与label比较类似
Radiobutton 单选按钮控件;显示一个单选的按钮状态
Scale 范围控件;显示一个数值刻度,为输出限定范围的数字区间
Scrollbar 滚动条控件,当内容超过可视化区域时使用,如列表框。
Text 文本控件;用于显示多行文本
Toplevel 容器控件;用来提供一个单独的对话框,和Frame比较类似
Spinbox 输入控件;与Entry类似,但是可以指定输入范围值
PanedWindow PanedWindow是一个窗口布局管理的插件,可以包含一个或者多个子控件。
LabelFrame labelframe 是一个简单的容器控件。常用与复杂的窗口布局。
tkMessageBox 用于显示你应用程序的消息框。

标准属性

标准属性也就是所有控件的共同属性,如大小,字体和颜色等等。

属性 描述
Dimension 控件大小;
Color 控件颜色;
Font 控件字体;
Anchor 锚点;
Relief 控件样式;
Bitmap 位图;
Cursor 光标;

几何管理

Tkinter控件有特定的几何状态管理方法,管理整个控件区域组织,一下是Tkinter公开的几何管理类:包、网格、位置

几何方法 描述
pack() 包装;
grid() 网格;
place() 位置;

Python 工具集

IDE

开发环境 描述 网址
IDLE The standard Python environment http://www.python.org/idle
Pythonwin Windows-oriented environment http://www.python.org/download/windows
ActivePython Feature-packed; contains Pythonwin IDE http://www.activestate.com
Komodo Commercial IDE http://www.activestate.com3
Wingware Commercial IDE http://www.wingware.com
BlackAdder Commercial IDE and (Qt) GUI builder http://www.thekompany.com
Boa Constructor Free IDE and GUI builder http://boa-constructor.sf.net
Anjuta Versatile IDE for Linux/UNIX http://anjuta.sf.net
Arachno Python Commercial IDE http://www.python-ide.com
Code Crusader Commercial IDE http://www.newplanetsoftware.com
Code Forge Commercial IDE http://www.codeforge.com
Eclipse Popular, flexible, open source IDE http://www.eclipse.org
eric Free IDE using Qt http://eric-ide.sf.net
KDevelop Cross-language IDE for KDE http://www.kdevelop.org
VisualWx Free GUI builder http://visualwx.altervista.org
wxDesigner Commercial GUI builder http://www.roebling.de
wxGlade Free GUI builder http://wxglade.sf.net

软件安装

pip

Pip 是目前安装python包很好的工具,但有时可能网络比较慢或者无法访问,此时可以临时更改pypi镜像。

国内pypi镜像

指定单次安装源方法如下:

1
pip install <包名> -i http://pypi.v2ex.com/simple

图形库

列举了一些Python的图形库,其中matplotlib功能最强大,Cairoplot最漂亮,django-chartitDjango集成了。

matplotlib

Matplotlib 是一个由 John Hunter 等开发的,用以绘制 二维图形的 Python 模块。它利用了 Python 下的数值计算模块 Numeric 及 Numarray,克隆了许多 Matlab 中的函数, 用以帮助用户轻松地获得高质量的二维图形。Matplotlib 可以绘制多种形式的图形包括普通的线图,直方图,饼图,散点图以及误差线图等;可以比较方便的定制图形的各种属性比如图线的类型,颜色,粗细,字体的大小 等;它能够很好地支持一部分 TeX 排版命令,可以比较美观地显示图形中的数学公式。个人比较推荐这个类库。可以用于生成通常是由 matlab 或者 Mathematica 生成的高质量图表。

Cairoplot

Cairoplot在网页上的表现力堪比flex中的图表图形效果。非常漂亮,非常赞!但是这个似乎只能跑在linux平台上。所以很多windows用户估计要失望了。

Chaco

Chaco是一个2D的绘图库。其中文简单教程参考:http://hyry.dip.jp/pydoc/chaco_intro.html

更多资料:

http://cairoplot.sourceforge.net/index.html
https://github.com/rodrigoaraujo01/cairoplot
https://groups.google.com/forum/?fromgroups#!forum/cairoplot

Python Google Chart,

官网:http://pygooglechart.slowchop.com/ 。从命名方式来看,这个肯定与google chart扯上了关系。所以该类库是对Google chart API的一个完整封装。

PyCha

官网:https://bitbucket.org/lgs/pycha/wiki/Home 。PyCha可是说是Cairo 类库的一个简单封装,为了是实现轻量级,以及容易使用,当然还做了一些优化等。

pyOFC2

官网:http://btbytes.github.com/pyofc2/ 。它是Open Falsh Library的Python类库。所以图形具有Flash效果,可以随鼠标移动动态显示图标中信息,这是优越于其他静态图示的。

Pychart

官网:http://home.gna.org/pychart/ 。pyChart是用于创建高品质封装的PostScript,PDF格式,PNG,或SVG图表Python库。

PLPlot

官网:http://plplot.sourceforge.net/ 。PLPlot是用于创建科学图表的跨平台软件包。以C类库为核心,支持各种语言绑定(C, C++, Fortran, Java, Python, Perl etc.)。开源免费。

reportlab

官网:http://www.reportlab.com/software/opensource/ 。这个我们之前介绍过,参考http://www.codecho.com/installation-and-example-of-reportlab-in-python/ 。这个类库支持在pdf中画图表。

Vpython

官网:http://www.vpython.org/index.html ,VPython是Visual Python的简写,Visual是由Carnegie Mellon University(卡耐基–梅隆大学)在校学生David Scherer于2000年撰写的一个Python 3D绘图模块。

Pycairo

http://cairographics.org/pycairo/ Pycairo is a set of Python bindings for the cairo graphics library.

panda3d

http://www.panda3d.org/ Panda3D不像是一个画基本图表的东东,它是一个 3D 引擎,用于三维图形的演示及游戏开发。程序库采用C++以及Python语言来绑定。用panda3d进行游戏开发通常写一段Python或C + +程序控制panda3d程序库。

django-chartit

非常漂亮的,并且与Django集成哦,它与MYSQL数据库集成了~

http://chartit.shutupandship.com
https://github.com/pgollakota/django-chartit

时间库

  • time
  • datetime : 扩展的time,表示绝对时间和相对时间
  • calendar : 有几个比较有用的工具,比如isleap

文件读写

  • pickle :简单滴只用dump和load即可
  • shelve:数据存在硬盘而不是内存中,适合在内存有限的情况下读取非常大的数据

数据分析