Python Tkinter Hello, Again

Hello, Again

When you write larger programs, it is usually a good idea to wrap your code up in one or more classes. The following example is adapted from the “hello world”program in Matt Conway’s A Tkinter Life Preserver (dead link).








 


当编写大型应用的时候把代码包裹成一个或多个类是个不错的注意。下面这个例子改编自Matt Conway的 A Tkinter Life Preserver  (死链接)中的“hello world”。
Our Second Tkinter Program
from Tkinter import *

class App:

    def __init__(self, master):

        frame = Frame(master)
        frame.pack()

        self.button = Button(
            frame, text="QUIT", fg="red", 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, everyone!"

root = Tk()

app = App(root)

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

Running the Example

When you run this example, the following window appears.

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

Running the sample program (using Tk 8.0 on a Windows 95 box)

If you click the right button, the text “hi there, everyone!” is printed to the console. If you click the left button, the program stops.

如果点击右边的按钮,将会在console里面打印"hi there, everyone!"。如果点击左边的按钮,程序将会停止。

Note: Some Python development environments have problems running Tkinter examples like this one. The problem is usually that the enviroment uses Tkinter itself, and the mainloop call and the quit calls interact with the environment’s expectations. Other environments may misbehave if you leave out the explicit destroy call. If the example doesn’t behave as expected, check for Tkinter-specific documentation for your development environment.

注意:一些Python开发环境在运行类似上面这个Tkinter例子的时候会出现问题。这个问题通常是环境在使用Tkinter本身,调用mainloop和quit的时候会影响到环境预期。如果遗漏掉明确调用destroy的话其他环境会产生行为异常。如果这个例子没有期望的行为,那么检查一下开发环境的Tkinter-specific文档。

Details

This sample application is written as a class. The constructor (the __init__method) is called with a parent widget (the master), to which it adds a number of child widgets. The constructor starts by creating a Frame widget. A frame is a simple container, and is in this case only used to hold the other two widgets.

这个示例应用被写作一个类。这个构造器(__init__方法)被一个父组件(master)调用。构造器以创建一个Frame组件开始。这个框架是一个简单的容器,它是用来容纳其他两个组件的。

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

The frame instance is stored in a local variable called frame. After creating the widget, we immediately call the pack method to make the frame visible.

这个frame实例被存储在一个成文frame的本地变量里面。在创建完成以后,马上可以调用pack方法去让frame变得可视。

We then create two Button widgets, as children to the frame.

创建两个Button组件作为frame的孩子。

self.button = Button(frame, text="QUIT", fg="red", 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)

This time, we pass a number of  options to the constructor, as keyword arguments. The first button is labelled “QUIT”, and is made red ( fg is short for  foreground). The second is labelled “Hello”. Both buttons also take a  command option. This option specifies a function, or (as in this case) a bound method, which will be called when the button is clicked.

这次传递了一些选项给这个构造作为关键参数。第一个按钮被标记为"QUIT",并被标为红色(fg是foreground的缩写)。第二个被标记为"Hello".俩个按钮都有一个command选项,这个选项指派一个函数或者一个绑定的方法,它们会在按钮被点击的时候被调用。

The button instances are stored in instance attributes. They are both packed, but this time with the side=LEFT argument. This means that they will be placed as far left as possible in the frame; the first button is placed at the frame’s left edge, and the second is placed just to the right of the first one (at the left edge of the remaining space in the frame, that is). By default, widgets are packed relative to their parent (which is master for the frame widget, and the frame itself for the buttons). If the side is not given, it defaults to TOP.

按钮实例被存储在实例属性中。它们都被打包,带有一个参数side=LEFT。这就意味着它们被放置在框架的最左侧。第一个按钮被放置在框架的最左边,第二个按钮紧靠第一个按钮的右边(这是框架剩余空间的最左边)。一般来说,组件打包和父组件有关(对于框架组件来说是master,而对于按钮来说是框架本身)。如果side参数没有被给定,默认值是TOP。

The “hello” button callback is given next. It simply prints a message to the console everytime the button is pressed:

接下来指派"hello"按钮的回调函数。它在按钮被按下的时候简单的在console中打印一条信息。

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

 Finally, we provide some script level code that creates a  Tk root widget, and one instance of the  App class using the root widget as its parent:

最后,提供一些脚本层面的代码创建一个Tk根组件和一个使用根组件作为父组件的App类实例

root = Tk()
app = App(root)
root.mainloop()
root.destory()

The  mainloop call enters the Tk event loop, in which the application will stay until the  quit method is called (just click the QUIT button), or the window is closed.

mainloop调用进入Tk事件循环,直到quit方法被调用(只要点击QUIT按钮)或者窗口被关闭之前应用都会呆在事件循环里。

The destroy call is only required if you run this example under certain development environments; it explicitly destroys the main window when the event loop is terminated. Some development environments won’t terminate the Python process unless this is done.

只有当在特定的开发环境中运行这个例子的时候才需要调用destroy方法。当事件循环结束的是它会明确的销毁主窗口。如果不这样做的话一些开发环境不会结束Python进程。

More on widget references

In the second example, the frame widget is stored in a local variable named frame, while the button widgets are stored in two instance attributes. Isn’t there a serious problem hidden in here: what happens when the __init__ function returns and the frame variable goes out of scope?

在第二个例子中,frame组件存储在一个名字为frame的本地变量中,而按钮组件存储在两个实例属性中。这是不是隐藏了一个严重的问题“当__init__函数返回和frame变量超出范围以后会发生什么?

Just relax; there’s actually no need to keep a reference to the widget instance. Tkinter automatically maintains a widget tree (via the master and children attributes of each widget instance), so a widget won’t disappear when the application’s last reference goes away; it must be explicitly destroyed before this happens (using the destroy method). But if you wish to do something with the widget after it has been created, you better keep a reference to the widget instance yourself.

放松些,事实上不需要对保持参考组件实例保持一个参考。Tkinter会自动地维护一个组件树(通过每一个组件实例的master和children属性),所以在应用的最后一个参考离开之前这个组件不会消失,必须显示的去销毁才行(使用destroy方法)。但如果想在一个组件被创建后对它做些什么,最好是自己对组件实例保持参考。

Note that if you don’t need to keep a reference to a widget, it might be tempting to create and pack it on a single line:

注意如果不需要对一个组件保持参考,那么可以通过一行尝试创建和pack它。

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

Don’t store the result from this operation; you’ll only get disappointed when you try to use that value (the  pack method returns  None). To be on the safe side, it might be better to always separate construction from packing:

不要存储这个操作的返回值,当这样做的时候会很失望(pack方法返回None)。安全起见,最好是分开来构造。

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

More on widget names

Another source of confusion, especially for those who have some experience of programming Tk using Tcl, is Tkinter’s notion of the widget name. In Tcl, you must explicitly name each widget. For example, the following Tcl command creates a Button named “ok”, as a child to a widget named “dialog” (which in turn is a child of the root window, “.”).

另外一个困惑,尤其对于有使用Tcl对Tk编程经验的人,是Tkinter的组件名称概念。在Tck中,你必须显式的命名每一个组件,例如下面的Tcl命令创建一个名为"Ok"的按钮作为名为"dialog"的组件的孩子。

button.dialog.ok

The corresponding Tkinter call would look like:

正确的Tkinter调用应该是这样:

ok = Button(dialog)

However, in the Tkinter case, ok and dialog are references to widget instances, not the actual names of the widgets. Since Tk itself needs the names, Tkinter automatically assigns a unique name to each new widget. In the above case, the dialog name is probably something like “.1428748,” and the button could be named “.1428748.1432920”. If you wish to get the full name of a Tkinter widget, simply use the str function on the widget instance:

总之,在Tkinter例子中,Ok和dialog是组件实例的参考,而非真正的名字。因为Tk本身需要名字,Tkinter自动地为每一个新组件分配一个独一无二的名字。在上面的例子中,dialog名字可能是想".1428748"的东西,按钮可能是".128748.1432920"。如果想得到一个Tkinter组件的全名,可以使用组件实例的str函数:

>>>print str(ok)
1428748.1432920

(if you print something, Python automatically uses the str function to find out what to print. But obviously, an operation like “name = ok” won’t do the that, so make sure always to explicitly use str if you need the name).

(如果想打印些什么,Python自动地使用str函数去找到要打印什么。但是显然像"name = ok"这样的一个操作不会这样做,所以当需要获得名字的时候要显式的使用str)

If you really need to specify the name of a widget, you can use the name option when you create the widget. One (and most likely the only) reason for this is if you need to interface with code written in Tcl.

如果需要为一个组件指定名字,可以在创建组件的时候使用name选项。这样做的原因可能是你需要Tcl代码的接口。

In the following example, the resulting widget is named “.dialog.ok” (or, if you forgot to name the dialog, something like “.1428748.ok”):

在下面的例子中,结果就是这个组件被命名为".dialog.ok"(或者是一个想".1428748"的东西,如果你忘记命名这个会话的话)

ok = Button(dialog, name = 'ok')
To avoid conflicts with Tkinter’s naming scheme, don’t use names which only contain digits. Also note that  name is a “creation only” option; you cannot change the name once you’ve created the widget.

为了避免和Tkinter明明规范冲突,是要使用全是数字的名字。注意选项name是一个"creation only"选项,一旦创建好组件就不能再更改它的名字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值