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,一经查实,立即删除!

相关文章

【0287】Postgres内核在pg_internal.init不存在情况下的relcache cache初始化实现

上一篇: 【0264】深入分析relcache(relation descriptor cache)缓存初始化第2阶段(2) 0. 前言 在用户未CREATE DATABASE 情况(即initdb创建了Postgres数据库集簇,或有过psql登录数据库动作)下,PGDATA/global目录下是还不存在pg_internal.init文件的,因此,启动Post…

elasticsearch安装(centos7)

先给出网址 elasticsearch&#xff1a;Download Elasticsearch | Elastic elasticKibana&#xff1a;Download Kibana Free | Get Started Now | Elastic Logstash&#xff1a;Download Logstash Free | Get Started Now | Elastic ik分词&#xff1a;Releases infinilabs/…

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

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

Ruby 数据库访问 - DBI 教程

Ruby 数据库访问 - DBI 教程 本文将详细介绍如何使用 Ruby 的 DBI(Database Interface)库来访问和操作数据库。DBI 是 Ruby 语言中一个常用的数据库接口库,它提供了一套统一的接口来访问不同的数据库系统,如 MySQL、PostgreSQL、SQLite 等。通过本文的学习,您将掌握如何使…

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

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

解决python从TD数据库取50w以上大量数据慢的问题

1.问题背景描述 python项目中的时序数据都存放在TD数据库中&#xff0c;数据是秒级存入的&#xff0c;当查询一周数据时将超过50w数据量&#xff0c;这是一次性获取全量数据到python程序很慢&#xff0c;全流程10秒以上&#xff0c;希望进行优化加速 2.排查 首先&#xff0c…

vue中使用发布订阅的方式进行vue组件之间的通信

全部实现代码如下&#xff1a; header.vue组件的相关代码 Search GitHub Users <input type“button” value“Search” class“btn btn-primary” placeholder“请输入 github 用户名” click“search”> main组件的相关代码 请输入搜索用户的名称 loading {{error…

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…

常用告警规则

Node_exporter告警规则 NodeCPUUsageHigh: yaml 复制代码 alert: NodeCPUUsageHigh expr: (100 - (avg by (instance) (rate(node_cpu_seconds_total{mode“idle”}[5m])) * 100)) > 80 for: 5m labels: severity: critical annotations: summary: “High CPU usage detec…

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;文娱活…

确保数据一致性

目录 事务 ACID 属性 事务的作用 示例 隔离级别 事务管理的重要性 检查点 概述 检查点的好处 检查点的执行策略 检查点操作示例 并发控制 概述 并发控制技术 优点 缺点 适用场景 在数据库管理系统中&#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;该样式…

js-promise、async/await

promise&#xff0c;简单就就是回调的一种简化了回调地狱&#xff08;如果多个调用是异步并且有结果依赖&#xff0c;那么就需要写成回调&#xff09;。 async/await&#xff0c;需要成对使用&#xff0c;是对promise的更高级的抽象&#xff0c; 比如 runAsync1() .then(fun…

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

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