Python 的Tkinter包系列之六:好例子

用Tkinter写一个桌面应用程序,只需要三步:

1)创建一个窗体

2)把需要的控件放到窗体上(控件布局:设置控件在窗体内的位置以及填充、间隔等属性,使用pack、grid 和 place方法),并告诉它们当有预期的事件发生时就执行预设的动作(Tkinter的灵魂是事件驱动机制:当某事件发生时,程序就会自动执行预先设定的动作。事件驱动机制有三个要素:事件、事件函数和事件绑定)。

3)启动循环监听事件。(用mainloop()方法使主窗口进入消息事件循环,mainloop()方法的位置一定是放在最后,如果没有使主窗口进入消息事件循环,那么主窗口就不会出现。【提示:没有mainloop()方法窗口也没消失?那你是在IDLE中运行,用双击py文件 或 右击py文件使用“打开方式→Python”快捷菜单命令运行时没有mainloop()方法,你不会看到窗口】

无论这个程序有多么简单或多么复杂,第1步和第3步是固定不变的,设计者只需要专注于第2步的实现。

下面给出一个最简单的GUI应用程序——按钮点击计数器示例:

from tkinter import *

#事件函数, evt是事件对象
def on_button(evt):             
    counter.set(counter.get()+1)

#创建一个窗体
root = Tk()
root.title('按钮点击计数器')
root.geometry('320x160')
        
counter = IntVar() # 创建一个整型变量对象
counter.set(0) # 置其初值为0

label = Label(root, textvariable=counter, font=("Arial Bold", 50)) # 将Label和整型变量对象关联
label.pack(side='left', expand='yes', fill='both', padx=5, pady=5)

btn = Button(root, text='点我试试看', bg='#90F0F0')
btn.pack(side='right', anchor='center', fill='y', padx=5, pady=5)

btn.bind('<Button-1>', on_button) # 绑定事件和事件函数

#进入消息事件循环
root.mainloop()

from tkinter import *

def click_button():
    """事件函数"""    
    root.destroy() # 调用root的析构函数

运行效果:

python tkinter 实现多选 python tkinter mainloop_编程示例

现在点击按钮就可以看到效果了——单击一次按钮数字就加1

这就是Tkinter事件驱动机制在起作用!

熟悉OOP的读者,可能希望用面向对象的方式设计了一个按钮点击计数器。下面的代码就是: 

from tkinter import *

#继承Tk,创建自己的桌面应用程序类
class MyApp(Tk):
    #构造函数
    def __init__(self):         
        super().__init__()
        #创建一个窗体
        self.title('按钮点击计数器')
        self.geometry('320x160')
                
        self.counter = IntVar() # 创建一个整型变量对象
        self.counter.set(0) # 置其初值为0
        
        label = Label(self, textvariable=self.counter, font=("Arial Bold", 50)) # 将Label和整型变量对象关联
        label.pack(side='left', expand='yes', fill='both', padx=5, pady=5)
        
        btn = Button(self, text='点我试试看', bg='#90F0F0')
        btn.pack(side='right', anchor='center', fill='y', padx=5, pady=5)
        
        btn.bind('<Button-1>', self.on_button) # 绑定事件和事件函数

    #事件函数, evt是事件对象
    def on_button(self, evt):             
        self.counter.set(self.counter.get()+1)

app = MyApp()
#进入消息事件循环
app.mainloop()

运行效果和上图一样

python tkinter 实现多选 python tkinter mainloop_绑定事件_02

python支持多种编程范式。

☆面向过程的程序设计(Process oriented programming),也称为结构化程序设计(Structured programming),有时会被视为是指令式编程(Imperative programming)的同义语。编写程序可以说是这样一个过程:从系统要实现的功能入手把复杂的任务分解成子任务,把子任务再分解成更简单的任务,层层分解来完成。可以采用函数(function)或过程(procedure)一步步细化调用实现。

☆面向对象程序设计(Object Oriented Programming),是围绕着问题域中的对象(Object)来设计,对象包含属性、方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关联的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。

【编程范式是编程语言的一种分类方式,它并不针对某种编程语言,是从编程思想这个角度分析解决问题。就编程语言而言,一种编程语言也可以支持适用多种编程范式。

下面给出Tkinter完成的例子

以“简易计算器”为例,用两种程序设计思想实现。

下面是采用面向过程技术的实现

#简易计算器(面向过程)
from tkinter import *
reset=True

def buttonCallBack(event): 
     global label 
     global reset 
     num=event.widget['text'] 
     if num=='C': 
         label['text']="0"
         return
     if num in "=": 
         label['text']=str(eval(label['text'])) 
         reset=True
         return
     s=label['text'] 
     if s=='0' or reset==True: 
         s="" 
         reset=False
     label['text']=s+num
 
#主窗口 
root=Tk() 
root.wm_title("简易计算器") 
#显示栏1 
label=Label(root,text="0",background="light gray",anchor="e") 
label['width']=35
label['height']=2
label.grid(row=1,columnspan=4,sticky=W) 
#按钮 
showText="789/456*123-0.C+"
for i in range(4): 
    for j in range(4): 
         b=Button(root,text=showText[i*4+j],width=7) 
         b.grid(row=i+2,column=j) 
         b.bind("<Button-1>",buttonCallBack) 
showText="()"
for i in range(2): 
    b=Button(root,text=showText[i],width=7) 
    b.grid(row=6,column=2+i) 
    b.bind("<Button-1>",buttonCallBack) 
b=Button(root,text="=") 
b.grid(row=6,columnspan=2,sticky="we") 
b.bind("<Button-1>",buttonCallBack) 
root.mainloop()

运行效果:

python tkinter 实现多选 python tkinter mainloop_绑定事件_03

下面是采用面向对象技术的实现

# 简单计算器(采用类技术)
from tkinter import *
class App:
    def __init__(self, master):
        self.master = master
        self.initWidgets()
        self.hi = None
        
    def initWidgets(self):
        # 创建一个输入组件
        self.show = Label(relief=SUNKEN, font=('Courier New', 24),\
            width=23, bg='white', anchor=W)
        # 对该输入组件使用Pack布局,放在容器顶部
        self.show.pack(side=TOP, pady=10)
        p = Frame(self.master)
        p.pack(side=TOP)
        # 定义字符串的元组
        names = ("+", "1" , "2" , "3" , "C" 
            ,"-", "4" , "5" , "6" , "**" , "*", "7" , "8"
            , "9", "//", "/" , "." , "0" , "%", "=")
        # 遍历字符串元组
        for i in range(len(names)):
            # 创建Button,将Button放入p组件中
            b = Button(p, text=names[i], font=('Verdana', 20), width=5)
            b.grid(row=i // 5, column=i % 5)
            # 为鼠标左键的单击事件绑定事件处理方法
            b.bind('<Button-1>', self.click)
            # 为鼠标左键的双击事件绑定事件处理方法
            if b['text'] == 'C': b.bind('<Button-1>', self.clean)
        # 定义一个记录输入数字次数的变量
        self.i = 0
        
    def click(self, event):
        # 如果用户单击的是数字键或点号
        if(event.widget['text'] in ('0', '1', '2', '3',\
            '4', '5', '6', '7', '8', '9', '.')):
            # 判断self.i是否为0,0的话清空show['text']的值
            if self.i == 0 :
                self.show['text'] = ''
            self.show['text'] = self.show['text'] + event.widget['text']
            self.i = self.i + 1
            print(self.i)
        # 如果用户单击了运算符
        elif(event.widget['text'] in ('+', '-', '*', '/', '%', '**', '//')):
            # 把输入的数字与输入的字符相结合,组成一个数学运算式
            self.show['text'] = self.show['text'] + event.widget['text']
        elif(event.widget['text'] == '=' and self.show['text'] is not None):
            # 赋值给self.hi
            self.hi = self.show['text']
            # 其实这一步可以不要,主要作用是在调试时可以在后台看输入的数据
            print(self.hi)
            # 使用eval函数计算表达式的值
            self.show['text'] = str(eval(self.hi))
            self.hi = None
            self.i = 0
    # 点击C(恢复)按钮时,程序清空计算结果、将表达式设为None
    
    def clean(self, event):
        self.hi = None
        self.show['text'] = ''
        
root = Tk()
root.title("简单计算器")
App(root)
root.mainloop()

运行效果:

python tkinter 实现多选 python tkinter mainloop_python_04

 下面是一个“简单绘图“采用面向对象技术源码:

#简单绘图(采用面向对象技术)
from tkinter import *
from tkinter import colorchooser

class Application(Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.createWidget()
        self.x = 0
        self.y = 0
        self.lastDraw = 0 #最后绘制的图形id
        self.startDrawFlag = False
        self.fgcolor = "red"
                
    def createWidget(self):
        #创建绘图区
        self.drawPad = Canvas(root, width=900, height=500, bg="black")
        self.drawPad.pack()
        
        #画图软件的各种按钮
        btn_pen = Button(self, text="画笔", name="pen")
        btn_pen.pack(side="left", padx="10")
        btn_rect = Button(self, text="矩形", name="rect")
        btn_rect.pack(side="left", padx="10")
        btn_clear = Button(self, text="清屏", name="clear")
        btn_clear.pack(side="left", padx="10")
        btn_erasor = Button(self, text="橡皮擦", name="erasor")
        btn_erasor.pack(side="left", padx="10")
        btn_line = Button(self, text="直线", name="line")
        btn_line.pack(side="left", padx="10")
        btn_lineArrow = Button(self, text="箭头直线", name="lineArrow")
        btn_lineArrow.pack(side="left", padx="10")
        btn_color = Button(self, text="颜色", name="color")
        btn_color.pack(side="left", padx="10")

        #为所有button绑定事件
        btn_pen.bind_class("Button", "<1>", self.eventManage)
        self.drawPad.bind("<ButtonRelease-1>", self.stopDraw)
    
    def stopDraw(self, event):
        self.startDrawFlag = False
        self.lastDraw = 0
          
    def startDraw(self, event):
        self.drawPad.delete(self.lastDraw)
        if not self.startDrawFlag:
            self.startDrawFlag = True
            self.x = event.x
            self.y = event.y
    
    def eventManage(self, event):
        name = event.widget.winfo_name()
        print(name) #选取工具名字        
        if name == "line":
            varText.set("画线")
            self.drawPad.bind("<B1-Motion>", self.myline)
        elif name == "lineArrow":
            varText.set("画箭头")
            self.drawPad.bind("<B1-Motion>", self.mylineArrow)
        elif name == "rect":
            varText.set("画矩形")
            self.drawPad.bind("<B1-Motion>", self.myRect)
        elif name == "pen":
            varText.set("画笔")
            self.drawPad.bind("<B1-Motion>", self.myPen)            
        elif name == "erasor":
            varText.set("橡皮")
            self.drawPad.bind("<B1-Motion>", self.myErasor)
        elif name == "clear":
            self.drawPad.delete("all")
        elif name == "color":
            c = colorchooser.askcolor(color=self.fgcolor, title="选择画笔颜色")
            self.fgcolor = c[1]
            
    def myline(self, event):
        self.startDraw(event)     
        self.lastDraw = self.drawPad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor)
        
    def mylineArrow(self, event):
        self.startDraw(event)        
        self.lastDraw = self.drawPad.create_line(self.x, self.y, event.x, event.y, arrow=LAST, fill=self.fgcolor)
        
    def myRect(self, event):
        self.startDraw(event) 
        self.lastDraw = self.drawPad.create_rectangle(self.x, self.y, event.x, event.y, outline=self.fgcolor)
    
    def myPen(self, event):
        self.startDraw(event)     
        self.drawPad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor)
        self.x = event.x
        self.y = event.y        
               
    def myErasor(self, event):
        self.startDraw(event) 
        self.drawPad.create_rectangle(event.x-3, event.y-3, event.x+3, event.y+3, fill="black")
        self.x = event.x
        self.y = event.y
         
if __name__ == '__main__':
    root = Tk()
    root.geometry("900x500+200+200")
    root.title("画图软件")
    #下面4行用来提示选取工具
    varText = StringVar() 
    varText.set("工具提示")
    lbl=Label(root,textvariable=varText)
    lbl.pack(side="bottom", padx="10")
    app = Application(master=root)
    root.mainloop()

运行效果:

python tkinter 实现多选 python tkinter mainloop_编程示例_05

下面的例子支持“撤销”和“恢复”功能,并可以使用右键菜单

源码如下:

import tkinter as tk
from tkinter import ttk

class tkinter_example(object):
    def __init__(s):
        s.win = tk.Tk()               # 创建主窗口
        s.win.title("tkinter Canvas实现鼠标画图板") # 窗口标题
        s.win.withdraw()              # 隐藏窗口

        s.win.update_idletasks()      # 刷新窗口
        s.width, s.height = 600,400   #获取此时窗口大小
        s.Canvas()                    # 添加Canvas界面

        #窗口位置居中
        s.win.geometry('%dx%d+%d+%d' % (s.width, s.height, 
                      (s.win.winfo_screenwidth()  - s.width)/2,
                      (s.win.winfo_screenheight() - s.height)/2))

        s.win.resizable(0,0)     # 阻止GUI大小调整
        s.win.deiconify()        # 显示窗口
        s.win.mainloop()         # 显示主窗口

    def Canvas(s):
        #新建画布界面
        canvas = tk.Canvas(s.win, width=s.width, height=s.height, highlightthickness=0, bg='#AFEEEE')  
        canvas.grid()
        
        #创建一个可在 canvas 上手动绘图的效果,通过两点画线段的方式
        draw_point = ['', '']  #用于储存拖拉鼠标时的点
        revoke     = [ ] #用于储存每次鼠标绘图操作的ID供撤销用[[...],[...],[...]]
        recover    = [ ] #用于储存每次鼠标绘图的点构成的列表供恢复
        clear      = [ ] #用于记录是否使用过清空,因为列表可变,支持全局修改,所以用列表记录
        def _canvas_draw(event):
            if not event: #松开鼠标左键时执行,清空记录点
                draw_point[:] = ['','']  #[:]只改变draw_point指向的列表的内容,不是重新赋值一个新的列表所以修改值全局通用
                return
            point = [event.x, event.y]   #此次传递的点坐标
            if draw_point==['','']:      #按下鼠标左键开始拖动时执行
                draw_point[:] = point    #保存拖动的第一个点
                if len(revoke) < len(recover):
                    recover[len(revoke):] = [] #用于使用过撤销后再绘图,清除撤销点后的恢复数据
                clear[:] = []
                revoke.append([])        #新建一个撤销记录列表
                recover.append([])       #新建一个恢复记录列表
                recover[-1].extend(point)#在新建的恢复记录列表里记录第一个点
            else:
                revoke[-1].append(
                    canvas.create_line(draw_point[0], draw_point[1], event.x, event.y, fill="#476042", width=1,
                    tags = "line")
                          )      #绘制的线段并保存到撤销记录的末次列表
                draw_point[:] = point    #保存拖动点,覆盖上一次
                recover[-1].extend(point)#保存此次传递的点坐标到恢复记录的末次列表
        canvas.bind("<B1-Motion>", _canvas_draw) #设定拖动鼠标左键画线段
        canvas.bind("<ButtonRelease-1>", lambda event:_canvas_draw(0)) #设定松开鼠标左键清除保存的点

        #添加撤销和恢复功能rev撤销,rec恢复
        def _canvas_re(rev=0, rec=0):
            if rev and revoke: #撤销执行
                for i in revoke.pop(-1): canvas.delete(i) #pop弹出最后一个撤销列表,删除图像
            elif rec and recover and (len(revoke) != len(recover)): #恢复执行,恢复列表需要大于撤销列表
                if clear:
                    for i in recover: revoke.append([canvas.create_line(i , fill="#476042", width=1, tags = "line")])
                    clear[:] = []
                else:
                    revoke.append([canvas.create_line(recover[len(revoke)], fill="#476042", width=1, tags = "line")])

        #清空功能
        def _canvas_clear():
            canvas.delete("line") #清除 tags = "line"的图像
            revoke[:] = []
            clear.append(1)

        #添加右键菜单
        menu = tk.Menu(s.win, tearoff=0)    #不加 tearoff=0 的会出现可弹出选项
        menu.add_command(label="撤销", command = lambda:_canvas_re(rev=1))
        menu.add_command(label="恢复", command = lambda:_canvas_re(rec=1))
        menu.add_command(label="清空", command = _canvas_clear)
        canvas.bind("<Button-3>", lambda event: menu.post(event.x_root,event.y_root))#右键激活菜单

        # 创建一个Button对象,默认设置为居中对齐
        bt1 = ttk.Button(canvas,text = '撤销',command = lambda:_canvas_re(rev=1))
        #修改button在canvas上的对齐方式
        canvas.create_window((5, s.height-20), window = bt1, anchor = 'w')
        bt2 = ttk.Button(canvas,text = '恢复',command = lambda:_canvas_re(rec=1))
        canvas.create_window((s.width-90, s.height-20), window = bt2, anchor = 'w')
        bt3 = ttk.Button(canvas,text = "清空", command = _canvas_clear)
        canvas.create_window((s.width/2-43, s.height-20), window = bt3, anchor = 'w')

tkinter_example()

运行效果:

python tkinter 实现多选 python tkinter mainloop_python tkinter 实现多选_06

下面是一个数学函数作图——熠函数绘图工具。取自https://v-wb.youku.com/v_show/id_XNDYzMDc0MTYyOA==.html仅做少量修订。

先给出运行效果图:

python tkinter 实现多选 python tkinter mainloop_ide_07

特别提示:若显示的图像太小看不清,使用“+ ”按钮放大!

【使用说明:
1.点击左下角“新建”按钮",出现“新建函数”对话框,输入函数。
2.在绘图区显示函数图像。双击左侧函数列表中的函数可以在修改框中进行修改,回车确认。
注意:回车确认时,函数列表中的函数应处于选中状态。",
3.使用“+ -”可以放大缩小;“精度滑动条”可以调节精度。】

 源码如下:

#https://v-wb.youku.com/v_show/id_XNDYzMDc0MTYyOA==.html
from math import * #导入绘图模块
from tkinter import *
from tkinter.simpledialog import askstring
from tkinter.messagebox import askokcancel

text=["熠函数绘图工具,简易数学函数绘图。",
      "",
      "可以绘制简单的数学函数图像。",
      "",
      "1.点击左下角“新建”按钮,出现“新建函数”对话框,可以输入函数",
      "",
      "2.在绘图区显示函数图像。双击左侧函数列表中的函数可以在修改框中进行修改,回车确认。",
      "",
      "注意:回车确认时,函数列表中的函数应处于选中状态。",
      "",
      "3.使用“+ -”可以放大缩小;“精度滑动条”可以调节精度。",
      "",      
      "开发者:义乌东河小学学生孙璟熠。",
      ]
a=Tk()
a.title("")
a.geometry("900x620")
a.title("函数绘图 V1.4")
a.resizable(0,0)
size=10
mouse=[]
bc=80
help3=0
gb=0

def close():
    global a,help3
    if askokcancel("退出","你要退出吗?"):
        a.destroy()
        if help3!=0:
            help3.destroy()

def update(_=0):
    global c,size,s,bc,l,t4
    c.delete(ALL)
    j=s.get()
    functions=l.get(0,END)
    for z in range(-20,20):
        if z%4==0:
            c.create_line(z*20+375,0,z*20+375,500,fill="#202020")
        else:
            c.create_line(z*20+375,0,z*20+375,500,fill="#101010")
    for z in range(-16,16):
        if z%4==0:
            c.create_line(0,z*20+255,750,z*20+255,fill="#202020")
        else:
            c.create_line(0,z*20+255,750,z*20+255,fill="#101010")
    c.create_line(375,0,375,510,fill="#5a5a5a")
    c.create_line(0,255,750,255,fill="#5a5a5a")
    for z in functions:
        _i=True
        while _i:
             _i=False
             for z2 in range(len(z)):
                 try:
                     eval(z[z2])
                     if z[z2+1]=="x":                         
                         z=z[:z2+1]+"*"+z[z2+1:]
                         _i=True
                         break
                     if z[z2+1]=="π":
                         z=z[:z2+1]+"*"+z[z2+1:]
                         _i=True
                         break   
                 except:
                     ...
                 if z[z2]=="³":
                     if z2 != len(z)-1:
                         z=z[:z2]+"**3"+z[z2+1:]
                     else:
                         z=z[:z2]+"**3"
                     _i=True
                     break
                 if z[z2]=="²":
                     if z2 != len(z)-1:
                         z=z[:z2]+"**2"+z[z2+1:]
                     else:
                         z=z[:z2]+"**2"
                     _i=True
                     break
                 if z[z2]=="π":
                     z=z[:z2]+"3.1415926"+z[z2+1:]
                     _i=True
                     break
                 if z[z2]=="e":
                     z=z[:z2]+"2.7182818"+z[z2+1:]
                     _i=True
                     break
        print(z)
        lc=locals()
        txt=z.split("\n")[0]
        points=[]
        x=-3750/size
        try:
            while x<=3750/size:
                if x!=0:
                    exec(txt)
                    y=lc['y']
                    if type(y) !=complex:
                        points.append(x/10*size+375)
                        points.append(-y/10*size+255)
                x +=10/size*(101-j)
            exec(txt)
            y=lc['y']
            c.create_line(points,fill="#aaaaff",width=3)
        except:
            ...
    c.create_text(347,15,text="y",fill="#ff1010" ,font="time 20 bold" )
    c.create_text(730,240,text="x",fill="#ff1010" ,font="time 20 bold" )
    for z in range(-5,5):
        c.create_text(z*80+375,245,text=str(bc * z),fill="white")
    for z in range(-4,4):
        c.create_text(365,z*80+255,text=str(bc * -z),fill="white")

def add(event=0):
    global l
    text =str(askstring("新建函数",prompt="请输入你需要的函数",initialvalue="y=x"))
    if text !="None":
        l.insert(END,text)
    update()

def delete(event=0):
    global l,t4
    try:
        l.delete(ACTIVE)
        t4.delete("1.0",END)
    except:
        ...
    update()
    
def enlarge(event=0):
    global size,bc
    size *= 2
    bc /= 2
    update()

def narrow(event=0):
    global size,bc
    size =size/2
    bc *= 2
    update()
    
def show(event):
    global t4,l,gb
    try:
        t4.delete("1.0",END)
        t4.insert(INSERT,l.get(0,END)[l.curselection()[0]])        
        gb=l.curselection()[0]                  
    except:
        ...      
         
def save(event=0):
    global l,t4,gb
    try:
        s=l.curselection()[0]
        l.delete(s)
        t=t4.get("1.0",END)
        t=t.replace("\n","")
        t4.delete("1.0",END)
        t4.insert(INSERT,t)
        l.insert(s,t)
        l.selection_set(gb)
    except:
        ...
    update()

def help_close():
    global help3
    help3.destroy()
    help3=0

def help2(event=0):
    global help3,text
    if help3==0:
        help3=Tk()
        help3.title("帮助")
        frame3=Frame(help3,borderwidth=3)
        frame3.pack()
        frame2=Frame(frame3,borderwidth=3,relief=GROOVE)
        frame2.pack()
        frame=Frame(frame2,borderwidth=3)
        frame.pack()
        for z in range(len(text)):
            if z % 2 ==0:
                t = Label(frame,text=text[z],font=("",11))
            else:
                t = Label(frame,text=text[z],font=("",3))
            t.pack(anchor=W)
        help3.protocol("WM_DELETE_WINDOW",help_close)
        help3.mainloop()

def _2(event=0):
    global t4
    t4.insert(INSERT,"²")

def _3(event=0):
    global t4
    t4.insert(INSERT,"³")                          
        
def pi(event=0):
    global t4
    t4.insert(INSERT,"π")

menu = Menu()
menu1 = Menu(menu)
menu1.add_command(label="放大",command=enlarge,accelerator="Ctrl +")
menu1.add_command(label="缩小",command=narrow,accelerator="Ctrl -")
menu.add_cascade(label="缩显示",menu=menu1)
menu2 = Menu(menu)
menu2.add_command(label="平方 ²",command=_2,accelerator="Ctrl 2")
menu2.add_command(label="立方 ³",command=_3,accelerator="Ctrl 3")
menu2.add_command(label="π",command=pi,accelerator="Ctrl p")
menu.add_cascade(label="插入",menu=menu2)
menu3 = Menu()
menu.add_command(label="新建 Ctrl n",command=add)
menu.add_command(label="帮助 F1",command=help2)
a["menu"]=menu
a.bind_all("<Control-Key-2>",_2)
a.bind_all("<Control-Key-3>",_3)
a.bind_all("<Control-+>",enlarge)
a.bind_all("<Control-Key->",narrow)
a.bind_all("<Control-Key-n>",add)
a.bind_all("<Control-Key-p>",pi)
a.bind_all("<Return>",save)
a.bind_all("<F1>",help2)
f1=Frame(a,width=900,height=60,relief=SUNKEN,borderwidth=2)
f1.pack_propagate(0)
f1.pack()
f2=Frame(f1,width=900,height=35)
f2.pack_propagate(0)
f2.pack(side=TOP,anchor='sw')
f3=Frame(f1,width=900,height=25)
f3.pack_propagate(0)
f3.pack(side=TOP,anchor='sw',expand='yes')
b1=Button(f2,command=enlarge,width=2,height=2,text="+",font=("Times","18"))
b1.pack(side=LEFT)
b2=Button(f2,command=narrow,width=2,height=2,text="-",font=("Times","18"))
b2.pack(side=LEFT)
t1=Text(f3,width=4,height=2)
t1["wrap"]="none"
t1.insert(INSERT,"放大")
t1.config(state=DISABLED)
t1.pack(side=LEFT)
t2=Text(f3,width=5,height=2)
t2["wrap"]="none"
t2.insert(INSERT,"缩小")
t2.config(state=DISABLED)
t2.pack(side=LEFT)
s=Scale(f2,from_=1,to=100,orient=HORIZONTAL,resolution=1,length=800,tickinterval=10,width=20,command=update)
s.set(100)
s.pack(side=LEFT)
t3=Text(f3,width=500,height=2)
t3["wrap"]="none"
t3.insert(INSERT,"精度")
t3.config(state=DISABLED)
t3.pack(side=LEFT)
f4=Frame(a,width=150,height=540,relief=SUNKEN,borderwidth=2)
f4.pack_propagate(0)
f4.pack(side=LEFT)
l=Listbox(f4,height=27)
l.bind("<Double-Button-1>",show)
l.bind("<BackSpace>",delete)
l.pack()
f5=Frame(f4,width=150,height=40,relief=SUNKEN,borderwidth=2)
f5.pack_propagate(0)
f5.pack()
b3=Button(f5,width=5,height=2,text="新建",command=add)
b3.pack(side=LEFT)
b4=Button(f5,width=5,height=2,text="删除",command=delete)
b4.pack(side=LEFT)
b5=Button(f5,width=5,height=2,text="帮助",command=help2)
b5.pack(side=LEFT)
f6=Frame(a,width=750,height=540,relief=SUNKEN,borderwidth=3)
f6.pack_propagate(0)
f6.pack()
f7=Frame(f6,width=750,height=30,relief=SUNKEN,borderwidth=2)
f7.pack_propagate(0)
f7.pack()
f8=Frame(f6,width=750,height=510,relief=SUNKEN,borderwidth=2)
f8.pack_propagate(0)
f8.pack()
t4=Text(f7,width=120,height=2)
t4.pack(side=LEFT)
c=Canvas(f8,width=750,height=510,bg="black")
c.bind("Button-1",save)
c.pack()
update()
a.protocol("WM_DELETE_WINDOW",close)
a.mainloop()

更过例子可见