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的析构函数
运行效果:
现在点击按钮就可以看到效果了——单击一次按钮数字就加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支持多种编程范式。
☆面向过程的程序设计(Process oriented programming),也称为结构化程序设计(Structured programming),有时会被视为是指令式编程(Imperative programming)的同义语。编写程序可以说是这样一个过程:从系统要实现的功能入手把复杂的任务分解成子任务,把子任务再分解成更简单的任务,层层分解来完成。可以采用函数(function)或过程(procedure)一步步细化调用实现。
☆面向对象程序设计(Object Oriented Programming),是围绕着问题域中的对象(Object)来设计,对象包含属性、方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关联的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。
【编程范式是编程语言的一种分类方式,它并不针对某种编程语言,是从编程思想这个角度分析解决问题。就编程语言而言,一种编程语言也可以支持适用多种编程范式。更多情况Python面向对象程序设计讲座_软件开发技术爱好者的博客-CSDN博客 】
简易计算器
下面给出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()
运行效果:
下面是采用面向对象技术的实现
# 简单计算器(采用类技术)
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()
运行效果:
简单绘图
下面是一个“简单绘图“采用面向对象技术源码:
from tkinter import *
from tkinter import messagebox
from tkinter.colorchooser import askcolor
win_width = 780
win_height = 520
bgcolor = '#FFFFFF'
class Application(Frame):
"""一个经典的GUI写法"""
def __init__(self, master=None):
"""初始化方法"""
super().__init__(master) # 调用父类的初始化方法
self.x = 0
self.y = 0
self.fgcolor = 'black'
self.lastdraw = 0
self.start_flag = False
self.master = master
self.pack()
self.createWidget()
self.pen_width = 1 # 线的粗细
def createWidget(self):
"""创建画图区域"""
self.drawpad = Canvas(self, width=win_width, height=win_height, bg=bgcolor)
self.drawpad.pack()
# 创建按钮
self.btn_pen = Button(self, name='pen', text='画笔')
self.btn_pen.pack(side='left', padx=10)
self.btn_rect = Button(self, name='rect', text='矩形')
self.btn_rect.pack(side='left', padx=10)
self.btn_oval = Button(self, name='oval', text='圆形') # 新增按钮:画圆
self.btn_oval.pack(side='left', padx=10)
self.btn_line = Button(self, name='line', text='直线')
self.btn_line.pack(side='left', padx=10)
self.btn_dashed_line = Button(self, name='dashed_line', text='虚直线')
self.btn_dashed_line.pack(side='left', padx=10)
self.btn_line_arrow = Button(self, name='line_arrow', text='箭头直线')
self.btn_line_arrow.pack(side='left', padx=10)
self.btn_color = Button(self, name='color', text='颜色')
self.btn_color.pack(side='left', padx=10)
self.btn_eraser = Button(self, name='eraser', text='橡皮擦')
self.btn_eraser.pack(side='left', padx=10)
self.btn_clear = Button(self, name='clear', text='清屏')
self.btn_clear.pack(side='left', padx=10)
self.scl_pen_width = Scale(self, from_=1, to=10, orient=HORIZONTAL, label='线条粗细') # 新增:线条粗细调整
self.scl_pen_width.pack(side='left', padx=10)
self.lbl_current_tool = Label(self, text="工具:未选", font=("Arial", 10)) # 提示
self.lbl_current_tool.pack(side='bottom', pady=10)
# 绑定事件
self.btn_line.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_line_arrow.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_rect.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_pen.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_eraser.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_clear.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_color.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_oval.bind('<Button-1>', self.eventManager) # 点击按钮事件
self.btn_dashed_line.bind('<Button-1>', self.eventManager)# 虚直线点击事件
self.drawpad.bind('<ButtonRelease-1>', self.stopDraw) # 左键释放按钮
def eventManager(self, event):
name = event.widget.winfo_name()
print(name)
self.start_flag = True
self.pen_width = self.scl_pen_width.get() # 获取线条粗细值
tool_name = "未选"
if name == 'line':
self.drawpad.bind('<B1-Motion>', self.myline)
tool_name = "直线"
self.lbl_current_tool.config(text=f"当前: {tool_name}")
elif name == 'dashed_line':
self.drawpad.bind('<B1-Motion>', self.mydashedline)
tool_name = "虚直线"
self.lbl_current_tool.config(text=f"当前: {tool_name}")
elif name == 'line_arrow':
self.drawpad.bind('<B1-Motion>', self.myline_arrow)
tool_name = "箭头直线"
self.lbl_current_tool.config(text=f"当前: {tool_name}")
elif name == 'rect':
self.drawpad.bind('<B1-Motion>', self.myrect)
tool_name = "矩形"
self.lbl_current_tool.config(text=f"当前: {tool_name}")
elif name == 'oval':
self.drawpad.bind('<B1-Motion>', self.myoval)
tool_name = "圆形"
self.lbl_current_tool.config(text=f"当前: {tool_name}")
elif name == 'pen':
self.drawpad.bind('<B1-Motion>', self.mypen)
tool_name = "画笔"
self.lbl_current_tool.config(text=f"当前: {tool_name}")
elif name == 'eraser':
self.drawpad.bind('<B1-Motion>', self.myeraser)
tool_name = "橡皮擦"
self.lbl_current_tool.config(text=f"当前: {tool_name}")
elif name == 'clear':
self.drawpad.delete('all')
# tool_name = "清屏"
elif name == 'color':
c = askcolor(color=self.fgcolor, title='请选择颜色')
print(c)
self.fgcolor = c[1]
# tool_name = "颜色选择"
def startDraw(self, event):
self.drawpad.delete(self.lastdraw)
if self.start_flag:
self.start_flag = False
self.x = event.x
self.y = event.y
def stopDraw(self, event):
self.start_flag = True
self.lastdraw = 0
# 直线
def myline(self, event):
self.startDraw(event)
self.lastdraw = self.drawpad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor, width=self.pen_width)
# 虚直线
def mydashedline(self, event):
self.startDraw(event)
# dash参数定义了虚线的模式,比如(4, 4)表示线段长度为4,空白也为4
self.lastdraw = self.drawpad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor, width=self.pen_width, dash=(4, 4))
# 带箭头的线
def myline_arrow(self, event):
self.startDraw(event)
self.lastdraw = self.drawpad.create_line(self.x, self.y, event.x, event.y, arrow=LAST, fill=self.fgcolor, width=self.pen_width)
# 矩形
def myrect(self, event):
self.startDraw(event)
self.lastdraw = self.drawpad.create_rectangle(self.x, self.y, event.x, event.y, outline=self.fgcolor, width=self.pen_width)
# 画笔
def mypen(self, event):
self.startDraw(event)
# print('self.x=', self.x, ',self.y=', self.y)
self.drawpad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor, width=self.pen_width)
self.x = event.x
self.y = event.y
# 橡皮擦
def myeraser(self, event):
self.startDraw(event)
eraser_size = 10 # 定义橡皮擦的大小
self.drawpad.create_rectangle(event.x - eraser_size/2, event.y - eraser_size/2, event.x + eraser_size/2, event.y + eraser_size/2, fill=bgcolor, outline=bgcolor)
self.x = event.x
self.y = event.y
# 圆
def myoval(self, event):
self.startDraw(event)
self.lastdraw = self.drawpad.create_oval(self.x, self.y, event.x, event.y, outline=self.fgcolor, width=self.pen_width)
if __name__ == '__main__':
root = Tk()
root.title('画图窗口')
root.geometry('800x600+200+100')
app = Application(master=root)
root.mainloop()
运行效果:
下面的简单绘图例子支持“撤销”和“恢复”功能,并可以使用右键菜单
源码如下:
import tkinter as tk
from tkinter import ttk
import math
class tkinter_example(object):
def __init__(self):
self.win = tk.Tk() # 创建主窗口
self.win.title("tkinter Canvas实现鼠标画图板") # 设置窗口标题
self.create_widgets() # 创建窗口内的组件
self.center_window() # 将窗口居中显示
self.win.resizable(0, 0) # 禁止窗口改变大小
self.win.mainloop() # 运行主事件循环
def create_widgets(self):
self.width, self.height = 600, 400 # 画布宽高
# 创建放置按钮的框架
self.button_frame = tk.Frame(self.win)
self.button_frame.grid(row=0, column=0, sticky='ew')
self.button_frame.columnconfigure(0, weight=1) # 让按钮水平居中
# 添加按钮
self.undo_button = ttk.Button(self.button_frame, text='撤销', command=lambda: self.canvas_re(rev=1))
self.undo_button.grid(row=0, column=0)
self.redo_button = ttk.Button(self.button_frame, text='重做', command=lambda: self.canvas_re(rec=1))
self.redo_button.grid(row=0, column=1)
self.clear_button = ttk.Button(self.button_frame, text='清除', command=self.canvas_clear)
self.clear_button.grid(row=0, column=2)
self.pen_button = ttk.Button(self.button_frame, text='笔', command=self.use_pen)
self.pen_button.grid(row=0, column=3)
self.line_button = ttk.Button(self.button_frame, text='直线', command=self.use_line)
self.line_button.grid(row=0, column=4)
self.circle_button = ttk.Button(self.button_frame, text='圆', command=self.use_circle)
self.circle_button.grid(row=0, column=5)
# 创建画布
self.canvas = tk.Canvas(self.win, width=self.width, height=self.height, highlightthickness=0, bg='white')
self.canvas.grid(row=1, column=0)
self.revoke = [] # 保存撤销操作的图形
self.recover = [] # 保存恢复操作的图形
self.canvas.bind("<Button-1>", self.canvas_click) # 绑定鼠标点击事件
self.canvas.bind("<B1-Motion>", self.canvas_draw) # 绑定鼠标拖动事件
self.canvas.bind("<ButtonRelease-1>", self.canvas_release) # 绑定鼠标释放事件
self.create_right_click_menu() # 创建右键菜单
self.tool = "pen" # 默认使用笔工具
def create_right_click_menu(self):
menu = tk.Menu(self.win, tearoff=0)
menu.add_command(label="撤销", command=lambda: self.canvas_re(rev=1))
menu.add_command(label="重做", command=lambda: self.canvas_re(rec=1))
menu.add_command(label="清除", command=self.canvas_clear)
self.canvas.bind("<Button-3>", lambda event: menu.post(event.x_root, event.y_root))
def canvas_click(self, event):
if self.tool == "line" or self.tool == "circle":
self.start_point = [event.x, event.y]
self.canvas_store()
elif self.tool == "pen":
self.canvas_store()
self.draw_point = [event.x, event.y]
def canvas_draw(self, event):
if self.tool == "pen":
item = self.canvas.create_line(self.draw_point[0], self.draw_point[1], event.x, event.y, fill="#476042", width=1, tags="line")
self.revoke[-1].append(("line", self.canvas.coords(item)))
self.draw_point = [event.x, event.y]
def canvas_release(self, event):
if self.tool == "line":
item = self.canvas.create_line(self.start_point[0], self.start_point[1], event.x, event.y, fill="#476042", width=1, tags="line")
self.revoke[-1].append(("line", self.canvas.coords(item)))
elif self.tool == "circle":
radius = math.sqrt((event.x - self.start_point[0]) ** 2 + (event.y - self.start_point[1]) ** 2)
item = self.canvas.create_oval(self.start_point[0] - radius, self.start_point[1] - radius,
self.start_point[0] + radius, self.start_point[1] + radius,
outline="#476042", width=1, tags="circle")
self.revoke[-1].append(("circle", self.canvas.coords(item)))
def canvas_store(self):
if len(self.revoke) < len(self.recover):
self.recover = self.recover[:len(self.revoke)]
self.revoke.append([])
def canvas_re(self, rev=0, rec=0):
if rev and self.revoke:
items = self.revoke.pop()
self.recover.append(items)
for item in items:
if item[0] == "line":
self.canvas.delete(self.canvas.find_withtag("line")[-1])
else:
self.canvas.delete(self.canvas.find_withtag("circle")[-1])
elif rec and self.recover:
items = self.recover.pop()
self.revoke.append(items)
for item in items:
if item[0] == "line":
self.canvas.create_line(item[1], fill="#476042", width=1, tags="line")
else:
self.canvas.create_oval(item[1], outline="#476042", width=1, tags="circle")
def canvas_clear(self):
self.canvas.delete("line", "circle")
self.revoke = []
self.recover = []
def center_window(self):
self.win.geometry('%dx%d+%d+%d' % (self.width, self.height + 40, # 增加按钮框架高度
(self.win.winfo_screenwidth() - self.width) / 2,
(self.win.winfo_screenheight() - self.height - 40) / 2)) # 减去按钮框架高度
def use_pen(self):
self.tool = "pen"
def use_line(self):
self.tool = "line"
def use_circle(self):
self.tool = "circle"
tkinter_example()
运行效果:
数学函数作图
下面是一个数学函数作图——熠函数绘图工具。取自https://v-wb.youku.com/v_show/id_XNDYzMDc0MTYyOA==.html仅做少量修订。
先给出运行效果图:
特别提示:若显示的图像太小看不清,使用“+ ”按钮放大!
【使用说明:
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()
更过例子可见 https://blog.csdn.net/cnds123/article/details/128091966