用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('', 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('', 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("",buttonCallBack)
showText="()"
for i in range(2):
b=Button(root,text=showText[i],width=7)
b.grid(row=6,column=2+i)
b.bind("",buttonCallBack)
b=Button(root,text="=")
b.grid(row=6,columnspan=2,sticky="we")
b.bind("",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('', self.click)
# 为鼠标左键的双击事件绑定事件处理方法
if b['text'] == 'C': b.bind('', 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 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("", 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("", self.myline)
elif name == "lineArrow":
varText.set("画箭头")
self.drawPad.bind("", self.mylineArrow)
elif name == "rect":
varText.set("画矩形")
self.drawPad.bind("", self.myRect)
elif name == "pen":
varText.set("画笔")
self.drawPad.bind("", self.myPen)
elif name == "erasor":
varText.set("橡皮")
self.drawPad.bind("", 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少儿编程作品-科学绘图工具-义乌东河小学孙璟熠-教育-高清完整正版视频在线观看-优酷仅做少量修订。
先给出运行效果图:
【使用说明:
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("",_2)
a.bind_all("",_3)
a.bind_all("",enlarge)
a.bind_all("",narrow)
a.bind_all("",add)
a.bind_all("",pi)
a.bind_all("",save)
a.bind_all("",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("",show)
l.bind("",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()