基本使用
基于tkinter创建 GUI基本四步:窗口->组件->布局->事件
1.创建窗口对象
from tkinter import *root = Tk() # 创建窗口root.mainloop() # 进入事件循环
2.创建组件
按钮文本等组件
btn = Button(root) # 创建Button组件,使组件在root窗口展示
btn['text'] = '我是按钮' # 组件属性参数
3.布局管理
管理组件的大小位置样式
btn.pack() # 布局管理器,组件的大小位置样式
4.事件
通过与组件绑定,获取组件所触发的事件
def btn_event(obj): # obj 即事件对象print('控制台输出:'+'触发了事件') # 输出到控制台
btn.bind('<Button-1>', btn_event) # 事件和组件进行绑定
案例:
from tkinter import *
from tkinter import messageboxroot = Tk() # 创建窗口btn = Button(root) # 创建Button组件,使组件在root窗口展示
btn['text'] = '我是按钮'
btn.pack() # 布局管理器,配置组件的样式def btn_event(obj): # obj 即事件对象messagebox.showinfo("Message","触发了事件") # 弹出新的窗口,并展示内容print('控制台输出:'+'触发了事件') # 输出到控制台btn.bind('<Button-1>', btn_event) # 事件绑定,事件和组件进行绑定 <Button-1> :鼠标左键点击一次 <Button-2>:鼠标右键点击一次if __name__ == '__main__':root.mainloop() # 进入事件循环
主窗口
title('窗口标题')
geometry('wxh ± x, ±y')
- w:宽度
- h:高度
- +x:距屏幕左边的距离,-x:距屏幕右边的距离
- +y:距屏幕上边的距离,-y:距;屏幕下边的距离
root.geometry('500x300+100+200') # 宽度500,高度300,距左边100,距上边200
组件
Toplevel | 顶层 | 容器类,可为其他组件提供单独的容器,类似窗口 |
Button | 按钮 | 按钮点击组件 |
Ganvas | 画布 | 提供绘图功能 |
Radiobutton | 单选框 | 单选框 |
CheckButton | 复选框 | 可勾选的复选框 |
Entry | 单行输入框 | 可输入内容 |
simpledialog其子方法 | 简单输入框 | |
filedialog其子方法 | 文件对话框 | 用于打开系统文件 |
Frame | 容器 | 用于装载其他组件 |
LabelFrame | 容器 | 类似Frame,但可以添加标题 |
label | 标签 | 显示不可编辑的文本或图标 |
Listbox | 列表框 | 可列出多个选项 |
Menu | 菜单 | 菜单组件 |
MenuButton | 菜单按钮 | 包含菜单的按钮,包括下拉层叠式等 |
OptionMenuu | 菜单按钮 | MenuButton的子类,可通过按钮打开一个菜单 |
Message | 消息框 | 可以显示多行文档 |
messagebox | 通用消息框 | 用于和用户简单的消息交互 |
Text | 文本框 | 可显示多行文本、图片、连接、HTML页面、CSS样式,甚至可添加组件等 |
Scale | 滑块 | 可移动滑块 |
askcolor | 颜色 |
Frame容器
GUI编程就是编写一个个组件,界面由组件组成,组件内又可以创建组件,这种组件即为容器
import tkinter as tk
from tkinter import Frameroot = tk.Tk()
root.title('包含容器的GUI')
root.geometry('500x300+200+200')
frame = Frame(master=root) # 在root中创建容器
frame.pack()root.mainloop()
经典的面向对象的GUI
import tkinter as tk
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('经典的面向对象的GUI')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''self.btn01 = Button(self, text='容器的按钮01', command=self.btn01_event) # 创建button组件,在Frame中显示,这里的self是Frameself.btn01.pack()self.btn02 = Button(self, text='退出', command=root.destroy)self.btn02.pack()def btn01_event(self):messagebox.showinfo('Message', '触发了事件')print('控制台输出:' + '触发了事件') # 输出到控制台def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
Label
- font:字体和大小,1个中文宽度两个字符,高度一个字符
- image:图片,目前支持gif
- fg:前景色,bg:背景色
- justigy:对齐方式,left、center、right
- width:宽度,heigth:高度
import tkinter as tk
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''# 文件标签self.text_label = Label(self, text='label组件',width=10, height=2, bg='black', fg='white', font=('黑体', 15), justify='left', borderwidth=1)self.text_label.pack()self.text_label2 = Label(self, text='label组件\nlabel组件内容不能修改\n哈哈',bg='black', fg='white', font=('黑体', 15), justify='left', borderwidth=1)self.text_label2.pack()# 图片标签global PHOTOPHOTO = PhotoImage(file='img.gif') # 注意:图片最好是全局变量self.photo_label = Label(root, image=PHOTO)self.photo_label.pack()def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
Button
import tkinter as tk
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')PHOTO = PhotoImage(file='img.gif') # 注意:图片最好是全局变量class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''self.login_btn = Button(self, text='登录', command=self.login_event) # 创建button组件,在Frame中显示,这里的self是Frameself.login_btn.pack()self.image_btn = Button(self, image=PHOTO, command=self.image_event)self.image_btn.pack()self.image_btn['state'] = 'disable' # 按钮禁止点击def image_event(self):messagebox.showinfo('Message', '点击了图片')def login_event(self):messagebox.showinfo('Message', '登录成功')# print('控制台输出:' + '触发了事件') # 输出到控制台def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
Entry
import tkinter as tk
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''self.user_label = Label(self, text='用户')self.user_label.pack()user_value = StringVar() # 定义变量,要用来接收Entry输入的值user_value.set('admin') # StringVar 的默认值self.user_entry = Entry(self, textvariable=user_value) # StringVar变量绑定到Entry组件self.user_entry.pack()print(user_value.get())print(self.user_entry.get())self.pwd_label = Label(self, text='密码')self.pwd_label.pack()pwd_value = StringVar()self.pwd_entry = Entry(self, textvariable=pwd_value, show="*") # 用户输入的内容展示成 *self.pwd_entry.pack()self.user_btn = Button(self, text='提交', command=self.login)self.user_btn.pack()def login(self):print('用户名: ' + self.user_entry.get()) # 获取输入框的值print('用户密码: ' + self.pwd_entry.get()) # 获取输入框的值messagebox.showinfo('Message', '登录成功')def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
Text
- insert 插入内容到指定位置
- get 获取指定位置的内容
- image_create 插入图片到指定位置
- delete 删除指定位置的内容
- tag_add:添加标签 tag_config:标签样式 tag_bind:标签事件
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''self.text = Text(self, width=40, height=20, bg='gray') # width=40 宽度40,可显示20列汉字 height=20 高度20,可显示20行汉字self.text.pack()# 插入数据self.text.insert(1.0, '123456\n') # inster 第一个参数为插入数据的坐标 x.y 1.0表示第一行第0列Button(self, text='重复插入', command=self.insert_text).pack(side='left') # pack(side='left') 表示水平排列Button(self, text='返回文本', command=self.return_text).pack(side='left')Button(self, text='添加图片', command=self.add_image).pack(side='left')Button(self, text='添加组件', command=self.add_widget).pack(side='left')Button(self, text='通过tag精准控制文本', command=self.test_tag).pack(side='left')def insert_text(self):self.text.insert(INSERT, 'AAA') # INSERT 在光标所在位置插入内容self.text.insert(END, 'BBB') # END 在文本末尾插入内容def return_text(self):print(self.text.get(1.0, 2.5)) # 获取指定范围内的文本, get(1.0, 2.5) 表示获取第1行第0列至地2行第5列的内容print(self.text.get(1.0, END)) # 获取全部内容def add_image(self):self.photo = PhotoImage(file='img.gif')self.text.image_create(END, image=self.photo)def add_widget(self):'''在文本框中添加按钮组件'''btn = Button(self.text, text='按钮') # 添加的组件是在text组件中,所以一个参数是 self.textself.text.window_create(INSERT, window=btn) # 将组件添加到 text组件中def test_tag(self):self.text.delete(1.0, END)self.text.insert(1.0, '天净沙·秋思\n马致远\n枯藤老树昏鸦,\n小桥流水人家,\n古道西风瘦马。\n夕阳西下,断肠人在天涯\n')# 添加 tagself.text.tag_add('古诗名', 1.0, 1.6) # 第一个参数标签名,第二个参数标签范围# 为标签添加样式self.text.tag_config('古诗名', background='yellow', foreground='red', font=5)self.text.insert(END, '百度')# 为标签绑定事件self.text.tag_add('baidu', 7.0, 7.2)self.text.tag_config('baidu', underline=True)self.text.tag_bind('baidu', '<Button-1>', self.go_baidu)def go_baidu(self, event):webbrowser.open('http://www.baidu.com')def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
Radiobutton
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''# 创建变量self.gender = StringVar()self.gender.set('F') # 设置默认值# 变量与单选框绑定self.rbtn1 = Radiobutton(self, text='男性', value='M', variable=self.gender).pack(side='left') # variable 将用户选择的值 value赋值给self.genderself.rbtn2 = Radiobutton(self, text='女性', value='F', variable=self.gender).pack(side='left')Button(self, text='确定', command=self.confirm).pack(side='left')def confirm(self):messagebox.showinfo('Message', '选择的性别为:'+self.gender.get())def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
Checkbutton
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''# 创建变量self.code_hobby = IntVar()self.video_hobby = IntVar()print(self.code_hobby.get()) # 默认值为0# Checkbutton onvalue选中时的值,offvalue未选中时的值, variable将值赋值给变量self.cbtn1 = Checkbutton(self, text='代码', onvalue=1, offvalue=0, variable=self.code_hobby).pack(side='left')self.cbtn2 = Checkbutton(self, text='电影', onvalue=1, offvalue=0, variable=self.video_hobby).pack(side='left')Button(self, text='确定', command=self.confirm).pack(side='left')def confirm(self):hobby = []if self.code_hobby.get() == 1:hobby.append('代码')if self.video_hobby.get() == 1:hobby.append('电影')messagebox.showinfo('Message', '选择的爱好:' + ','.join(hobby))def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
OptionMenu
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''self.value = StringVar()self.value.set('python')OptionMenu(self, self.value, 'python', 'go', 'java').grid(row=1, column=0)Button(self, text='确定', command=self.language).grid(row=1, column=1)def language(self):print(self.value.get())def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
Menu
import tkinter as tk
import webbrowser
from tkinter import *root = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(tk.Frame):def __init__(self, master=None):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):"""创建各种组件"""# 创建菜单栏main_menu = Menu(self.master)# 创建子菜单栏file_menu = Menu(main_menu, tearoff=0)edit_menu = Menu(main_menu, tearoff=0)help_menu = Menu(main_menu, tearoff=0)# 将子菜单栏加入主菜单栏main_menu.add_cascade(label='文件', menu=file_menu)main_menu.add_cascade(label='编辑', menu=edit_menu)main_menu.add_cascade(label='帮助', menu=help_menu)# 添加菜单选项并绑定方法file_menu.add_command(label='新建', accelerator='Ctrl+N', command=self.create_file)file_menu.add_command(label='打开', accelerator='Ctrl+O', command=self.open_file)file_menu.add_command(label='保存', accelerator='Ctrl+S', command=self.save_file)file_menu.add_separator() # 添加分割线file_menu.add_command(label='退出', command=root.quit)# 将主菜单添加到窗口self.master['menu'] = main_menudef create_file(self):passdef open_file(self):passdef save_file(self):passdef main():app = Application(master=root)app.mainloop()if __name__ == '__main__':main()
Scale
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):"""创建各种组件"""self.text_label = Label(self, text='好好学习', font=('宋体', 10))self.text_label.pack()Scale(self,from_=10, to=50, tickinterval=5, # 从10开始到50,按每份大小为5划分length=200,orient=HORIZONTAL, # HORIZONTAL:水平, 默认垂直command=self.test).pack()def test(self, value):# value 是滑块的值print('滑块的值: ' + value)font = ('宋体', value)self.text_label.config(font=font)def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
askcolor
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter.colorchooser import askcolorroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):"""创建各种组件"""Button(self, text='选择背景色', command=self.bgcolor).pack()def bgcolor(self):c = askcolor(title='选择背景色', color='red')print(c[1])root.config(bg=c[1])def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
filedialog文本对话框
方法包括:
askopenfilenames
:选择多个文件。- askopenfilename: 选中一个文件
askdirectory
:选择一个目录。asksaveasfilename
:选择一个文件保存位置。askopenfile
:打开一个文件并返回一个文件对象。asksaveasfile
:选择一个文件保存位置并返回一个文件对象
askopenfilename
参数:
title
:对话框的标题。initialdir
:初始目录。filetypes
:指定过滤的文件类型。defaultextension
:默认扩展名。
返回值:返回所选择文件的绝对路径,若选择的文件不存在则为空
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter.filedialog import *root = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):"""创建各种组件"""self.show_file_path = Label(self)self.show_file_path.pack()Button(self, text='上传文件', command=self.file_path).pack()def file_path(self):file = askopenfilename(title='上传文件', initialdir='/', filetypes=[('文本文件', '.txt')])self.show_file_path['text'] = filedef main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
askopenfile
返回值:返回文件对象
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter.filedialog import *root = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):"""创建各种组件"""self.show_file_content = Label(self)self.show_file_content.pack()Button(self, text='上传文件', command=self.file_content).pack()def file_content(self):file = askopenfile(title='上传文件', initialdir='/', filetypes=[('文本文件', '.txt')])self.show_file_content['text'] = file.read()def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
simpledialog简单输入框
要包含了以下几种对话框方法:
askstring(title, prompt, **options)
用户输入的字符串,如果用户点击了取消或关闭对话框,则返回None
askinteger(title, prompt, **options)
用户输入的整数,如果用户点击了取消或关闭对话框,则返回None
askfloat(title, prompt, **options)
用户输入的浮点数,如果用户点击了取消或关闭对话框,则返回None
参数:
title
:对话框的标题。prompt
:显示在对话框中的提示信息。**options
:其他选项,如initialvalue
、minvalue
、maxvalue
等。
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter.simpledialog import *root = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):"""创建各种组件"""self.show_name = Label(self)self.show_name.grid(row=1, column=0)Button(self, text='输入姓名', command=self.name).grid(row=1, column=1)self.show_age = Label(self)self.show_age.grid(row=2, column=0)Button(self, text='输入年龄', command=self.age).grid(row=2, column=1)def name(self):v = askstring(title='输入姓名', prompt='请输入姓名')self.show_name['text'] = vdef age(self):v = askinteger(title='输入年龄', prompt='请输入年龄', initialvalue=18, # 默认值minvalue=1, maxvalue=150 # 大小范围)self.show_age['text'] = vdef main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
messagebox
包含的方法
showinfo(title, message, **options)
用于显示信息消息。showwarning(title, message, **options)
用于显示警告消息。showerror(title, message, **options)
用于显示错误消息。
askquestion(title, message, **options)
用于询问用户一个问题,并提供“是”和“否”两个选项。
askokcancel(title, message, **options)
用于询问用户一个问题,并提供“确定”和“取消”两个选项。
askyesno(title, message, **options)
用于询问用户一个问题,并提供“是”和“否”两个选项。
askretrycancel(title, message, **options)
用于询问用户是否重试,提供“重试”和“取消”两个选项。
askyesnocancel(title, message, **options)
用于询问用户一个问题,并提供“是”、“否”和“取消”三个选项。
参数:
title
:对话框的标题。message
:显示的信息内容。**options
:其他选项,如图标、按钮文本等。
案例
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):"""创建各种组件"""Button(self, text='showinfo', command=self.showinfo).pack()Button(self, text='showwarning', command=self.showwarning).pack()Button(self, text='showerror', command=self.showerror).pack()Button(self, text='askquestion', command=self.askquestion).pack()Button(self, text='askokcancel', command=self.askokcancel).pack()Button(self, text='askyesno', command=self.askyesno).pack()Button(self, text='askretrycancel', command=self.askyesno).pack()Button(self, text='askyesnocancel', command=self.askyesno).pack()def showinfo(self):messagebox.showinfo('消息提示', '这是一条提示消息')def showwarning(self):messagebox.showwarning("警告提示", "这是一个警告提示框。")def showerror(self):messagebox.showerror("错误提示", "这是一个错误提示框。")def askquestion(self):# # 询问问题(返回 'yes' 或 'no')response = messagebox.askquestion("询问提示", "您确定要继续吗?")if response == 'yes':print("用户选择了 '是'。")else:print("用户选择了 '否'。")def askokcancel(self):# 询问问题(返回 True 或 False)response = messagebox.askokcancel("询问提示", "您确定要继续吗?")if response:print("用户选择了 '确定'。")else:print("用户选择了 '取消'。")def askyesno(self):# 询问问题(返回 True 或 False)response = messagebox.askyesno("询问提示", "您确定要继续吗?")if response:print("用户选择了 '是'。")else:print("用户选择了 '否'。")def askretrycancel(self):# 询问是否重试(返回 True 或 False)response = messagebox.askretrycancel("询问提示", "操作失败,您想重试吗?")if response:print("用户选择了 '重试'。")else:print("用户选择了 '取消'。")def askyesnocancel(self):# 询问问题(返回 True、False 或 None)response = messagebox.askyesnocancel("询问提示", "您确定要继续吗?")if response is True:print("用户选择了 '是'。")elif response is False:print("用户选择了 '否'。")else:print("用户选择了 '取消'。")def main():app = Application(root)root.mainloop()if __name__ == '__main__':main()
布局管理器
`tkinter` 提供了三种常用的布局管理器:`pack`、`grid` 和 `place`。每种布局管理器都有其独特的用途和特性,适用于不同的布局需求。
pack
`pack` 是一种基于容器的布局管理器,它将组件放置在父容器中的左侧、右侧、顶部或底部。使用 `pack` 时,组件可以扩展以填充可用空间,或者收缩以适应空间。这种布局方式非常适合那些不需要精确位置控制的简单界面。
- 组件可以扩展或收缩以适应容器大小的变化。
- 组件可以水平或垂直排列。
- 支持填充(fill)和扩展(expand)选项,使得组件可以占据更多的空间。
- 不适合需要精确坐标定位的情况。
常用参数:
- `side`:指定组件放置的位置,可以是 `TOP`、`BOTTOM`、`LEFT` 或 `RIGHT`。
- `expand`:布尔值,指定组件是否应该扩展以占据所有可用空间。
- `fill`:指定组件应该填充的方向,可以是 `X`、`Y` 或 `BOTH`。
grid
`grid` 布局管理器提供了一个表格形式的布局方式,可以将组件放置在一个二维网格中的单元格内。这种方式非常适合需要精确行和列定位的应用场景。
- 组件放置在一个由行和列组成的网格中。
- 每个组件占据一个或多个单元格。
- 支持跨越多个行或列的组件。
- 更适合复杂界面设计,尤其是表格式的布局。
常用参数:
- `row` 和 `column`:指定组件所在的行和列。
- `sticky`:指定组件如何对其所在单元格进行对齐,可以是 `N`、`S`、`E`、`W`、`NE`、`NW`、`SE`、`SW`、`NS`、`EW`、`NSW`、`NSE`、`NEW`、`NSEW`。
- `columnspan` 和 `rowspan`:指定组件跨越的行数和列数。
- `padx` 和 `pady`:指定组件周围的内部填充。
- `ipadx` 和 `ipady`:指定组件内部的填充。
案例
import tkinter as tk
import webbrowser
from tkinter import *
from tkinter import messageboxroot = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')class Application(Frame):def __init__(self, master):super().__init__(master)self.master = masterself.pack()self.create_widget()def create_widget(self):'''创建各种组件'''self.name = StringVar()self.name.set('admin')Label(self, text='账号').grid(row=1, column=0)Entry(self, textvariable=self.name).grid(row=1, column=1)self.pwd = StringVar()Label(self, text='密码').grid(row=2, column=0)Entry(self, textvariable=self.pwd).grid(row=2, column=1)Button(self, text='登录', command=self.login).grid(row=3, column=0)Button(self, text='退出', command=root.destroy).grid(row=3, column=1, sticky=E)def login(self):if self.name.get() == 'admin' and self.pwd.get() == '123456':messagebox.showinfo('Message', '登录成功')else:messagebox.showinfo('Message', '用户名或密码错误')def main():app = Application(root)rows, columns = root.grid_size()print(f"Rows: {rows}, Columns: {columns}")root.mainloop()if __name__ == '__main__':main()
place
`place` 布局管理器允许开发者以绝对坐标的形式来定位组件。这种方式最灵活但也最难维护,因为每个组件的位置都需要明确指定。
- 组件位置通过坐标 `(x, y)` 明确指定。
- 支持组件大小的精确控制。
- 适合需要高度定制化布局的设计。
- 由于绝对定位,可能导致布局在不同屏幕尺寸或分辨率下的表现不一致。
常用参数:
- `x` 和 `y`:指定组件左上角的坐标。
- `width` 和 `height`:指定组件的宽度和高度。
- `relx`、`rely` :相对父组件坐标进行定位(值范围:0-1)
- `relwidth`、`relheight`:相对父组件进行尺寸大小设置(值范围:0-1)。
案例
import tkinter as tk
from tkinter import *root = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')f1 = Frame(root, width=300, height=200, bg='green')
f1.place(x=30, y=30) # f1 组件的左上角相对于其父组件(root)的距离 横向30,纵向30Button(root, text='按钮1').place(relx=0.2, # 相对父组件坐标 500 * 0.2x=50, # relx 后面的 x属性 表示再向右移动y=100,relwidth=0.2, # 相对父组件宽度 500 * 0.2relheight=0.5 # 相对父组件高度 300 * 0.5
)Button(f1, text='按钮2').place(relx=0.1, rely=0.2)root.mainloop()
选择合适的布局管理器
- 如果你的应用程序需要简单的布局,而且不需要精确的坐标定位,那么 `pack` 是一个很好的选择。
- 如果你需要一个表格形式的布局,其中每个组件的位置都可以精确控制,那么 `grid` 更适合你。
- 如果你需要绝对控制每个组件的位置和大小,那么 `place` 可以提供最大的灵活性,但也会带来更复杂的维护工作。
事件
组件绑定事件方法:
- widget.bind(event,handler) 当需要获取event对象时
- widget(commadn=handler) 当不需要获取event对象时
- widget.bind_class('Button',<Button-1>, func) 将所有Button绑定事件
当事件发生,handler函数会被出发,并将事件对象event传入
import tkinter as tk
from tkinter import *root = tk.Tk()
root.title('我是窗口')
root.geometry('500x300+200+200')def test1():print('test1')def test2(a, b):print(a + b)def test3(event):print('test3')# 适用事件函数不需要参数时
Button(root, text='按钮1', command=test1).pack(side='left')
# 适用事件函数需要参数时,利用lambda
Button(root, text='按钮2', command=lambda: test2(2, 5)).pack(side='left')
# 为所有Button按钮绑定鼠标右键事件
Button(root, text='按钮3').bind_class('Button', '<Button-2>', test3)root.mainloop()
鼠标和键盘事件
event常用属性
ttk模块控件
特点
- 可定制性:
ttk
控件支持主题化,可以更容易地改变控件的外观。 - 跨平台一致性:
ttk
控件在不同操作系统上的外观更加一致。 - 更多的组件:
ttk
提供了一些tkinter
没有的组件,例如树形控件(Treeview)、进度条(Progressbar)等。
控件
ttk.Button
:按钮控件。ttk.Checkbutton
:复选框控件。ttk.Combobox
:下拉组合框控件。ttk.Entry
:输入框控件。ttk.Frame
:容器控件。ttk.Label
:标签控件。ttk.LabelFrame
:带标签的容器控件。ttk.Menubutton
:菜单按钮控件。ttk.PanedWindow
:窗格控件,用于创建分割窗口。ttk.Progressbar
:进度条控件。ttk.Radiobutton
:单选按钮控件。ttk.Scale
:滑动条控件。ttk.Separator
:分隔线控件。ttk.Sizegrip
:大小调整控件。ttk.Treeview
:树形表格控件。
案例
import tkinter as tk
from tkinter import ttkroot = tk.Tk()
root.title('ttk 示例')
root.geometry('500x300+200+200')# 创建一个 Frame 容器
frame = ttk.Frame(root, padding=10)
frame.pack(fill=tk.BOTH, expand=True)# 创建一个 Label 标签
label = ttk.Label(frame, text="欢迎使用 ttk 控件!")
label.pack()# 创建一个 Button 按钮
button = ttk.Button(frame, text="点击我")
button.pack()# 创建一个 Entry 输入框
entry = ttk.Entry(frame)
entry.pack()# 创建一个 Checkbutton 复选框
check_var = tk.BooleanVar()
checkbutton = ttk.Checkbutton(frame, text="同意协议", variable=check_var)
checkbutton.pack()# 创建一个 Radiobutton 单选按钮
radio_var = tk.IntVar()
radiobutton1 = ttk.Radiobutton(frame, text="选项1", variable=radio_var, value=1)
radiobutton2 = ttk.Radiobutton(frame, text="选项2", variable=radio_var, value=2)
radiobutton1.pack()
radiobutton2.pack()# 创建一个 Combobox 下拉组合框
combo = ttk.Combobox(frame, values=["选项A", "选项B", "选项C"])
combo.pack()# 创建一个 Progressbar 进度条
progressbar = ttk.Progressbar(frame, length=200, mode='determinate')
progressbar.pack()# 创建一个 Treeview 树形表格
tree = ttk.Treeview(frame, columns=("姓名", "年龄"), show='headings')
tree.heading("姓名", text="姓名")
tree.heading("年龄", text="年龄")
tree.insert("", tk.END, values=("张三", "25"))
tree.insert("", tk.END, values=("李四", "30"))
tree.pack()root.mainloop()