目录
一、导入模块
二、类的写法
三、各组件的功能
1.Button
2.Label
3.Entry
4.Text && Tag
5.RadioButton && CheckButton
6.Canvas
7.布局管理器
①grid
②pack
③place
8.Event
9.OptionMenu && Scale
10.Color && file choose frame
11.Simpledialog && messagebox
12.Menu
四、实战演练
1.NoteBook
2.DrawingPad
python中提供tkinter模块进行GUI设计,使用时直接按照import tkinter 或者 import tkinter as tk导入即可。
类的写法思路应包括:
①导入模块
②类的实现(包括master参数的传入和组件的创建)
③主界面的设置(包括大小、标题、循环等)
具体代码如下:
from tkinter import *
class Application(Frame): #继承Frame
def __init__(self,master=None): #传入master参数
super().__init__(master)
self.pack() #界面布局,可以更改
self.creatWidge()
def creatWidge(self): #创建组件
pass
root = Tk() #设置主界面
root.geometry("500x300+450+250") #设置大小
root.title("一个经典程序GUI的类的写法") #设置标题
Application(master=root)
root.mainloop() # 界面循环
tkinter模块中提供多种组件,如下图所示:
Button初始化传入参数为:def __init__(self, master=None, cnf={}, **kw)
这意味着需要给Button传入一个master参数。
如果需要对Button属性进行设置,则需要引入Options选项的概念,我们可以通过三种方式设置Options选项,这在各种GUI组件中用法都一致。
①创建对象是,使用命名参数(关键字参数)
fred = Button(self,fg="red",bg="blue")
②创建对象之后,使用字典索引方式
fred["fg"] = "red"
③创建对象后,使用config()方法
fred.coonfig(fg="red",bg="blue")
各种Options选项如下:
对Button属性设置完成之后需要再调用pack()方法将其进行布局。
以下为一种实例:
def creatWidge(self):
self.btn01 = Button(self)
self.btn01["text"] = "ButtonOne"
self.btn01.pack()
self.btn01["command"] = self.ButtonOne
self.btnQuit = Button(self,text="退出",command=root.destroy)
self.btnQuit.pack()
def ButtonOne(self):
tk.messagebox.showinfo("Title","Content")
#需要在tkinter模块中导入messagebox
Label的常用属性如下所示:
Label的具体配置过程与Button类似。
应注意Label中image参数无法直接传入图片路径,应配合PhotoImage函数使用,具体实例如下:
def creatWidge(self):
self.label01 = Label(self, text="The Cat", width=10, height=2,
bg="blue", fg="white",font=("黑体",30),anchor=W)
self.label01.pack()
self.photo1 = PhotoImage(file="imgs/cat.png")
self.label02 = Label(self,image=self.photo1)
self.label02.pack()
image参数也可以传入Button中。
Entry用来传入用户输入的字符串,内容需要使用StringVar()来保存在一个变量中,可以通过set方法设置初始值,然后传入到textvariable里面。
以下是一个实例:
def creatWidge(self):
self.NameLable = Label(self,text="用户名")
self.NameLable.pack()
v1 = StringVar()
v1.set("admin")
self.NameEntry = Entry(self,textvariable=v1)
self.NameEntry.pack()
# print(v1.get());print(self.NameEntry.get()) 打印输入框内的值
self.PasswordLable = Label(self,text="密码")
self.PasswordLable.pack()
v2 = StringVar()
self.PasswordEntry = Entry(self,textvariable=v2,show="*")
self.PasswordEntry.pack()
self.Login = Button(self,text="登录",command=self.login)
self.Login.pack()
def login(self):
if self.NameEntry.get() == "Chen" and self.PasswordEntry.get() == "123456":
messagebox.showinfo("系统", "登录成功!")
else:
messagebox.showinfo("系统", "登录失败!用户名或密码错误!")
Text是多行文本框,可以用来给用户进行文本输入,具体功能如下面的例子所示:
def creatWidge(self):
self.text1 = Text(self,width=70,height=30,bg="gray")
self.text1.pack()
self.text1.insert(1.0,"请输入文字...",) #1行0列插入一段文字(Text从1行0列开始)
Button(text="重复插入文本",command=self.insertText).pack(side="left")
Button(text="返回文本", command=self.returnText).pack(side="left")
Button(text="添加图片", command=self.addImage).pack(side="left")
Button(text="添加组件", command=self.addWidget).pack(side="left")
Button(text="通过tag精确控制文本", command=self.textTag).pack(side="left")
def insertText(self):
self.text1.insert(INSERT,' Chen ') #INSERT表示在光标处插入
self.text1.insert(END,'[cat]') #END表示在文本最后插入
def returnText(self):
print(self.text1.get(1.2,1.5))
print(self.text1.get(1.0,END)) #打印全部内容
def addImage(self):
self.photo = PhotoImage(file="imgs/cat.png")
self.text1.image_create(END,image=self.photo) #添加图片
def addWidget(self):
b1 = Button(text="Button")
self.text1.window_create(INSERT,window=b1) #添加按钮
def textTag(self):
self.text1.delete(1.0,END) #删除全部内容
self.text1.insert(INSERT,"There is no word!\n面向CSDN编程!\n百度一下,你就知道!")
self.text1.tag_add("word",1.12,1.16) # 添加一个tag,tag名称为word
self.text1.tag_config("word",background="yellow",foreground="red") # 对tag进行配置
self.text1.tag_add("baidu",3.0,3.4)
self.text1.tag_config("baidu",underline=True) #添加下划线
self.text1.tag_bind("baidu","",self.webshow) # 对tag进行绑定
def webshow(self,event):
webbrowser.open("http://www.baidu.com") #需要用到webbrowser模块
RadioButton是单选按钮,CheckButton是多选按钮,都需要一个变量储存内容,具体功能如下面例子所示:
def creatWidge(self):
self.v1 = StringVar()
self.v1.set("M")
self.v2 = IntVar()
self.v3 = IntVar()
self.Radio1 = Radiobutton(text="男性",value="M",variable=self.v1) #单选按钮配置
self.Radio2 = Radiobutton(text="女性", value="F", variable=self.v1)
self.Radio1.pack(side="left");self.Radio2.pack(side="left")
Button(text="确认",command=self.confirm_one).pack(side="left")
self.Check1 = Checkbutton(text="敲代码",variable=self.v2,onvalue=1,offvalue=0) #多选按钮配置
self.Check2 = Checkbutton(text="睡觉",variable=self.v3,onvalue=1,offvalue=0)
self.Check1.pack(side="right");self.Check2.pack(side="right")
Button(text="确认",command=self.confirm_two).pack(side="right")
def confirm_one(self):
messagebox.showinfo("Confirm","性别为:"+self.v1.get())
def confirm_two(self):
if self.v2.get()==1:
messagebox.showinfo("Confirm","赶紧敲代码!")
if self.v3.get()==1:
messagebox.showinfo("Confirm","碎觉碎觉~")
elif self.v2.get()!=1:
messagebox.showinfo("Confirm","为什么什么都不选?")
Canvas用于图形绘制,具体功能如下面例子所示:
def creatWidge(self):
self.canvas = Canvas(self,width=300,height=200,bg="gray")
self.canvas.pack()
line = self.canvas.create_line(10,10,30,20,40,50) # 画一条折线
rect = self.canvas.create_rectangle(50,50,100,100) # 画一个矩形
oval = self.canvas.create_oval(50,50,100,100) # 画一个椭圆
self.photo = PhotoImage(file="imgs/Reimu.png")
self.canvas.create_image(120,170,image=self.photo) #导入一个图片
Button(self,text="画十个矩形",command=self.draw10Rect).pack(side="left")
def draw10Rect(self):
for i in range(10):
x1 = random.randrange(int(self.canvas["width"])/2) #生成一个0到width的数字
y1 = random.randrange(int(self.canvas["height"])/2)
x2 = x1 + random.randrange(int(self.canvas["width"]) / 2)
y2 = y1 + random.randrange(int(self.canvas["height"]) / 2)
self.canvas.create_rectangle(x1,y1,x2,y2)
tkinter中提供了三种布局管理器:grid、pack、place。
grid表格布局,采用表格结构组织组件,子组件的位置由行和列的单元格来确定,grid方法提供的选项如下所示:
具体实例如下:
def creatWidge(self):
btnText = (("MC","M+","M-","MR"),
("C","±","/","×"),
(7,8,9,"-"),
(4,5,6,"+"),
(1,2,3,"="),
(0,".")) #计算器内容
Entry().grid(row=0,column=0,columnspan=4,pady=10)
for rindex,r in enumerate(btnText): #enumerate(btnText)将btnText变成枚举对象
for cindex,c in enumerate(r):
if c == "=":
Button(text=c, width=2).grid(row=rindex + 1, column=cindex, sticky=NSEW,rowspan=2)
elif c == 0:
Button(text=c, width=2).grid(row=rindex + 1, column=cindex, sticky=EW,columnspan=2)
elif c == ".":
Button(text=c, width=2).grid(row=rindex + 1, column=cindex+1, sticky=EW)
else:
Button(text=c,width=2).grid(row=rindex+1,column=cindex,sticky=EW)
pack是最简单的布局管理器,只能实现水平或者垂直的布局,pack方法提供的选项如下:
具体实例如下:
root = Tk();root.geometry("700x200")
f1 = Frame(root); f1.pack()
f2 = Frame(root); f2.pack()
btnText = ("流行风","中国风","日本风","重金属","轻音乐")
for txt in btnText:
Button(f1,text=txt).pack(side="left",padx="10")
for i in range(13):
Label(f2,width=5,height=10,borderwidth=1,relief="solid",
bg="black" if i%2==0 else "white").pack(side="left",padx=2)
root.mainloop()
place位置管理器,可以通过像素控制组件位置,place方法提供的选项如下:
具体实例如下:
def creatWidge(self):
self.photos = [PhotoImage(file=f"imgs/puke/puke{i+1}.png") for i in range(10)]
self.pukes = [Label(root,image=self.photos[i]) for i in range(10)]
for i in range(10):
self.pukes[i].place(x=10+i*40,y=50)
self.pukes[0].bind_class("Label","",self.chupai) # 为所有的Label增加事件处理
def chupai(self,event):
if event.widget.winfo_y() == 50:
event.widget.place(y=30)
else:
event.widget.place(y=50)
Event常用事件:
root = Tk();root.geometry("530x300")
c1 = Canvas(root,width=200,height=200,bg="blue")
c1.pack()
def mouseTest(event):
print("鼠标左键单击位置(相对于父容器):{0}{1}".format(event.x,event.y))
print("鼠标左键单击位置(相对于屏幕):{0}{1}".format(event.x_root,event.y_root))
print("事件绑定的组件:{0}".format(event.widget))
def testDrag(event):
c1.create_oval(event.x,event.y,event.x+1,event.y+1)
def keyboardTest(event):
print("键的keycode:{0},键的char:{1},键的keysym:{2}".format(event.keycode,event.char,event.keysym))
def press_a_test(event):
print("press a")
def release_a_test(event):
print("release a")
c1.bind("",mouseTest)
c1.bind("",testDrag)
root.bind("",keyboardTest)
root.bind("",press_a_test)
root.bind("",release_a_test)
root.mainloop()
OptionMenu 和 Scale 分别为选择菜单和滑条,具体例子如下:
root = Tk();root.geometry("200x100")
v = StringVar()
v.set("选项一")
om = OptionMenu(root,v,"选项一","选项二","选项三","选项四")
om["width"] = 10
om.pack()
def test1():
print("你的选项是:",v.get())
def test2(value):
# Scale滑动时自动传入value参数
newFont=("宋体",value)
a.config(font=newFont)
s1 = Scale(root,from_=10,to=50,length=200,tickinterva=5,orient=HORIZONTAL,command=test2)
# orient默认为垂直,加上HORIZONTAL为水平
s1.pack()
a = Button(root,text="确定",command=test1)
a.pack()
root.mainloop()
Color choose frame需要导入tkinter.colorchooser模块,file choose frame需要导入tkinter.filedialog模块,filedialog模块函数和命名参数如下:
具体例子如下:
root = Tk();root.geometry("600x400+500+200")
def test1():
s1 = askcolor(color="red",title="选择背景颜色")
# s1的形式为:((0.0,0.0,255.99609375),'#0000ff')
root.config(bg=s1[1])
def test2():
f = askopenfilename(title="上传文件",initialdir="Chen")
show["text"] = f
def test3():
with askopenfile(title="上传文件",filetypes=[("文本文件","txt")]) as f:
show["text"] = f.read()
Button(root,text="选择背景颜色",command=test1).pack()
Button(root,text="选择编辑的文件",command=test2).pack()
Button(root,text="选择读取的文本文件",command=test3).pack()
show = Label(root,width=40,height=3,bg="green")
show.pack()
root.mainloop()
Simledialog需要导入tkinter.simpledialog模块,messagebox需要导入tkinter.messagebox模块。
simpledialog常用函数如下:
messagebox常用函数如下:
root = Tk();root.geometry("400x100+500+300")
def test1():
a = askinteger(title="输入年龄",prompt="请输入年龄",initialvalue=18,minvalue=1,maxvalue=100)
# askstring、askfloat框使用方法一样
show["text"]=a
Button(root,text="你多大了?",command=test1).pack()
show = Label(root,width=40,height=3,bg="green")
show.pack()
a1 = showinfo(title="学习pyhton",message="零基础学习python")
root.mainloop()
通过Menu组件我们可以建立主菜单和快捷菜单,具体例子如下:
def creatWidge(self):
# 创建主菜单栏
menubar = Menu(root)
# 创建子菜单栏
menuFile = Menu(menubar)
menuEdit = Menu(menubar)
menuHelp = Menu(menubar)
# 将子菜单添加到主菜单栏
menubar.add_cascade(label="文件(F)",menu=menuFile)
menubar.add_cascade(label="编辑(E)",menu=menuEdit)
menubar.add_cascade(label="帮助(H)",menu=menuHelp)
# 添加菜单项
menuFile.add_command(label="新建",accelerator="ctrl+n",command=self.test)
menuFile.add_command(label="打开",accelerator="ctrl+o",command=self.test)
menuFile.add_command(label="保存",accelerator="ctrl+s",command=self.test)
menuFile.add_separator() # 添加分割线
menuFile.add_command(label="退出",accelerator="ctrl+q",command=self.test)
# 将主菜单加到根窗口
root.config(menu=menubar)
# 文本编辑区
self.textpad = Text(root,width=50,height=30)
self.textpad.pack()
# 创建上下菜单
self.contextMenu = Menu(root)
self.contextMenu.add_command(label="背景颜色",command=self.test)
# 右键绑定事件
root.bind("",self.createContextMenu)
def test(self):
pass
def createContextMenu(self,event):
# 菜单在鼠标右键单击的坐标处显示
self.contextMenu.post(event.x_root,event.y_root)
from tkinter import *
class Application(Frame):
def __init__(self,master=None):
super().__init__(master)
self.master = master
self.textpad = None
self.pack()
self.creatWidge()
def creatWidge(self):
# 创建主菜单栏
menubar = Menu(root)
# 创建子菜单栏
menuFile = Menu(menubar)
menuEdit = Menu(menubar)
menuHelp = Menu(menubar)
# 将子菜单添加到主菜单栏
menubar.add_cascade(label="文件(F)",menu=menuFile)
menubar.add_cascade(label="编辑(E)",menu=menuEdit)
menubar.add_cascade(label="帮助(H)",menu=menuHelp)
# 添加菜单项
menuFile.add_command(label="新建",accelerator="ctrl+n",command=self.test)
menuFile.add_command(label="打开",accelerator="ctrl+o",command=self.test)
menuFile.add_command(label="保存",accelerator="ctrl+s",command=self.test)
menuFile.add_separator() # 添加分割线
menuFile.add_command(label="退出",accelerator="ctrl+q",command=self.test)
# 将主菜单加到根窗口
root.config(menu=menubar)
# 文本编辑区
self.textpad = Text(root,width=50,height=30)
self.textpad.pack()
# 创建上下菜单
self.contextMenu = Menu(root)
self.contextMenu.add_command(label="背景颜色",command=self.test)
# 右键绑定事件
root.bind("",self.createContextMenu)
def test(self):
pass
def createContextMenu(self,event):
# 菜单在鼠标右键单击的坐标处显示
self.contextMenu.post(event.x_root,event.y_root)
if __name__ == '__main__':
root = Tk()
root.geometry("300x300+450+200")
root.title("Test")
app = Application(master=root)
root.mainloop()
from tkinter import *
from tkinter.colorchooser import *
# 窗口的宽度和高度
win_width = 900
win_height = 500
# 画布背景颜色
bgcolor = "black"
class Application(Frame):
def __init__(self,master=None):
super().__init__(master)
self.fgcolor="#ff0000"
self.lastDraw = 0 # 用于删除未完成的直线
self.startDrawFlag = False # 用于定位直线开始位置
self.pack()
self.creatWidge()
def creatWidge(self):
# 创建绘画区
self.drawpad = Canvas(root,width=win_width,height=win_height*0.9,bg=bgcolor)
self.drawpad.pack()
# 创建按钮
btn_start = Button(root,text="开始",name="start")
btn_start.pack(side="left",padx="30")
btn_pen = Button(root,text="画笔",name="pen")
btn_pen.pack(side="left",padx="30")
btn_rect = Button(root,text="矩形",name="rect")
btn_rect.pack(side="left",padx="30")
btn_clear = Button(root,text="清屏",name="clear")
btn_clear.pack(side="left",padx="30")
btn_eraser = Button(root,text="橡皮擦",name="eraser")
btn_eraser.pack(side="left",padx="30")
btn_line = Button(root,text="直线",name="line")
btn_line.pack(side="left",padx="30")
btn_arrowLine = Button(root,text="箭头",name="arrowLine")
btn_arrowLine.pack(side="left",padx="30")
btn_color = Button(root,text="画笔颜色",name="color")
btn_color.pack(side="left",padx="30")
# 事件处理
btn_pen.bind_class("Button","<1>",self.eventManager)
self.drawpad.bind("",self.stopDraw)
# 增加快捷键
root.bind("", lambda event: self.myColor())
def eventManager(self,event):
name =event.widget.winfo_name()
if name == "line":
self.drawpad.bind("",self.myline)
elif name == "arrowLine":
self.drawpad.bind("",self.myarrowLine)
elif name == "rect":
self.drawpad.bind("", self.myRect)
elif name == "pen":
self.drawpad.bind("",self.myPen)
elif name == "eraser":
self.drawpad.bind("",self.myEraser)
elif name == "clear":
self.drawpad.delete("all")
elif name == "color":
self.myColor()
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 myline(self,event):
self.startDraw(event)
self.lastDraw = self.drawpad.create_line(self.x,self.y,event.x,event.y,fill=self.fgcolor)
def myarrowLine(self,event):
self.startDraw(event)
self.lastDraw = self.drawpad.create_line(self.x,self.y,event.x,event.y,fill=self.fgcolor,arrow=LAST)
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 myEraser(self,event):
self.startDraw(event)
self.drawpad.create_rectangle(self.x-4, self.y-4, event.x+4, event.y+4, fill=bgcolor)
self.x = event.x
self.y = event.y
def myColor(self):
c = askcolor(color=self.fgcolor, title="选择画笔颜色")
self.fgcolor = c[1]
if __name__ == '__main__':
root = Tk()
root.geometry(f"{win_width}x{win_height}+300+150")
root.title("Canvas")
app = Application(master=root)
root.mainloop()