记事本项目
通过具体的项目和案例来具体操作tkinter的组件以及相关的应用。
先创建画布的框架,然后把需要的组件放在画纸上,再把画纸放到画布上。创建组件的时候按照主菜单、子菜单的顺序依次创建,进行布局,然后再写点击时实现的函数,再对菜单进行绑定。
from tkinter import *
from tkinter.messagebox import * # 导入消息框
from tkinter.filedialog import * # 导入文件管理,打开,保存以及右键功能等
from tkinter.colorchooser import * # 导入颜色选择
# 创建一个类继承自frame组件,把Frame当作画纸,窗口root当作画板
class Application(Frame):
#窗口放置的位置,初始化init方法,master指类放在哪里
def __init__(self,master=None):
# 继承自父类的init方法
super().__init__(master)
self.master = master
# 创建实例化方法直接应用
self.creatWidget()
# 创建相应组件,进行摆放
def creatWidget(self):
# 创建主菜单,放在窗口上
menuber = Menu(root)
# 创建子菜单
menuFile = Menu(menuber) # 文件菜单
menuEdit = Menu(menuber) # 编辑菜单
menuHelp = Menu(menuber) # 帮助菜单
# 子菜单加入到主菜单种
menuber.add_cascade(label='文件(F)', menu=menuFile)
menuber.add_cascade(label='编辑(E)', menu=menuEdit)
menuber.add_cascade(label='帮助(H)', menu=menuHelp)
# 添加菜单项,在标签后添加快捷键的说明,绑定命令
menuFile.add_command(label='新建', accelerator='ctrl+n', command=self.newfile)
menuFile.add_command(label='打开', accelerator='ctrl+o', command=self.openfile)
menuFile.add_command(label='保存', accelerator='ctrl+s', command=self.savefile)
menuFile.add_separator() # 添加分割线
menuFile.add_command(label='退出', accelerator='ctrl+q', command=self.quitfile)
# 将主菜单添加到窗口上
root['menu'] = menuber
# 添加快捷键的处理,方法里没有时间的形参,bind绑定时,调用函数的时候需要加上形参event
root.bind('<Control-n>',lambda event: self.newfile())
root.bind('<Control-o>',lambda event: self.openfile())
root.bind('<Control-s>',lambda event: self.savefile())
root.bind('<Control-q>',lambda event: self.quitfile())
# 文本编辑区
self.textpad = Text(root,width=50,height=30)
self.textpad.pack()
# 创建上下文菜单
self.contextMenu = Menu(root)
self.contextMenu.add_command(label='背景颜色',command=self.openAskcolor) # 绑定颜色函数
# 右键绑定事件
root.bind('<Button-3>',self.createContextMenu)
# 新建文件
def newfile(self):
# 提示把之前的内容另存为,然后再保存,清空,
self.filename = asksaveasfilename(title='另存为',initialfile='未命名.txt',filetypes=[('文本文档','*.txt')],
defaultextension='.txt')
self.savefile()
self.textpad.delete(1.0, END) # 把text控件中所有内容清空,好比新建房子清楚地面内容
# 打开文件
def openfile(self):
# 打开前需要先清空之前文本框的内容
self.textpad.delete(1.0, END) # 把text控件中所有内容清空,好比新建房子清楚地面内容
# 写入内容,打开某个文件
with askopenfile(title='打开文本文件') as f:
# 从文件中读取到的内容插入到当前的文本框中
self.textpad.insert(INSERT,f.read())
# 文件名称就是打开的文件
self.filename = f.name
# 保存文件
def savefile(self):
# 打开的文件
with open(self.filename, 'w') as f:
#从当前的文本框中获取所有的内容
content = self.textpad.get(1.0,END)
f.write(content)
# 退出
def quitfile(self):
root.quit()
# 背景颜色
def openAskcolor(self):
# 默认为蓝色,
bg = askcolor(color='blue',title='选择背景颜色')
# 当前背景框为选择的颜色,gb返回的是元组的形式,第一个内容是RGB的形式,第二个元素是十六进制的形式
self.textpad.config(bg=bg[1])
root.config(bg=bg[1]) # 填充文本框外部,画布的颜色
# 创建上下文菜单的函数,在鼠标右键点击的位置显示
def createContextMenu(self,event):
#在鼠标右击的地方传递所对应的x和y的坐标
self.contextMenu.post(event.x_root,event.y_root)
if __name__ == '__main__':
root = Tk()
root.geometry('500x300+200+300')
root.title('记事本')
# 通过类创建的实例对象放到root窗口上
Application(master=root)
# 窗口的消息循环,等待用户操作
root.mainloop()
画板工具项目
实现画板工具基本的选项设置
第一步先实现界面的布局样式,第二步写出对应的逻辑,实现相应的功能,第三步把界面和功能进行绑定联系起来。当点击按钮触发对应的逻辑。
from tkinter import *
from tkinter.messagebox import * # 导入消息框
from tkinter.filedialog import * # 导入文件管理,打开,保存以及右键功能等
from tkinter.colorchooser import * # 导入颜色选择
# 创建一个类继承自frame组件,把Frame当作画纸,窗口root当作画板
class Application(Frame):
#窗口放置的位置,初始化init方法,master指类放在哪里
def __init__(self,master=None):
# 继承自父类的init方法
super().__init__(master)
self.master = master
# 创建实例化方法直接应用
self.creatWidget()
self.fgcolor = '#ff0000' # 默认的画笔颜色
self.bgcolor = '#000000' # 当前画板工具默认的背景颜色
# 开始绘制时候的状态及坐标值,如绘制直线时开始和最后的坐标及最后停留的位置
self.x = 0
self.y = 0 # 开始绘制时的坐标值
# 最后的一次绘制的位置
self.lastDraw = 0
# 绘制的状态,是第一笔画,如第一次画直线,第二次画矩形
self.firstDrawFlag = False
# 创建相应组件,进行摆放
def creatWidget(self):
# 创建画图区域
self.DrawArea = Canvas(root,width=900,height=500,bg='#000000')
self.DrawArea.pack()
# 创建按钮
# name是为按钮起了个名字,当鼠标进行点击的时候不用再另外的判断了
# 当鼠标按下的时候,一直都是当前按钮的操作,不需要每次画同样的图形都要先点击一下了
# 点击其他按钮再进行图形的切换,方便后面进行if判断
btn_start = Button(root, text='开始', name='start')
btn_start.pack(side='left', padx=10) # 间距为10,与之并列组件之间的间隔
btn_pen = Button(root, text='画笔', name='pen')
btn_pen.pack(side='left', padx=10)
btn_rect = Button(root, text='矩形', name='rect')
btn_rect.pack(side='left', padx=10)
btn_clear = Button(root, text='清屏', name='clear')
btn_clear.pack(side='left', padx=10)
btn_eraser = Button(root, text='橡皮', name='eraser')
btn_eraser.pack(side='left', padx=10)
btn_line = Button(root, text='直线', name='line')
btn_line.pack(side='left', padx=10)
btn_lineArrow = Button(root, text='箭头直线', name='lineArrow')
btn_lineArrow.pack(side='left', padx=10)
btn_color = Button(root, text='颜色', name='color')
btn_color.pack(side='left', padx=10)
# 为矩形框按钮绑定左键点击时,触发事件管理,all表示同级按钮都触发
btn_rect.bind_all('<Button-1>', self.eventMange)
# 为绘图区域绑定 松开鼠标,停止绘画
self.DrawArea.bind('<ButtonRelease-1>', self.stopDraw)
# 事件管理,实现组件对应的方法
def eventMange(self,event):
# 获取当前组件的名字
name = event.widget.winfo_name()
if name == 'start': # 执行开始的代码
self.DrawArea.bind('<B1-Motion>', self.startDraw)
elif name == 'pen':
self.DrawArea.bind('<B1-Motion>', self.pen)
elif name == 'rect':
self.DrawArea.bind('<B1-Motion>', self.rect) # 对名字绑定绘制矩形框
elif name == 'clear':
self.DrawArea.delete('all')
elif name == 'eraser':
self.DrawArea.bind('<B1-Motion>', self.eraser)
elif name == 'line':
self.DrawArea.bind('<B1-Motion>', self.myline)
elif name == 'lineArrow':
self.DrawArea.bind('<B1-Motion>', self.lineArrow)
elif name == 'color':
# 默认颜色
color = askcolor(self.fgcolor, title='颜色管理')
self.fgcolor = color[1] # 元组,第一个内容是RGB,第二个元素是十六进制的形式
# 开始绘画的方法,如用画笔的时候,需要开始和停止绘制
def startDraw(self, event):
self.DrawArea.delete(self.lastDraw)
if not self.firstDrawFlag:
self.firstDrawFlag = True
self.x, self.y = event.x, event.y # 跟随鼠标
# 停止绘制
def stopDraw(self, event):
self.firstDrawFlag = False
self.lastDraw = 0
# 绘制矩形
def rect(self, event):
self.startDraw(event)
# 绘制矩形的开始位置和结束位置坐标点,默认颜色
self.lastDraw = self.DrawArea.create_rectangle(self.x, self.y, event.x, event.y, outline=self.fgcolor)
# 画笔,画线
def pen(self, event):
self.startDraw(event)
self.DrawArea.create_line(self.x, self.y, event.x,event.y,fill=self.fgcolor)
self.x = event.x # 画线的时候并不是直线,线弯曲的时候,弯曲的点即为下次绘画的起点
self.y = event.y
# 橡皮擦
def eraser(self, event):
self.startDraw(event)
# 绘制橡皮擦的区域,颜色为背景颜色,也可以改为擦除的区域为线条
self.DrawArea.create_rectangle(self.x, self.y, event.x, event.y, fill=self.bgcolor)
# 画带箭头的直线
def lineArrow(self, event):
self.startDraw(event)
self.lastDraw = self.DrawArea.create_line(self.x, self.y, event.x, event.y, arrow=LAST, fill=self.fgcolor)
# 画直线
def myline(self,event):
self.startDraw(event)
self.lastDraw = self.DrawArea.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor)
if __name__ == '__main__':
root = Tk()
root.geometry('1000x700+100+100')
root.title('画板')
# 通过类创建的实例对象放到root窗口上
Application(master=root)
# 窗口的消息循环,等待用户操作
root.mainloop()