目录
1.tkinter 模块使用
tkinter 介绍
创建一个简单的 GUI
给窗口添加小构件
小构件种类
小构件参数说明
查看某个小构件的所有方法和属性
常用小构件用法
Button:按钮用法
Label:标签用法
Entry:输入框用法
Combobox:下拉框用法
数据显示小构件
Listbox 显示数据
Text 文本编辑器(也可展示数据)
Treeview:表格数据
Treeview:树状数据
2.画布类 Canvas
3.几何管理器
网格管理器
包管理器
位置管理器
4.显示图像
5.菜单
下拉菜单
弹出菜单
6.鼠标、按键事件和绑定
7.动画
原理
示例1:滑动窗口
示例2:四辆汽车比赛
示例3:转动的时钟
8.滚动条
9.选择或者输入对话框
10.作业练习
简单的文本编辑器
贷款计算器
查找四个连续相同的数字
井字游戏
拖动小构件
显示 n 个颜色随机的球
n 个随机运动的球
画函数图像
1.tkinter 模块使用
tkinter 介绍
创建一个简单的 GUI
import tkinter
mytk = tkinter.Tk() # Tk 是一个类,用来创建一个窗口
mytk.title("hello tkinter") # 设置窗口的名字,默认名字为 tk
mytk.geometry("600x400+200+0") # 宽度为 600,高度为 400,x,y 窗口左上角的坐标
mytk.mainloop() # 启动
给窗口添加小构件
小构件种类
Tkinter小构件种类 | |
小构件类 | 描述 |
Button | 单一按钮 |
Checkbutton | 多种选择时的多选按钮 |
Radiobutton | 多种选择时的单选按钮 |
Entry | 文本输入框 |
Frame | 局部框架。包含其它小构件的一个容器小构件。 |
Canvas | 画布。结构化的图形,用于绘制图形、创建图形编辑器。或者实现自定的小构件类 |
Menu | 菜单栏。可实现下拉菜单或者弹出菜单。 |
Menubutton | 实现下拉菜单的菜单按钮 |
Label | 标签。用来显示文本或者图像。 |
Message | 显示文本,类似标签,但是能自定将文本放在指定的宽度或高度比内 |
Text | 格式化的文本显示,允许不同的风格和属性显示文本,还可以编辑文本,也支持内嵌的图片和窗口。 |
小构件参数说明
- 第一个参数总是父容器(就是小构件将要放置在哪个容器里)
-
命名参数 ,text 或者 image,可以通过插入换行字符\n 来多行显示文本,text = "大威\n 天龙"
-
字体参数 ,font,与 text 参数配合使用,比如font = "Times 20 bold",font = "Times 20 bold italic overstrike underline",font = ("华文彩云", 260)
-
颜色参数 ,fg 和 bg,"red"、"yellow",也可以使用字符串"#RRGGBB",比如"#AB84F9"。fg 默认黑色,bg 默认白色。
-
对齐 参数 , justify , 设置标签、按钮、输入框等的内容靠左还是靠右,默认居中
-
鼠标参数 ,cursor,"arrow"(默认)、"circle"、"cross"
查看某个小构件的所有方法和属性
import tkinter
for item in dir(tkinter.Label):
print(item)
常用小构件用法
Button:按钮用法
import tkinter
import os
window = tkinter.Tk()
window.geometry("600x400+0+0")
def func():
print("正在打开记事本")
os.system("notepad")
button1 = tkinter.Button(window, text="打开记事本", command=func)
button1.pack()
window.mainloop()
Label:标签用法
例子1:基础用法
import tkinter
window = tkinter.Tk()
window.geometry("600x400+0+0")
label1 = tkinter.Label(window, text="这是第一个标签", bg="red")
label1.pack()
label2 = tkinter.Label(window, text="这是第二个标签", bg="red")
label2["text"] = "这是第二个标签:新的内容" # 改变内容
label2["fg"] = "white" # 改变颜色
label2.pack()
window.mainloop()
例子2:搭配button按钮和变量
import tkinter
window = tkinter.Tk()
window.geometry("600x400+0+0")
v1 = tkinter.StringVar()
v2 = tkinter.StringVar()
label1 = tkinter.Label(window, text="这是第一个标签", bg="yellow", textvariable=v1)
label1.pack()
label2 = tkinter.Label(window, text="这是第二个标签", bg="blue", textvariable=v2)
label2["text"] = "这是第二个标签:新的内容" # 改变内容
label2["fg"] = "white" # 改变颜色
label2.pack()
def func(var1, var2):
content1 = var1.get()
content2 = var2.get()
print(content1)
print(content2)
var1.set("[var1]" + content1)
var2.set("[var2]" + content2)
button1 = tkinter.Button(window, text="搜索", command=lambda: func(v1, v2))
button1.pack()
window.mainloop()
Radiobutton:单选按钮用法
import tkinter
window = tkinter.Tk()
window.geometry("600x400+0+0")
label1 = tkinter.Label(window, text="这是一个标签", bg="green")
label1.pack()
def change_label_color(label, var):
if var.get() == "R":
label["bg"] = "red"
elif var.get() == "Y":
label["bg"] = "yellow"
v1 = tkinter.StringVar()
rbRed = tkinter.Radiobutton(window, text="red", bg="red", variable=v1, value='R',
command=lambda: change_label_color(label1, v1))
rbRed.pack()
rbYellow = tkinter.Radiobutton(window, text="yellow", bg="yellow", variable=v1, value='Y',
command=lambda: change_label_color(label1, v1))
rbYellow.pack()
window.mainloop()
Checkbutton:多选按钮用法
import tkinter
window = tkinter.Tk()
window.geometry("600x400+0+0")
label1 = tkinter.Label(window, text="这是一个标签", bg="yellow")
label1.pack()
def change_label_text(label, var1, var2):
if var1.get() == 1 and var2.get() == 1:
label["text"] = "中国和美国"
elif var1.get() == 1:
label["text"] = "中国"
else:
label["text"] = "美国"
v1 = tkinter.IntVar()
v2 = tkinter.IntVar()
c1 = tkinter.Checkbutton(window, text="中国", variable=v1,
command=lambda: change_label_text(label1, v1, v2))
c1.pack()
c2 = tkinter.Checkbutton(window, text="美国", variable=v2,
command=lambda: change_label_text(label1, v1, v2))
c2.pack()
window.mainloop()
Entry:输入框用法
第一种:输入直接获取值
import tkinter
import os
def go(entry1, entry2):
print(entry1.get())
print(entry2.get())
if entry2.get() == "记事本":
os.system("notepad")
else:
pass
win = tkinter.Tk()
button = tkinter.Button(win, text="搜索", command=lambda: go(e1, e2))
button.pack()
e1 = tkinter.Entry(win, width=50, bg="red", fg="black")
e2 = tkinter.Entry(win, show="*", width=50, bg="yellow", fg="black") # show="*"表示让内容不显示出来
e1.pack()
e2.pack()
win.mainloop()
第二种:引入变量获取值
label1.pack()
def change_label_text(label, var1, var2):
# var1.set("[var1]" + var1.get())
# var2.set("[var2]" + var2.get())
label["text"] = var1.get() + var2.get()
button1 = tkinter.Button(win, text="点击这里根据输入框改变标签内容的按钮",
command=lambda: change_label_text(label1, v1, v2))
button1.pack()
v1 = tkinter.StringVar()
entry1 = tkinter.Entry(win, width=50, fg="green", textvariable=v1)
v2 = tkinter.StringVar()
entry2 = tkinter.Entry(win, show="*", width=50, fg="red", textvariable=v2)
entry1.pack()
entry2.pack()
win.mainloop()
Combobox:下拉框用法
import tkinter
from tkinter import ttk
def go(com_list, _event, var): # 处理事件
print(var.get())
var.set("[xxx]" + var.get())
print(_event)
print(com_list.get()) # 选中当前的值
win = tkinter.Tk() #
v1 = tkinter.StringVar() # 窗体自带的文本,新建一个值
combox_list = ttk.Combobox(win, textvariable=v1) # 初始化
combox_list["values"] = ("1", "2", "3", "4")
combox_list.current(0) # 默认选择第一个
combox_list.bind("<<ComboboxSelected>>", lambda event: go(combox_list, event, v1)) # 绑定事件
combox_list.pack()
win.mainloop() # 进入消息循环
当事件被触发时,会产生event对象,lambda表达式会接收一个名为event的参数,并调用go函数,将combox_list和event作为参数传递。
在go函数中,您使用了com_list.get()来获取组合框的值,也可以用v1.get()用于获取通过StringVar关联的值。一般用关联的变量来或获取组合框的值。
数据显示小构件
Listbox 显示数据
import tkinter
win = tkinter.Tk() # 构造窗体
mylist = tkinter.Listbox(win, width=100) # 列表框
mylist.pack()
# 内容插入
for item in ["1", "asdsa", "asdsadsa", "asdsadsad"]:
mylist.insert(tkinter.END, item) # 尾部插入
win.mainloop() # 进入消息循环
效果
Text 文本编辑器(也可展示数据)
import tkinter
win = tkinter.Tk()
text = tkinter.Text(win)
text.insert(tkinter.INSERT, "文本编辑器\r\n")
text.insert(tkinter.INSERT, "要掌握\r\n")
text.insert(tkinter.INSERT, "用来编辑文本和数据\r\n")
text.insert(tkinter.INSERT, "间接用来展示数据\r\n")
text.pack()
win.mainloop()
效果
Treeview:表格数据
import tkinter
from tkinter import ttk # 导入内部包
win = tkinter.Tk()
tree = ttk.Treeview(win) # 表格
tree['columns'] = ('姓名', '年龄', '身高') # 像字典一样创建列对象
tree.column("姓名", width=100) # 调整列的宽度,但不显示列
tree.column("年龄", width=100)
tree.column("身高", width=100)
tree.heading("姓名", text="姓名-name") # 显示表头
tree.heading("年龄", text="年龄-age")
tree.heading("身高", text="身高-tall")
tree.insert("", 0, text="line1", values=('1', '2', '3')) # 插入的行数
tree.insert("", 1, text="line2", values=('a', 'b', 'c'))
tree.insert("", 2, text="line3", values=('我', '爱', '你'))
tree.pack()
win.mainloop()
效果
Treeview:树状数据
import tkinter
from tkinter import ttk
win = tkinter.Tk()
tree = ttk.Treeview(win, height=10)
myid1 = tree.insert("", 0, "中国", text="中国 China", values=("1",))
# 前两个参数:parent,index。parent 为""表示根目录。index 为插入的位置。open 参数,布尔变量,是否显示子树枝
myid11 = tree.insert(myid1, 0, "广东", text="中国广东", values=("2",))
myid111 = tree.insert(myid11, 0, "广州", text="中国广东广州", values=("2",))
myid12 = tree.insert(myid1, 1, "江苏", text="中国江苏", values=("3",))
myid13 = tree.insert(myid1, 1, "四川", text="中国四川", values=("4",))
myid2 = tree.insert("", 1, "美国", text="美国 USA", values=("5",))
myid21 = tree.insert(myid2, 1, "加州", text="美国加州", values=("6",))
print(tree.item(myid11).keys())
print(dir(tree.item(myid11)))
tree.pack()
win.mainloop()
效果
2.画布类 Canvas
坐标系与参数说明
示例代码
from tkinter import *
class CanvasDemo:
def __init__(self):
window = Tk()
window.title("Canvas Demo")
self.canvas = Canvas(window, width=200, height=100, bg="white")
self.canvas.pack()
frame = Frame(window)
frame.pack()
btRectangle = Button(frame, text="Rectangle", command=self.displayRect)
btOval = Button(frame, text="Oval", command=self.displayOval)
btArc = Button(frame, text="Arc", command=self.displayArc)
btPolygon = Button(frame, text="Polygon", command=self.displayPolygon)
btLine = Button(frame, text="Line", command=self.displayLine)
btString = Button(frame, text="String", command=self.displayString)
btClear = Button(frame, text="Clear", command=self.clearCanvas)
btRectangle.grid(row=1, column=1)
btOval.grid(row=1, column=2)
btArc.grid(row=1, column=3)
btPolygon.grid(row=1, column=4)
btLine.grid(row=1, column=5)
btString.grid(row=1, column=6)
btClear.grid(row=1, column=7)
window.mainloop()
def displayRect(self):
self.canvas.create_rectangle(10, 10, 190, 90, tags="rect")
def displayOval(self):
self.canvas.create_oval(10, 10, 190, 90, fill="red", tags="oval")
def displayArc(self):
self.canvas.create_arc(10, 10, 190, 90, start=0, extent=90, width=8, fill="red", tags="arc")
def displayPolygon(self):
self.canvas.create_polygon(10, 10, 190, 90, 30, 50, tags="polygon")
def displayLine(self):
self.canvas.create_line(10, 10, 190, 90, fill="red", tags="line") # Arrow 参数末端为 last
self.canvas.create_line(10, 90, 190, 10, width=9, arrow="last", activefill="blue", tags="line")
def displayString(self):
self.canvas.create_text(60, 40, text="Hi, I am a string", font="Times 10 bold underline", tags="String")
def clearCanvas(self):
self.canvas.delete("rect", "oval", "arc", "polygon", "line", "String")
CanvasDemo()
效果
点击按钮后
3.几何管理器
网格管理器
- row 和 column 参数可以将小构件放在特定的行和列内
- rowspan 和 columnspan 参数将小构件放在多行和多列中
- sticky 参数将小构件放在所在行列的东南西北东北东南西北西南其中一个方位,命名常量 E, S, W, N, NW, NE, SW, SE
- padx 和 pady 参数设置小构件四周边界距离单元格边界的距离,默认情况下填充为 0
- ipadx 和 ipady 参数设置小构件内的文字距离小构件边界的距离,默认情况下填充为 0
- 这两种选项情况下,小构件内的文字的大小不会发生变化,但是小构件和单元格会因边距太大时而自动调整
from tkinter import *
class GridManagerDemo:
window = Tk()
window.title("Grid Manager Demo")
message = Message(window, text="The message widget occupies three rows and two columns")
message.grid(row=1, column=1, rowspan=3, columnspan=2)
Label(window, text="First Name:").grid(row=1, column=3)
Entry(window).grid(row=1, column=4,padx=4, pady=5)
Label(window, text="Last Name:").grid(row=2, column=3)
Entry(window).grid(row=2, column=4)
Button(window, text="Get Name").grid(row=3, padx=5, pady=5, column=4, sticky=E)
window.mainloop()
GridManagerDemo()
效果展示
包管理器
- side 参数:在父容器内,设置小构件放置在下一个小构件上边或下边或左边或右边,命名常量 LEFT、RIGHT、TOP(默认)、BOTTOM
- fill 参数:设置当前小构件垂直或水平占满它在父容器的所在位置,命名常量 X、Y、BOTH 填充水平、垂直、两个方向。使用 fill 参数后,小构件的大小会跟着窗口自动变大或者变小。
- expand 参数:会自动将整个父容器多出的空间(如果有的话),自动平均分配给所有 expand 值为非零的所有构件。默认情况下 expand 值为 0,意思就是小构件框本身是多大就占多大。
from tkinter import *
class PackManagerDemo:
def __init__(self):
window = Tk()
window.geometry("600x400+0+0")
window.title("Pack Manager Demo 1")
Label(window, text="Blue", bg="blue").pack(side=LEFT)
Label(window, text="Red", bg="red").pack(side=LEFT, fill=BOTH, expand=1)
Label(window, text="Green", bg="green").pack(fill=Y)
window.mainloop()
PackManagerDemo()
效果
位置管理器
from tkinter import *
class PlaceManagerDemo:
def __init__(self):
window = Tk()
window.title("Place Manager Demo")
Label(window, text="Blue", bg="blue").place(x=20, y=20)
Label(window, text="Red", bg="red").place(x=50, y=50)
Label(window, text="Green", bg="green").place(x=80, y=80)
window.mainloop()
PlaceManagerDemo()
效果
import tkinter
win = tkinter.Tk()
label1 = tkinter.Label(win, text="AA1", bg="blue")
label2 = tkinter.Label(win, text="A12", bg="yellow")
label3 = tkinter.Label(win, text="123", bg="red")
label1.place(x=10, y=10, anchor=tkinter.NW) # 等价于:label1.place(x=10, y=10)
label2.place(x=100, y=150, anchor=tkinter.E) # 设置东所在的位置为x=100, y=150
label3.place(x=10, y=150, anchor=tkinter.SW)
win.mainloop()
效果
import tkinter
win = tkinter.Tk()
win.geometry("500x500+300+0")
label = tkinter.Label(win, text="hello python")
label.pack()
label2 = tkinter.Label(win,
anchor=tkinter.E, # 位置 n, ne, e, se, s, sw, w, nw, center
bg="blue",
fg="yellow",
text="gogogo",
width=20,
height=10)
label2.pack()
win.mainloop() # 进入消息循环
效果
4.显示图像
- 创建图像时图像来源必须是 GIF 格式
- 创建图像,photoName = PhotoImage(file = imagefilename)
- 可以向标签、按钮、多选按钮、单选按钮添加图像
- 添加的画像相当于原来 text 的作用。也就是可以用文字 text,也可以用图像 image
- 还可以在画布里添加图像,使用 create_image(x = 90, y = 50, image = chinaImage)
示例代码
from tkinter import *
class ImageDemo:
def __init__(self):
window = Tk()
window.title("Image Demo")
caImage = PhotoImage(file="image/ca.gif")
chinaImage = PhotoImage(file="image/china.gif")
leftImage = PhotoImage(file="image/left.gif")
rightImage = PhotoImage(file="image/right.gif")
usImage = PhotoImage(file="image/usIcon.gif")
ukImage = PhotoImage(file="image/ukIcon.gif")
crossImage = PhotoImage(file="image/x.gif")
circleImage = PhotoImage(file="image/o.gif")
frame1 = Frame(window)
frame1.pack()
Label(frame1, image=caImage).pack(side=LEFT)
canvas = Canvas(frame1)
canvas.create_image(90, 50, image=chinaImage)
canvas["width"] = 200
canvas["height"] = 100
canvas.pack(side=LEFT)
frame2 = Frame(window)
frame2.pack()
Button(frame2, image=leftImage).pack(side=LEFT)
Button(frame2, image=rightImage).pack(side=LEFT)
Checkbutton(frame2, image=usImage).pack(side=LEFT)
Checkbutton(frame2, image=ukImage).pack(side=LEFT)
Radiobutton(frame2, image=crossImage).pack(side=LEFT)
Radiobutton(frame2, image=circleImage).pack(side=LEFT)
window.mainloop()
ImageDemo()
5.菜单
下拉菜单
- 创建菜单栏:menubar = Menu(window)
- 放置菜单栏:window.config(menu = menubar)
- 创建菜单:menuName = Menu(menubar, tearoff = 0)
- 设置菜单名字:menubar.add_cascade(label = “菜单名字”, menu = menuName)
- 给菜单添加条目:menuName.add_command(label = “条目名字”, command = self.xxxx)
from tkinter import *
class MenuDemo:
def __init__(self):
window = Tk()
window.title("Menu Demo")
# 创建菜单栏、菜单、菜单条目==================================
menubar = Menu(window)
window.config(menu=menubar)
operationMenu = Menu(menubar, tearoff=0)
# tearoff 被设置为 0,它表明菜单不能移出窗口
# 如果没有设置这个选项,可以将菜单复制多个单独从窗口中移出来在电脑屏幕任何地方使用
menubar.add_cascade(label="Operation", menu=operationMenu)
operationMenu.add_command(label="Add", command=self.add)
operationMenu.add_command(label="Subtract", command=self.subtract)
operationMenu.add_separator()
# 在不同的菜单栏条目之间画一根分割线
operationMenu.add_command(label="Multiply", command=self.multiply)
operationMenu.add_command(label="Divide", command=self.divide)
exitmenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Exit", menu=exitmenu)
exitmenu.add_command(label="Quit", command=window.quit)
# 给 frame0 添加图像按钮=======================================
frame0 = Frame(window)
frame0.grid(row=1, column=1, sticky=W)
# 创建图像
plusImage = PhotoImage(file="image/plus.gif")
minusImage = PhotoImage(file="image/minus.gif")
timesImage = PhotoImage(file="image/times.gif")
divideImage = PhotoImage(file="image/divide.gif")
# 创建图像按钮
Button(frame0, image=plusImage, command=self.add).grid(row=1, column=1, sticky=W)
Button(frame0, image=minusImage, command=self.subtract).grid(row=1, column=2, sticky=W)
Button(frame0, image=timesImage, command=self.multiply).grid(row=1, column=3, sticky=W)
Button(frame0, image=divideImage, command=self.divide).grid(row=1, column=4, sticky=W)
# 给 frame1 添加标签和文本输入框============================
frame1 = Frame(window)
frame1.grid(row=2,column=1, pady=10)
Label(frame1, text="Number 1:").pack(side=LEFT)
self.v1 = StringVar()
Entry(frame1, width=20, textvariable=self.v1, justify=RIGHT).pack(side=LEFT)
# width 设置的是文本输入框的宽度
Label(frame1, text="Number 2:").pack(side=LEFT)
self.v2 = StringVar()
Entry(frame1, width=5, textvariable=self.v2, justify=RIGHT).pack(side=LEFT)
Label(frame1, text="Number 3:").pack(side=LEFT)
self.v3 = StringVar()
Entry(frame1, width=5, textvariable=self.v3, justify=RIGHT).pack(side=LEFT)
# 给 frame2 添加按钮 =====================================
frame2 = Frame(window)
frame2.grid(row=3, column=1, pady=10, sticky=E)
Button(frame2, text="Add", command=self.add).pack(side=LEFT)
Button(frame2, text="Subtract", command=self.subtract).pack(side=LEFT)
Button(frame2, text="Multiply", command=self.multiply).pack(side=LEFT)
Button(frame2, text="Divide", command=self.divide).pack(side=LEFT)
mainloop()
def add(self):
self.v3.set(eval(self.v1.get()) + eval(self.v2.get()))
def subtract(self):
self.v3.set(eval(self.v1.get()) - eval(self.v2.get()))
def multiply(self):
self.v3.set(eval(self.v1.get()) * eval(self.v2.get()))
def divide(self):
self.v3.set(eval(self.v1.get()) / eval(self.v2.get()))
MenuDemo()
弹出菜单
- 创建一个 Menu 的实例
- 向它添加条目
- 将一个小构件和一个事件绑定以弹出菜单
示例代码
from tkinter import *
class PopupMenuDemo:
def __init__(self):
window = Tk()
window.title("Popup Menu Demo")
# 创建一个弹出菜单======
self.menu = Menu(window, tearoff=0)
self.menu.add_command(label="Draw a line", command=self.displayLine)
self.menu.add_command(label="Draw a oval", command=self.displayOval)
self.menu.add_command(label="Draw a rectangle", command=self.displayRect)
self.menu.add_command(label="Clear", command=self.clearCanvas)
# 在 window 中放置一个画布
self.canvas=Canvas(window, width=200, height=100, bg="white")
self.canvas.pack()
# 将弹出菜单绑定到画布======
self.canvas.bind("<Button-3>", self.popup)
window.mainloop()
def displayRect(self):
self.canvas.create_rectangle(10, 10, 190, 90, tags="rect")
def displayOval(self):
self.canvas.create_oval(10, 10, 190, 90, tags="oval")
def displayLine(self):
self.canvas.create_line(10, 10, 190, 90, tags="line")
self.canvas.create_line(10, 90, 190, 10, tags="line")
def clearCanvas(self):
self.canvas.delete("rect", "oval", "line")
# 展示弹出菜单======
def popup(self, event):
self.menu.post(event.x_root, event.y_root)
PopupMenuDemo()
运行后
鼠标右键效果
6.鼠标、按键事件和绑定
def handler(event): # 注意有 event 这个关键字
menu.post(event.x_root, event.y_root) # 调用事件属性进行某些操作
例子1:鼠标和键盘事件响应
from tkinter import *
class MouseKeyEventDemo:
def __init__(self):
window = Tk()
window.title("Mouse and Key Event Demo")
canvas = Canvas(window, bg="white", width=200, height=100)
canvas.pack(side=LEFT)
canvas2 = Canvas(window, bg="red", width=200, height=100)
canvas2.pack(side=LEFT)
canvas.bind("<Button-1>", self.processMouseEvent)
canvas2.bind("<Button-1>", self.processMouseEvent)
canvas.bind("<Key>", self.processKeyEvent)
canvas.focus_set() # 在画布上获取焦点,以便于从键盘上获取输入,配合 key 事件
window.mainloop()
def processMouseEvent(self,event):
print("-----Mouse Info-----")
print("Clicked at", event.x_root, event.y_root)
print("Position in the screen", event.x_root, event.y_root)
print("Which button is clicked ?", event.num)
def processKeyEvent(self,event):
print("-----Key Info-----")
print("keysym ?", event.keysym)
print("char ?", event.char)
print("keycode ?", event.keycode)
MouseKeyEventDemo()
运行效果
import tkinter
def call(event):
print(event.x, event.y)
win = tkinter.Tk()
frame = tkinter.Frame(win, width=200, height=200)
frame.bind("<Motion>", call)
frame.pack()
win.mainloop()
运行后,随着鼠标不断移动,会不断显示鼠标所在的位置
例子3:两圆相交
import math
from tkinter import *
class Circle2D:
def __init__(self, x = 0, y = 0, radius = 0):
self.x = x
self.y = y
self.radius = radius
def getX(self):
return self.x
def getY(self):
return self.y
def getRadius(self):
return self.radius
def setX(self, x):
self.x = x
def setY(self, y):
self.y = y
def setRadius(self, radius):
self.radius = radius
def getPerimeter(self):
return 2 * math.pi * self.radius
def getArea(self):
return math.pi * self.radius * self.radius
def containsPoint(self, x, y):
d = distance(x, y, self.x, self.y)
return d <= self.radius
def containsCircle(self, circle):
d = distance(circle.x, circle.y, self.x, self.y)
return d + circle.radius <= self.radius
def overlapsCircle(self, circle):
return distance(self.x, self.y, circle.x, circle.y) <= self.radius + circle.radius
# 两点之间距离的函数
def distance(x1, y1, x2, y2):
d2 = (x1 - x2) ** 2 + (y1 - y2) ** 2
return math.sqrt(d2)
# 画圆的函数
def displayCircle(c, text):
canvas.delete(text)
canvas.create_oval(c.x - c.radius, c.y - c.radius, c.x + c.radius, c.y + c.radius, tags=text)
canvas.create_text(c.x, c.y, text=text, tags=text)
# 鼠标绑定事件
def mouseMoved(event):
if c1.containsPoint(event.x, event.y):
c1.setX(event.x)
c1.setY(event.y)
displayCircle(c1, "c1")
if c1.overlapsCircle(c2):
label["text"] = "两圆相交"
else:
label["text"] = "两圆不相交"
elif c2.containsPoint(event.x, event.y):
c2.setX(event.x)
c2.setY(event.y)
displayCircle(c2, "c2")
if c1.overlapsCircle(c2):
label["text"] = "两圆相交"
else:
label["text"] = "两圆不相交"
window = Tk()
window.title("两个圆之间的相互关系")
label = Label(window, text="两圆相交")
label.pack()
width = 300
height = 100
canvas = Canvas(window, width=width, height=height, bg="white")
canvas.pack()
canvas.bind("<B1-Motion>", mouseMoved)
c1 = Circle2D(50, 50, 30)
c2 = Circle2D(30, 40, 20)
displayCircle(c1, "c1")
displayCircle(c2, "c2")
window.mainloop()
效果
拖动图上的圆
7.动画
原理
示例1:滑动窗口
from tkinter import *
class ControlAnimation:
def __init__(self):
window = Tk()
window.title("Control Animation Demo")
self.width = 250
self.canvas = Canvas(window, width=self.width, height=50, bg="white")
self.canvas.pack()
frame = Frame(window)
frame.pack()
btStop = Button(frame, text="Stop", command=self.stop)
btStop.pack(side=LEFT)
btResume = Button(frame, text="Resume", command=self.resume)
btResume.pack(side=LEFT)
btFaster = Button(frame, text="Faster", command=self.faster)
btFaster.pack(side=LEFT)
btSlower = Button(frame, text="Slower", command=self.slower)
btSlower.pack(side=LEFT)
self.x = 0 # 设置起点和要变化的方向
self.sleepTime = 100 # 睡眠时间,用来控制速度
self.canvas.create_text(self.x, 30, text="Message Moving", tags="text")
self.dx = 3
self.isStopped = False
self.animate() # 主函数,设置动画主要运动规则
window.mainloop()
def stop(self):
self.isStopped = True
def resume(self):
self.isStopped = False
self.animate()
def faster(self):
if self.sleepTime > 5:
self.sleepTime -= 20
print("当前的间隔时间是 ",self.sleepTime," 毫秒")
def slower(self):
if self.sleepTime > 5:
self.sleepTime += 20
print("当前的间隔时间是 ", self.sleepTime, " 毫秒")
def animate(self):
while not self.isStopped:
self.canvas.move("text", self.dx, 0)
self.canvas.after(self.sleepTime)
self.canvas.update()
if self.x < self.width:
self.x += self.dx
else:
self.x = 0
self.canvas.delete("text")
self.canvas.create_text(self.x, 30, text="Message Moving", tags="text")
ControlAnimation()
示例2:四辆汽车比赛
from tkinter import *
class RaceCar(Canvas):
def __init__(self, master, width, height):
super().__init__(master, width=width, height=height)
self["bg"] = "white"
self.sleepTime = 100
self.x = 10
self.y = 50
self.displayCar()
def displayCar(self):
self.delete("car")
self.create_oval(self.x + 10, self.y - 10, self.x + 20, self.y, fill="black", tags="car")
self.create_oval(self.x + 30, self.y - 10, self.x + 40, self.y, fill="black", tags="car")
self.create_rectangle(self.x, self.y - 20, self.x + 50, self.y - 10, fill="green", tags="car")
self.create_polygon(self.x + 10, self.y - 20,
self.x + 20, self.y - 30,
self.x + 30, self.y - 30,
self.x + 40, self.y - 20,
fill="red", tags="car")
def run():
while True:
for car in cars:
if car.x < int(car["width"]):
car.displayCar()
car.x += 2
else:
car.x = 0
car.after(car.sleepTime)
car.update()
window = Tk()
window.title("比赛的汽车")
width = 250
height = 48
cars = []
for i in range(4):
cars.append(RaceCar(window, width=width, height=height))
cars[i].pack()
run()
window.mainloop()
示例3:转动的时钟
import time
import math
from tkinter import *
class Clock(Canvas):
def __init__(self, master, side):
super().__init__(master, width=side, height=side)
self.side = side
self["bg"] = "white"
# 画外圈圆
self.drawSideCircle()
# 画刻度
self.drawCalibration()
# 画针和下面的时间信息
self.displayTime()
def drawSideCircle(self):
# 画外圈圆
self.create_oval(self.side * 0.1, self.side * 0.1, self.side * 0.9, self.side * 0.9, tags="oval")
def drawCalibration(self):
# 画刻度
r = self.side * 0.4
d_angle = 360 / 60
angle = 0
hour = 3
while angle < 360:
linecolor = "black"
if angle % (5 * d_angle) == 0:
linecolor = "red"
dx = r * math.cos(angle * math.pi / 180)
dy = r * math.sin(angle * math.pi / 180)
x1, y1 = self.side / 2 + dx, self.side / 2 - dy
x2, y2 = self.side / 2 + dx * 0.9, self.side / 2 - dy * 0.9
self.create_line(x1, y1, x2, y2, fill=linecolor, tags="line")
if angle % (5 * d_angle) == 0:
x3, y3 = self.side / 2 + dx * 0.8, self.side / 2 - dy * 0.8
self.create_text(x3, y3, text=str(hour), tags="line")
hour -= 1
if hour == 0:
hour = 12
angle += d_angle
def displayTime(self):
# 获取当前的小时、分钟、秒数
timenow = time.localtime()
current_hour = timenow.tm_hour
current_minute = timenow.tm_min
current_second = timenow.tm_sec
if current_second >= 60:
current_minute += 1
current_second -= 60
if current_minute == 60:
current_minute = 0
current_hour += 1
if current_hour == 24:
current_hour = 0
# 画秒针
self.delete("second")
r = self.side * 0.4
x0, y0 = self.side / 2, self.side / 2
angle_second = 90 - 6 * current_second
dx_second = r * math.cos(angle_second * math.pi / 180)
dy_second = r * math.sin(angle_second * math.pi / 180)
x4, y4 = self.side / 2 + dx_second * 0.7, self.side / 2 - dy_second * 0.7
self.create_line(x0, y0, x4, y4, fill="red", arrow="last", tags="second")
# 画分针
self.delete("minute")
r = self.side * 0.4
x0, y0 = self.side / 2, self.side / 2
angle_minute = 90 - 6 * current_minute
dx_minute = r * math.cos(angle_minute * math.pi / 180)
dy_minute = r * math.sin(angle_minute * math.pi / 180)
x5, y5 = self.side / 2 + dx_minute * 0.5, self.side / 2 - dy_minute * 0.5
self.create_line(x0, y0, x5, y5, fill="blue", arrow="last", tags="minute")
# 画时针
self.delete("hour")
r = self.side * 0.4
x0, y0 = self.side / 2, self.side / 2
angle_hour = 90 - 30 * current_hour
dx_hour = r * math.cos(angle_hour * math.pi / 180)
dy_hour = r * math.sin(angle_hour * math.pi / 180)
x6, y6 = self.side / 2 + dx_hour * 0.3, self.side / 2 - dy_hour * 0.3
self.create_line(x0, y0, x6, y6, fill="black", arrow="last", tags="line")
# 在最下面显示时间
self.delete("timedown")
second_down = str(0) + str(current_second) if current_second < 10 else str(current_second)
time_down = str(current_hour) + ":" + str(current_minute) + ":" + second_down
self.create_text(self.side / 2, self.side * 0.95, text = time_down, tags = "timedown")
def clockDynamicChange():
while True:
for clock in clocks:
clock.displayTime()
clock.after(1000)
clock.update()
window = Tk()
window.title("四个时钟")
clocks = []
for i in range(4):
clocks.append(Clock(window, 300))
clocks[i].pack(side=LEFT)
clockDynamicChange()
window.mainloop()
运行效果
8.滚动条
from tkinter import *
class ScrollText:
def __init__(self):
self.window = Tk()
self.window.title("Scroll Text Demo")
frame1 = Frame(self.window)
frame1.pack()
# 创建纵向滚动条
scrollbarY = Scrollbar(frame1)
scrollbarY.grid(row=1, column=2, sticky=NS)
# 创建横向滚动条
scrollbarX = Scrollbar(frame1, orient=HORIZONTAL, name="hbar") # 默认 vertical
scrollbarX.grid(row=2, column=1, rowspan=1, columnspan=2, sticky=EW)
# 创建需要绑定的小构件,以及绑定滚动条
# 若创建 Text 小构件时可加一个参数,wrap = WORD
text = Listbox(frame1, width=10, height=10, yscrollcommand=scrollbarY.set, xscrollcommand=
scrollbarX.set)
# text = Listbox(frame1, width = 10, height = 10)
# text.configure(yscrollcommand = scrollbarY.set, xscrollcommand = scrollbarX.set) ##滚动条关联
# text['yscrollcommand'] = scrollbarY.set
# text['xscrollcommand'] = scrollbarX.set
text.grid(row=1, column=1)
# 设置滚动条使得小构件移动的方式(垂直 or 左右)
# 注意只有当垂直滚动条的长度小于窗口高度时,或者横向滚动条的长度小于窗口宽度时,才可滑动
scrollbarY.config(command=text.yview)
scrollbarX.config(command=text.xview)
# scrollbarY['command'] = text.yview
# scrollbarX['command'] = text.xview
for i in range(100):
# text.delete('1.0', tkinter.END) # 小构件为 Text 时可用,清除文本框里的所有内容
text.insert(END, str(i) + " stringsssssssssssssssssss " + str(i)) # 文本自动插入内容显示
def show(self):
self.window.mainloop()
ScrollText = ScrollText()
ScrollText.show()
效果
9.选择或者输入对话框
用途:
- 显示特定消息警告
-
提示用户输入数字和字符串
import tkinter.messagebox
import tkinter.simpledialog
import tkinter.colorchooser
# 显示特定信息或警告
tkinter.messagebox.showinfo("对话框名字,它在对话框左上角", "对话框中间的内容")
tkinter.messagebox.showwarning("showwarning", "This is a warning")
tkinter.messagebox.showerror("showerror", "This is an error")
# 提示用户进行选择,并获取值
isYes = tkinter.messagebox.askyesno("askyesno", "Contiue ?")
print(isYes) # True 或者 False
isOk = tkinter.messagebox.askokcancel("askokcancel", "OK ?")
print(isOk) # True 或者 False
isYesNoCancel = tkinter.messagebox.askyesnocancel("askyesnocancel", "Yes, No, Cancel ?")
print(isYesNoCancel) # True 或者 False 或者 None
# 提示用户进行输入,并获取值
name = tkinter.simpledialog.askstring("askstring", "Enter your name")
print(name) # OK返回输入的内容,取消返回None,
age = tkinter.simpledialog.askinteger("askinteger", "Enter your age")
print(age) # OK返回输入的内容,输入非整数会报错,会让其重新输入,取消返回None,
weight = tkinter.simpledialog.askfloat("askfloat", "Enter your weight")
print(weight)
10.作业练习
简单的文本编辑器
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import asksaveasfilename
class FileEditor:
def __init__(self):
window = Tk()
window.title("简单的文本编辑器")
# 创建一个菜单栏
menubar = Menu(window)
window.config(menu=menubar)
# 创建一个下拉菜单栏,并将它添加到这个菜单栏
operationMenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=operationMenu)
# 给这个下拉菜单添加元素
operationMenu.add_command(label="open", command=self.openFile)
operationMenu.add_command(label="save", command=self.saveFile)
# 添加第一个工具栏框架
frame0 = Frame(window)
frame0.grid(row=1, column=1, sticky=W)
# 创建图像
openImage = PhotoImage(file="image/open.gif")
saveImage = PhotoImage(file="image/save.gif")
Button(frame0, image=openImage, command=self.openFile).grid(row=1, column=1, sticky=W)
Button(frame0, image=saveImage, command=self.saveFile).grid(row=1, column=2)
# 添加第二个工具栏框架:
frame1 = Frame(window)
frame1.grid(row=2, column = 1)
# 在右方创建一个滚动条
scrollbar = Scrollbar(frame1)
scrollbar.pack(side=RIGHT, fill=Y)
self.text = Text(frame1, width=40, height=20, wrap=WORD, yscrollcommand=scrollbar.set)
self.text.pack()
scrollbar.config(command=self.text.yview)
window.mainloop()
def openFile(self):
filenameforReading = askopenfilename()
infile = open(filenameforReading, "r")
self.text.insert(END, infile.read())
infile.close()
def saveFile(self):
filenameforWriting = asksaveasfilename()
outfile = open(filenameforWriting, "w")
outfile.write(self.text.get(1.0, END))
outfile.close()
FileEditor()
贷款计算器
from tkinter import *
class LoanCalculator:
def __init__(self):
window = Tk()
window.title("贷款计算器")
Label(window, text="Annual Interest Rate").grid(row=1, column=1, sticky=W)
Label(window, text="Number of Years").grid(row=2, column=1, sticky=W)
Label(window, text="Loan Amount").grid(row=3, column=1, sticky=W)
Label(window, text="Monthly Paymant").grid(row=4, column=1, sticky=W)
Label(window, text="Total Payment").grid(row=5, column=1, sticky=W)
self.annualInterestRateVar = StringVar()
Entry(window, textvariable=self.annualInterestRateVar, justify=RIGHT).grid(row=1, column=2)
self.numberOfYearVar = StringVar()
Entry(window, textvariable=self.numberOfYearVar, justify=RIGHT).grid(row=2, column=2)
self.loanAmountVar = StringVar()
Entry(window, textvariable=self.loanAmountVar, justify=RIGHT).grid(row=3, column=2)
#########################
self.monthlyPaymentVar = StringVar()
lblMonthlyPayment = Label(window, textvariable=self.monthlyPaymentVar, justify=RIGHT).grid(row=4, column=2, sticky=E)
self.totalPaymentVar = StringVar()
lblTotalPayment = Label(window, textvariable=self.totalPaymentVar, justify=RIGHT).grid(row=5, column=2, sticky=E)
btComputePayment = Button(window, text="Compute Payment", command=self.computePayment).grid(row=6, column=2,sticky=E)
window.mainloop()
def computePayment(self):
monthlyPayment = self.getMonthlyPayment(
float(self.loanAmountVar.get()),
float(self.annualInterestRateVar.get()) / 1200,
int(self.numberOfYearVar.get()))
# 用 set 方法改变命名变量的值
self.monthlyPaymentVar.set(format(monthlyPayment, "10.2f"))
# 用 get 方法获取命名变量的值
totalPayment = float(self.monthlyPaymentVar.get()) * 12 * int(self.numberOfYearVar.get())
self.totalPaymentVar.set(format(totalPayment, "10.2f"))
def getMonthlyPayment(self,
loanAmount,
monthlyInterestRate,
numberOfYears):
monthlyPayment = loanAmount * monthlyInterestRate / (1 - 1 / ( 1 + monthlyInterestRate) ** (numberOfYears * 12))
return monthlyPayment
LoanCalculator()
效果
查找四个连续相同的数字
from tkinter import *
from random import randint
class FourSame:
def __init__(self):
window = Tk()
window.title("四个连续相同的数字")
window.geometry("600x400+0+0")
frame = Frame(window)
frame.pack()
self.entryDict = {} # 用来存储 6*7=42 个输入框对象
self.varDict = {} # 用来存储 42 个变量
for i in range(1, 7):
for j in range(1, 8):
self.varDict[(i, j)] = StringVar()
print(self.varDict[(i, j)])
entry_tmp = Entry(frame, text=1, width=5, textvariable = self.varDict[(i, j)])
entry_tmp.grid(row=i, column=j)
self.entryDict[(i, j)] = entry_tmp
print(self.entryDict[(i, j)])
print('------')
solveButton = Button(window, text = "查找", command = self.solve)
solveButton.pack()
self.initial()
window.mainloop()
def solve(self):
for i in range(1, 7):
for j in range(1, 8):
# 判断横向
if j + 3 <= 7:
if self.varDict[(i, j)].get() == self.varDict[(i, j + 1)].get() == \
self.varDict[(i, j + 2)].get() == self.varDict[(i, j + 3)].get():
self.entryDict[(i, j)]["bg"] = "red"
self.entryDict[(i, j + 1)]["bg"] = "red"
self.entryDict[(i, j + 2)]["bg"] = "red"
self.entryDict[(i, j + 3)]["bg"] = "red"
# 判断纵向
if i + 3 <= 6:
if self.varDict[(i, j)].get() == self.varDict[(i + 1, j)].get() == \
self.varDict[(i + 2, j)].get() == self.varDict[(i + 3, j)].get():
self.entryDict[(i, j)]["bg"] = "yellow"
self.entryDict[(i + 1, j)]["bg"] = "yellow"
self.entryDict[(i + 2, j)]["bg"] = "yellow"
self.entryDict[(i + 3, j)]["bg"] = "yellow"
# 判断主对角线
if i + 3 <= 6 and j + 3 <= 7:
if self.varDict[(i, j)].get() == self.varDict[(i + 1, j + 1)].get() == \
self.varDict[(i + 2, j + 2)].get() == self.varDict[(i + 3, j + 3)].get():
self.entryDict[(i, j)]["bg"] = "green"
self.entryDict[(i + 1, j + 1)]["bg"] = "green"
self.entryDict[(i + 2, j + 2)]["bg"] = "green"
self.entryDict[(i + 3, j + 3)]["bg"] = "green"
# 判断次对角线
if i + 3 <= 6 and j - 3 >= 1:
if self.varDict[(i, j)].get() == self.varDict[(i + 1, j - 1)].get() == \
self.varDict[(i + 2, j - 2)].get() == self.varDict[(i + 3, j - 3)].get():
self.entryDict[(i, j)]["bg"] = "blue"
self.entryDict[(i + 1, j - 1)]["bg"] = "blue"
self.entryDict[(i + 2, j - 2)]["bg"] = "blue"
self.entryDict[(i + 3, j - 3)]["bg"] = "blue"
def initial(self):
for i in range(1, 7):
for j in range(1, 8):
self.varDict[(i, j)].set(randint(1, 3))
FourSame()
效果
井字游戏
from tkinter import *
window = Tk()
window.title("井字游戏")
window.geometry("600x400+0+0")
frame1 = Frame(window)
frame1.pack()
# 创建三种图像
emptyImage = PhotoImage(file=r"./image/empty.gif")
xImage = PhotoImage(file=r"./image/x.gif")
oImage = PhotoImage(file=r"./image/o.gif")
# 创建九个标签
labelDict = {} # 用来存储九个标签对象
varDict = {} # 用来存储标签的变量
for i in range(1, 4):
for j in range(1, 4):
var_tmp = StringVar()
label_tmp = Label(frame1, image = emptyImage, textvariable = var_tmp)
label_tmp.grid(row = i, column = j)
labelDict[(i, j)] = label_tmp
varDict[(i, j)] = var_tmp
print(labelDict[(i, j)])
print(varDict[(i, j)].get() == "")
# 展示进程和结果的标签
labelResult = Label(window, text = "点击方框开始游戏")
labelResult.pack()
# 统计 x 图像和 o 图像的个数,以此来判断下一个图像为 x 还是 o
def countXO():
print("此函数被调用")
n1 = 0 # x 图像
n2 = 0 # o 图像
for i in range(1, 4):
for j in range(1, 4):
if varDict[(i, j)].get() == "x":
n1 += 1
elif varDict[(i, j)].get() == "o":
n2 += 1
return n1, n2
# 判断是否出现三同
def getThree():
for i in range(1, 4):
for j in range(1, 4):
# 横向
if j + 2 <= 3:
if varDict[(i, j)].get() == varDict[(i, j + 1)].get() == varDict[(i, j + 2)].get():
if varDict[(i, j)].get() != "":
labelResult["text"] = str(varDict[(i, j)].get()) + "获胜"
# 纵向
if i + 2 <= 3:
if varDict[(i, j)].get() == varDict[(i + 1, j)].get() == varDict[(i + 2, j)].get():
if varDict[(i, j)].get() != "":
labelResult["text"] = str(varDict[(i, j)].get()) + "获胜"
# 主对角线
if i + 2 <= 3 and j + 2 <= 3:
if varDict[(i, j)].get() == varDict[(i + 1, j + 1)].get() == varDict[(i + 2, j + 2)].get():
if varDict[(i, j)].get() != "":
labelResult["text"] = str(varDict[(i, j)].get()) + "获胜"
# 次对角线
if i + 2 <= 3 and j - 2 >= 1:
if varDict[(i, j)].get() == varDict[(i + 1, j - 1)].get() == varDict[(i + 2, j - 2)].get():
if varDict[(i, j)].get() != "":
labelResult["text"] = str(varDict[(i, j)].get()) + "获胜"
def getResult(n1, n2):
if n1 + n2 < 9:
getThree()
if labelResult["text"].find("获胜") == -1:
labelResult["text"] = "继续游戏"
elif n1 + n2 == 9:
getThree()
if labelResult["text"].find("获胜") == -1:
labelResult["text"] = "平局"
def changeLabelImage(event):
print(event.widget["image"])
n1, n2 = countXO()
for key in labelDict:
if labelDict[key] == event.widget:
if n1 == n2 and varDict[key].get() == "":
event.widget["image"] = xImage
varDict[key].set("x")
n1 += 1
elif n1 - n2 == 1 and varDict[key].get() == "":
event.widget["image"] = oImage
varDict[key].set("o")
n2 += 1
break
getResult(n1, n2) # 调用胜负结果的函数
# 将所有标签与鼠标左键绑定
for i in range(1, 4):
for j in range(1, 4):
labelDict[(i, j)].bind("<Button-1>", changeLabelImage)
window.mainloop()
拖动小构件
from tkinter import *
# 定义距离函数
def distance(x1, y1, x2, y2):
return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
# 定义何为邻近的函数
def isNearby(x1, y1, x2, y2):
radius = 10
return distance(x1, y1, x2, y2) < radius + 10
class twoCircle:
def __init__(self):
self.x1, self.y1 = 20, 20
self.x2, self.y2 = 120, 50
self.radius = 20
window = Tk()
window.title("两个可移动的圆")
self.canvas = Canvas(window, width=800, height=800, bg="white")
self.canvas.pack()
self.drawNew() # 画初始圆和线段
self.canvas.bind("<B1-Motion>", self.mousemoved)
window.mainloop()
def mousemoved(self, event):
if isNearby(self.x1, self.y1, event.x, event.y):
self.canvas["cursor"] = "plus"
self.x1 = event.x
self.y1 = event.y
self.drawNew()
elif isNearby(self.x2, self.y2, event.x, event.y):
self.canvas["cursor"] = "plus"
self.x2 = event.x
self.y2 = event.y
self.drawNew()
else:
self.canvas["cursor"] = "arrow"
def drawNew(self):
self.canvas.delete("twoCircle")
self.canvas.create_oval(self.x1 - self.radius, self.y1 - self.radius,
self.x1 + self.radius, self.y1 + self.radius,
fill="black", tags="twoCircle")
self.canvas.create_oval(self.x2 - self.radius, self.y2 - self.radius,
self.x2 + self.radius, self.y2 + self.radius,
fill="black", tags="twoCircle")
self.canvas.create_line(self.x1, self.y1, self.x2, self.y2, tags="twoCircle")
self.d = format(distance(self.x1, self.y1, self.x2, self.y2), ".2f")
self.canvas.create_text((self.x1 + self.x2) / 2, (self.y1 + self.y2) / 2, text=str(self.d), tags="twoCircle")
twoCircle()
效果
显示 n 个颜色随机的球
from tkinter import *
from random import randint
width = 600 # 画布宽度
height = 600 # 画布高度
radius = 4 # 小球半径
number = 20 # 小球个数
# 将数转换为 16 进制的函数
def toHexChar(hexValue):
if 0 <= hexValue <= 9:
return str(hexValue)
elif 10 <= hexValue <= 15:
return chr(hexValue - 10 + ord('A'))
# 生成随机颜色的函数
def randomColor():
color = "#"
for j in range(6):
color += toHexChar(randint(0, 15))
return color
class RandomColorCircle:
def __init__(self):
window = Tk()
window.title("颜色随机的球")
self.canvas = Canvas(window, width=width, height=height, bg="white")
self.canvas.pack()
textname = "显示" + str(number) + "个颜色随机的球"
btDisplay = Button(window, text=textname, command=self.display)
btDisplay.pack()
window.mainloop()
def display(self):
self.canvas.delete("oval")
for i in range(number):
fillColor = randomColor()
x = randint(radius, width - radius)
y = randint(radius, height - radius)
self.canvas.create_oval(x - radius, y - radius,
x + radius, y + radius,
fill=fillColor, tags="oval")
RandomColorCircle()
效果
n 个随机运动的球
from tkinter import *
from random import randint
width = 600 # 画布宽度
height = 600 # 画布高度
# 返回随机颜色的函数
def getRandomColor():
color = "#"
for i in range(6):
color += toHexChar(randint(0,15))
return color
# 单个数转换为 16 进制的函数
def toHexChar(hexvalue):
if 0 <= hexvalue <= 9:
return str(hexvalue)
elif 10 <= hexvalue <= 15:
return chr(hexvalue - 10 + ord('A'))
# 定义一个球类
class Ball:
def __init__(self):
self.x = randint(0, width) # 圆心
self.y = randint(0, height)
self.dx = randint(2, 10) # 运动幅度
self.dy = randint(2, 10)
self.radius = randint(3, 5) # 半径
self.color = getRandomColor() # 颜色
class BounceBalls:
def __init__(self):
self.ballList = []
window = Tk()
window.geometry("600x400+0+0")
window.title("Bouncing Balls")
self.width = 400
self.height = 300
self.canvas = Canvas(window, width = self.width, height = self.height, bg = "white")
self.canvas.pack()
frame = Frame(window)
frame.pack()
Button(frame, text="Stop", command=self.stop).pack(side=LEFT)
Button(frame, text="Resume", command=self.resume).pack(side=LEFT)
Button(frame, text=" + ", command=self.add).pack(side=LEFT)
Button(frame, text=" - ", command=self.remove).pack(side=LEFT)
self.sleepTime = 100 # 100 毫秒
self.isStopped = False
self.animate() # 开始动画
window.mainloop()
def stop(self):
self.isStopped = True
def resume(self):
self.isStopped = False
self.animate()
def add(self):
self.ballList.append(Ball())
def remove(self):
self.ballList.pop()
def animate(self):
while not self.isStopped:
self.canvas.after(self.sleepTime)
self.canvas.update()
self.canvas.delete("ball")
for ball in self.ballList:
self.redisplayBall(ball)
def redisplayBall(self, ball):
if ball.x > self.width or ball.x < 0:
ball.dx = - ball.dx # 超出边界后,反向移动
if ball.y > self.height or ball.y < 0:
ball.dy = - ball.dy
ball.x += ball.dx
ball.y += ball.dy
self.canvas.create_oval(ball.x - ball.radius, ball.y - ball.radius,
ball.x + ball.radius, ball.y + ball.radius,
fill = ball.color, tags = "ball")
BounceBalls()
效果
画函数图像
示例代码
import math
from tkinter import *
# 定义一个函数
def f(x):
return -50 * math.sin((x / 100.0) * 2 * math.pi)
# 主程序
class DrawFunc:
def __init__(self):
window = Tk()
window.geometry("900x600+0+0")
window.title("函数图像")
width = 600
height = 400
canvas = Canvas(window, width=width, height=height)
canvas.pack()
# 生成很多点
p = []
xside = int(width * 0.4)
for x in range(- xside, xside + 1):
p.append([x + width / 2, f(x) + height / 2])
# 将点连线
for i in range(len(p) - 1):
canvas.create_line(p[i], p[i + 1])
# 画 X 轴
canvas.create_line(10, height / 2, width - 10, height / 2)
canvas.create_text(width / 2 + 100, height / 2 + 10, text="2\u03c0")
canvas.create_text(width / 2 - 100, height / 2 + 10, text="-2\u03c0")
canvas.create_line(width - 10 - 10, height / 2 + 10, width - 10, height / 2)
canvas.create_line(width - 10 - 10, height / 2 - 10, width - 10, height / 2)
# 画 Y 轴
canvas.create_line(width / 2, 10, width / 2, height - 10)
canvas.create_line(width / 2, 10, width / 2 - 10, 10 + 10)
canvas.create_line(width / 2, 10, width / 2 + 10, 10 + 10)
window.mainloop()
DrawFunc()
效果
end