python GUI开发: tkinter菜单创建,记事本和画图软件综合项目的实战演练

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:python图形化GUI编程tkinter精讲
景天的主页:景天科技苑

文章目录

  • 菜单
    • 1.主菜单
      • 1.1【示例】记事本软件的主菜单
    • 2.上下文菜单
      • 2.1【示例】为记事本程序增加上下文菜单
    • 3.【项目】记事本软件开发
    • 4.【项目】画图软件开发

菜单

GUI 程序通常都有菜单,方便用户的交互。我们一般将菜单分为两种:

  1. 主菜单
    主菜单通常位于 GUI 程序上方。例如:
    在这里插入图片描述

  2. 快捷菜单(上下文菜单)
    通过鼠标右键单击某个组件对象而弹出的菜单,一般是与该组件相关的操作。
    在这里插入图片描述

1.主菜单

主菜单一般包含:文件、编辑、帮助等,位于 GUI 窗口的上面。创建主菜单一般有如下 4
步:

  1. 创建主菜单栏对象
menubar = tk.Menu(root)
  1. 创建菜单,并添加到主菜单栏对象
file_menu = tk.Menu(menubar)
menubar.add_cascade(label=”文件”,menu=file_menu)
  1. 添加菜单项到 2 步中的菜单
file_menu.add_command(label=”打开”)
file_menu.add_command(label=”保存”,accelerator=^p” command=mySaveFile)
file_menu.add_separator()
file_menu.add_command(label=”退出”)
  1. 将主菜单栏添加到根窗口
root[“menu”]=menubar

1.1【示例】记事本软件的主菜单

#记事本软件,练习主菜单的设计from tkinter import *
from tkinter.filedialog import *root = Tk();root.geometry("400x400")
root.title("记事本")#创建主菜单栏
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)filename = ""def openfile():global filenamew1.delete('1.0', 'end')         # 先把Text控件中的内容清空with askopenfile(title="打开文件") as f:content = f.read()w1.insert(INSERT, content)filename = f.nameprint(f.name)def savefile():with open(filename, "w") as f:content = w1.get(1.0, END)f.write(content)def exit():root.quit()# 添加菜单项
#accelerator 快捷键
menuFile.add_command(label="打开", accelerator="ctrl+o", command=openfile)
menuFile.add_command(label="保存", command=savefile)
menuFile.add_separator()  # 添加分割线
menuFile.add_command(label="退出", command=exit)
# 将主菜单栏加到根窗口
root["menu"] = menubarw1 = Text(root, width=50, height=30)
w1.pack()root.mainloop()

运行
在这里插入图片描述

点击文件
在这里插入图片描述

2.上下文菜单

快捷菜单(上下文菜单)是通过鼠标右键单击组件而弹出的菜单,一般是和这个组件相关的
操作,比如:剪切、复制、粘贴、属性等。创建快捷菜单步骤如下:

  1. 创建菜单
menubar = tk.Menu(root)
menubar.add_command(label=”字体”)
  1. 绑定鼠标右键单击事件
def test(event):menubar.post(event.x_root,event.y_root) #在鼠标右键单击坐标处显示菜单root.bind(<Button-3>,test)

2.1【示例】为记事本程序增加上下文菜单

"""开发记事本软件的菜单
"""from tkinter import *
class Application(Frame):def __init__(self, master=None):super().__init__(master)        # super()代表的是父类的定义,而不是父类对象self.master = masterself.textpad = None             # textpad表示Text文本框对象self.pack()self.createWidget()def createWidget(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["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("<Button-3>",self.createContextMenu)def test(self):passdef createContextMenu(self,event):# 菜单在鼠标右键单击的坐标处显示self.contextMenu.post(event.x_root, event.y_root)if __name__ == '__main__':root = Tk()root.geometry("450x300+200+300")root.title("景天科技苑的简易记事本")app = Application(master=root)root.mainloop()

运行
在这里插入图片描述

在记事本中,右键可以显示背景颜色

3.【项目】记事本软件开发

结合所学 GUI 知识,开发一款模仿 windows 记事本的软件。包含了基本的功能:

  1. 新建文本文件
  2. 保存文件
  3. 修改文件内容
  4. 退出
  5. 各种快捷键处理
  6. 修改文本区域背景色
"""开发记事本软件的菜单
"""from tkinter import *
from tkinter.filedialog import *
from tkinter.colorchooser import *
from tkinter import messageboxclass Application(Frame):def __init__(self, master=None):super().__init__(master)        # super()代表的是父类的定义,而不是父类对象self.master = masterself.textpad = None             # textpad表示Text文本框对象self.filename = Noneself.pack()self.createWidget()def createWidget(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.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.exit)# 将主菜单栏加到根窗口root["menu"] = menubar# 增加快捷键的处理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.exit())#文本编辑区,多行文本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):#如果是第一次新建,就新建新文本,如果是打开程序直接点击保存,就把写进去的内容保存起来if self.filename:self.textpad.delete("1.0", "end")  # 把text控件中所有的内容清空self.filename= asksaveasfilename(title="另存为",initialfile="未命名.txt",filetypes=[("文本文档","*.txt")],defaultextension=".txt")#判断是否新建,如果未新建,则不用保存if self.filename:self.savefile()else:self.destroy()else:self.filename= asksaveasfilename(title="另存为",initialfile="未命名.txt",filetypes=[("文本文档","*.txt")],defaultextension=".txt")#判断是否新建,如果未新建,则不用保存if self.filename:self.savefile()else:self.destroy()def openfile(self):self.textpad.delete("1.0","end")        # 把text控件中所有的内容清空# with askopenfile(title="打开文本文件") as f: 别这样用,否则当没有打开文件时,会有个报错f = askopenfile(title="打开文本文件")print("打开的文件对象是:",f)#如果有打开,则在将写入的插入,没打开不用插入,在光标所在处插入文本内容if f:self.textpad.insert(INSERT,f.read())#将打开之后的文件名赋值给self.filenameself.filename = f.nameelse:self.destroy()#实现保存方法def savefile(self):#第一次打开程序,直接点击保存bug修复print("第一次打开程序点击保存",self.filename)if self.filename:f = open(self.filename,"w")if f:#获取到文本内容字符串,然后在通过open保存c = self.textpad.get(1.0,END)f.write(c)else:# messagebox.showinfo("Warning", "请先新建文件!")self.newfile()def exit(self):root.destroy()def openAskColor(self):s1 = askcolor(color="red",title="选择背景色")self.textpad.config(bg=s1[1])def createContextMenu(self,event):# 菜单在鼠标右键单击的坐标处显示self.contextMenu.post(event.x_root, event.y_root)if __name__ == '__main__':root = Tk()root.geometry("450x300+200+300")root.title("景天的简易记事本")app = Application(master=root)root.mainloop()

运行
在这里插入图片描述

点击文件-新建
在这里插入图片描述

修改文件名
在这里插入图片描述

点击保存,保存到了桌面
在这里插入图片描述

点击文件-打开
在这里插入图片描述

随便写点东西
在这里插入图片描述

点击文件-保存,查看文件,内容已被保存进去
在这里插入图片描述

askopenfile返回的文件对象解析,里面的name即为包含路径的文件名字符串
在这里插入图片描述

修改文本背景色,在文本域右键,背景颜色
在这里插入图片描述

选一个背景色

在这里插入图片描述
在这里插入图片描述

4.【项目】画图软件开发

开发一款简单的画图软件, 包含如下功能:

  1. 画笔
  2. 矩形/椭圆绘制
  3. 清屏
  4. 橡皮擦
  5. 直线/带箭头的直线
  6. 修改画笔颜色、背景颜色
"""开发画图软件的菜单
"""from tkinter import *
from tkinter.colorchooser import *#窗口的宽度和高度
win_width=900
win_height=450class Application(Frame):def __init__(self, master=None,bgcolor="#000000"):super().__init__(master)        # super()代表的是父类的定义,而不是父类对象self.master = masterself.bgcolor=bgcolorself.x = 0self.y = 0self.fgcolor = "#ff0000"self.lastDraw = 0               # 表示最后绘制的图形的idself.startDrawFlag = Falseself.pack()self.createWidget()def createWidget(self):# 创建绘图区self.drawpad = Canvas(root,width=win_width,height=win_height*0.9,bg=self.bgcolor)self.drawpad.pack()#创建按钮,并给每个按钮定义一个名字,好区分btn_start = Button(root,text="开始",name="start")btn_start.pack(side="left",padx="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_oval = Button(root,text="椭圆",name="oval")btn_oval.pack(side="left",padx="10")btn_clear = Button(root,text="清屏",name="clear")btn_clear.pack(side="left",padx="10")btn_erasor = Button(root,text="橡皮擦",name="erasor")btn_erasor.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")#事件处理#按下鼠标左键btn_pen.bind_class("Button","<1>",self.eventManager)#释放按键事件self.drawpad.bind("<ButtonRelease-1>",self.stopDraw)#增加颜色切换的快捷键root.bind("<KeyPress-r>",self.kuaijiejian)root.bind("<KeyPress-g>",self.kuaijiejian)root.bind("<KeyPress-y>",self.kuaijiejian)def eventManager(self,event):#获取根据名字获取相关按钮name = event.widget.winfo_name()# print("获取widget:", dir(event.widget))print(name)if name=="line":self.drawpad.bind("<B1-Motion>",self.myline)elif name=="lineArrow":self.drawpad.bind("<B1-Motion>",self.mylineArrow)elif name=="rect":self.drawpad.bind("<B1-Motion>",self.myRect)elif name == "oval":self.drawpad.bind("<B1-Motion>", self.myOval)elif name=="pen":self.drawpad.bind("<B1-Motion>",self.myPen)elif name=="erasor":self.drawpad.bind("<B1-Motion>",self.myErasor)elif name=="clear":#清屏,直接delete("all")self.drawpad.delete("all")elif name=="color":c = askcolor(color=self.fgcolor,title="选择画笔颜色")#[(255,0,0),"#ff0000"]#将选择的颜色赋值给前景色self.fgcolor = c[1]def stopDraw(self,event):self.startDrawFlag = Falseself.lastDraw = 0def startDraw(self,event):self.drawpad.delete(self.lastDraw)if not self.startDrawFlag:self.startDrawFlag = Trueself.x = event.xself.y = event.ydef 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)#矩形边框颜色 outlineself.lastDraw = self.drawpad.create_rectangle(self.x,self.y,event.x,event.y,outline=self.fgcolor)def myOval(self,event):self.startDraw(event)#椭圆边框颜色 outlineself.lastDraw = self.drawpad.create_oval(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.xself.y = event.ydef myErasor(self,event):self.startDraw(event)#橡皮擦实现的原理是用画布背景的矩形将原图遮盖#将矩形区域放大一些self.drawpad.create_rectangle(event.x-4,event.y-4,event.x+4,event.y+4,fill=self.bgcolor)self.x = event.xself.y = event.ydef kuaijiejian(self,event):if event.char =="r":self.fgcolor = "#ff0000"elif event.char =="g":self.fgcolor = "#00ff00"elif event.char =="y":self.fgcolor = "#ffff00"if __name__ == '__main__':root = Tk()root.geometry(str(win_width)+"x"+str(win_height)+"+200+300")root.title("景天科技苑的画图软件")app = Application(master=root)root.mainloop()

运行
在这里插入图片描述

可以根据各个按钮,实现不同功能
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/29875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

百度智能云推出智能运维工具,云助手让云服务器运维更简单

为了提升云服务器执行命令的效率&#xff0c;百度智能云发布了 SmartTerm 远程连接终端。不止于此&#xff0c;为了更加极致地提升运维效率&#xff0c;我们又推出了「云助手」这款轻量快捷的运维工具。 ​ 只有做过云服务器运维的人才知道管理上万台云服务器有多崩溃。在海量…

了解振弦采集仪在建筑物安全监测中的应用与研究

了解振弦采集仪在建筑物安全监测中的应用与研究 摘要&#xff1a;河北稳控科技振弦采集仪是一种常用的结构物安全监测设备&#xff0c;广泛应用于建筑物、桥梁、塔楼等工程结构的监测。本文将从振弦采集仪的原理、应用案例和研究进展等方面进行详细介绍&#xff0c;以便更好地…

springboot3 基础特性(1)

文章目录 一、SpringApplication三种方式1.1 基础方式1.2.自定义 SpringApplication1.3、FluentBuilder API 二、自定义Banner三、Profiles3.1 什么是 Profiles &#xff1f;3.2 声明Profiles3.3 激活配置文件3.3.1 分组3.3.2 环境包含3.3.3 激活方式3.3.4 配置优先级 一、Spri…

STM32单片机USART串口详解

文章目录 1. 通信接口概述 2. 串口通信 3. 硬件电路 4. 电平标准 5. 串口参数及时序 5.1 数据帧的组成 5.2 起始位 5.3 数据位 5.4 校验位 5.5 停止位 5.6 波特率 5.7 数据帧传输过程示例 6. 串口时序 7. USART概述 8. USART框图 9. USART基本结构 10. 数据帧…

力扣793. 阶乘函数后 K 个零

Problem: 793. 阶乘函数后 K 个零 文章目录 题目描述思路即解法复杂度Code 题目描述 思路即解法 1.根据题意可知即是要求取满足条件的n最小是多少&#xff0c;最大是多少&#xff0c;最大值和最小值一减&#xff0c;就可以算出来有多少个n满足条件了。 2.由于题目中的阶乘存在单…

乡村养老服务管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;医疗人员管理&#xff0c;乡村志愿者管理&#xff0c;文娱活动管理&#xff0c;活动报名管理&#xff0c;医疗保健管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;文娱活…

简单记录一下命名规则

简单记录一下命名规则 1. 记录一下 在编程中&#xff0c;命名规则&#xff08;也称为命名约定&#xff09;是非常重要的&#xff0c;它可以帮助我们编写出更易于理解和维护的代码。一直记不住到底有哪些&#xff0c;稍微记一下&#xff01; 以下是一些常见的命名规则&#xf…

软件推荐 caj2pdf

## 推荐内容 用 zotero 管理文献时&#xff0c;不能处理知网 caj 格时&#xff0c;有大佬做了相应的工作并开源了。 今天推荐这两个 GitHub 项目 https://github.com/caj2pdf/caj2pdfhttps://github.com/ElonH/caj2pdf_gui 一是 python 做的 caj 2 pdf 源码&#xff0c;二是结…

005-OSPF基本配置

OSPF基本配置 OSPF (Open Shortest Path First) 是一种链路状态路由协议&#xff0c;它属于内部网关协议&#xff08;IGP&#xff09;类别&#xff0c;用于在自治系统&#xff08;AS&#xff09;内部路由 IP 数据包。OSPF 通过使用 Dijkstra 算法计算最短路径树来确定到达每个…

Linux之旅: 基础知识点的终极指南

文章目录 1、Linux的目录结构2、ls命令3、管理文件和目录4、linux命令使用细节和技巧5、权限管理基本命令6、搜索命令7、管道符与重定向8、压缩和解压命令9、用户及vim编辑器10、用户和用户组管理一、Linux系统用户账号的基本管理二、Linux系统用户组的管理 1、Linux的目录结构…

【CSS in Depth2精译】1.1.2 行内样式~1.1.3 选择器的优先级

文章目录 1.1.2 行内样式1.1.3 选择器的优先级1.1.3.1 优先级的写法1.1.3.2 关于优先级的思考 1.1.2 行内样式 如果无法通过样式表来源规则解决样式冲突&#xff0c;浏览器则会考察它们是否通过 行内样式 作用于该元素。当使用 HTML 的 style 属性声明样式时&#xff0c;该样式…

Win32编程:第一个窗口程序(Part.1)

Win32系统编程是指在Windows操作系统上使用Win32 API进行软件开发的过程&#xff1b;Win32 API是Windows操作系统提供的应用程序接口&#xff0c;允许程序与操作系统进行交互&#xff0c;实现各种功能。 以下是Win32系统编程的基本概念和步骤&#xff1a; 环境准备 开发工具&…

element-plus的form表单组件之checkbox组件

单个checkbox 绑定的响应式的值类型为bool类型&#xff0c;同一个组的checkbox多选其值对应值的数组&#xff0c;类型根据checkbox的value值而来。 label只用来显示具体的值&#xff0c;根据value属性来设置。 element-plus的checkbox提供多种特性。 如单选&#xff0c;多选…

关机充电动画:流程与定制

关机充电动画&#xff1a;流程与定制 基于MTK平台Android 11分析 生成logo.bin 关机充电动画是由一系列的bmp图片组成的&#xff0c;这些图片资源存在于vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo目录下&#xff08;当然不仅保护关机充电动画&#xff0c…

【软件工程】【22.10】p2

关键字&#xff1a; 软件开发基本途径、初始需求发现技术、UML表达事物之间关系、RUP需求获取基本步骤、项目过程建立涉及工作、项目规划过程域的意图和专用目标 判定表、分支覆盖、条件覆盖 三、简答 四、应用 这里条件覆盖有待商榷

SpringBoot配置第三方专业缓存技术jetcache方法缓存方案

jetcache方法缓存 我们可以给每个方法配置缓存方案 JetCache 是一个基于 Java 的缓存库&#xff0c;支持多种缓存方案和缓存策略&#xff0c;主要用于提升应用程序的性能和响应速度。它提供了多种缓存模式和特性&#xff0c;可以根据需求选择合适的缓存方案。 JetCache 的主…

问题解决:局域网下多台电脑实现共享打印机

看了很多篇解决措施&#xff0c;都没有解决&#xff0c;自己鼓弄了好久&#xff0c;终于解决了&#xff0c;如下步骤所示&#xff0c;实测好用。 首先先保证本电脑已打开网络共享 其次关闭防火墙&#xff08;有时会出现奇怪问题&#xff0c;最好关闭&#xff09; 接着访问IP…

Scikit-Learn支持向量机回归

Scikit-Learn支持向量机回归 1、支持向量机回归1.1、最大间隔与SVM的分类1.2、软间隔最大化1.3、支持向量机回归1.4、支持向量机回归的优缺点2、Scikit-Learn支持向量机回归2.1、Scikit-Learn支持向量机回归API2.2、支持向量机回归初体验2.3、支持向量机回归实践(加州房价预测…

TikTok账号养号的流程分享

对于很多刚开始运营TikTok的新手小白来说&#xff0c;都会有一个同样的疑问&#xff0c;那就是&#xff1a;TikTok到底需不需要养号&#xff1f;这里明确告诉大家是需要养号的&#xff0c;今天就把我自己实操过的养号经验和策略总结出来&#xff0c;分享给大家。 一、什么是Ti…

国产24位I2S输入+192kHz立体声DAC音频数模转换器CJC4344

CJC4344是一款立体声数模转换芯片&#xff0c;内含插值滤波器、multi bit数模转换器、输出模拟滤波器。CJC4344系列支持大部分的音频数据格式。CJC4344基于一个带线性模拟低通滤波器的四阶multi-bitΔ-Σ调制器&#xff0c;而且本芯片可以通过检测信号频率和主时钟频率&#xf…