【tkinter制作文本编辑器(2)】文件菜单选项栏事件功能实现(文件及内容操作)

1. 文件菜单选项栏事件功能实现步骤

上一个博客中已经完成了文本编辑器基本页面的UI设计,这里接着完善上一个博客中菜单栏及关联选项栏内容出现的功能(事件回调)。首先就是对“文件”菜单栏下的关联内容进行功能设置如下

1.1 新建文件

新建文件,就是直接清除当前文本的内容,然后创建一个新的画布(存在着窗口标题的重命名问题),其余的几乎是没有发生变化,因此这里就定义个new_file函数,进行新建文件,然后将这个函数添加command参数中

需要注意的一点就是:新建的文件一般是没有文件名称的,所以会有self.file_name = None,同时为了更方便的调用这个变量(进行保存或者另存为时候需要用到),可以将其声明为全局变量(和之前的icon_res一样转化为类属性)

def new_file(self,event=None):
	self.title('New - EditorPlus')
	self.content_text.delete(1.0,END)
	self.file_name = None

#函数封装完毕后,需要把函数名称添加到command参数之后	
file_menu.add_command(label='新建',accelerator = 'Ctrl+N',command=self.new_file)

→ 输出的结果为:(新建文件功能实现)在这里插入图片描述

1.2 打开文件

打开文件就是在当前编辑器窗口界面上加载一个本地的文件(默认是txt),这时候就需要调用文件对话框了,设定要打开的文件类型。注意如果用户只是打开文件对话框并没有选择任何本地的文件,这时候不应执行打开文件的命令(也就是存在着条件判断,只用当用户选择了某一个文件的时候时,才进行文件的打开),整个过程封装在open_file函数中,然后将这个函数添加command参数中,如下

注意三点:① 弹出文件对话框中设置要选择打开的文件的类型

② 要对用户的操作进行判断,是否真实地点击了要打开的文件,如果点击了,才会打开文件

③ 这里的打开文件,实际上就是,将原来程序窗口的标题重新命名,然后把里面的文本内容全部删除,接着对这个文件名称进行赋值(这步操作就是为了后面的文件保存),最后再将与打开的文件内容写到文本栏中,这里要加上.read(),否则写入的只是一个文本对象,写入的方式很简单就是在最开始的地方开始插入欲打开的文本数据

def open_file(self,event=None):
	input_file = filedialog.askopenfilename(
		filetypes=[('所有文件','*.*'),('文本文档','*.txt')])  #弹出文件对话框,设置选择文件的类型
	
	if input_file:   			#如果用户选择了文本,则进行打开
		#print(input_file)   	#这里可以调试,看一下选中文本的路径的形式(绝对路径)
		self.title('{} - EditorPlus'.format(os.path.basename(input_file))) #以文件的名称进行窗口标题的命名
		self.file_name = input_file 	   #将这个打开的文件对象命名为其原来文件的名称
		self.content_text.delete(1.0,END)  #删除当前文本内容中的数据
		with open(input_file, 'r') as _file:
			self.content_text.insert(1.0,_file.read())  #将要打开文件中的数据写入到文本内容中

#函数封装完毕后,需要把函数名称添加到command参数之后	
file_menu.add_command(label='打开',accelerator = 'Ctrl+O',command=self.open_file)

→ 输出的结果为:(打开文件的功能实现)
在这里插入图片描述

1.3 保存文件

保存文件涉及到条件判断,也就是上面提及到的file_name(文件名称变量),如果这个文件是已经打开(有了文件名称变量的赋值),说明可以直接保存文件,如果文件file_name=None(比如新建的文件,文件的名称一般是没有的),这时候保存文件实际上就是将文件另存为,需要指定文件的路径和要保存的文件名称,因此整个过程封装save函数之中,然后将这个函数添加command参数中,如下

def save(self, event=None):
	if not self.file_name:  #这里就体现出来之前设置的self.file_name全局变量的作用了
		self.save_as()      #没有有文件名称的另保存
	else:
		self._write_to_file(self.file_name)  #有文件名称的直接写入文件(保存本地)

#函数封装完毕后,需要把函数名称添加到command参数之后	
file_menu.add_command(label='保存',accelerator = 'Ctrl+S',command=self.save)

1.4 另存为文件

有了之前打开文件和保存文件的操作,另存为文件的就变得较为简单,这里就是调用文件对话框,然后判断用户有没有进行文件名称的输入,如果有的话就执行文件的写入(类似之前的打开文件),整个过程封装为save_as函数,然后将这个函数添加command参数中,如下

def save_as(self,event=None):
	input_file = filedialog.asksaveasfilename(        #注意这里弹出的是文件保存对话框
		filetypes = [('所有文件','*.*'),('文本文档','*.txt')]
		)
	if input_file:   						#还是要对用户操作进行判定
		self.file_name = input_file     	#设置文件名称
		self._write_to_file(self.file_name) #写入本地

#函数封装完毕后,需要把函数名称添加到command参数之后	
file_menu.add_command(label='另存为',accelerator = 'Ctrl+Shift+S',command=self.save_as)

1.5 文本内容写入

通过上面的两个函数可以发现,最后都是直接调用_write_to_file函数,将多个函数中都要使用的步骤封装起来再调用可以明显的较少代码量,也可以提高程序的运行效率。现实中会存在一个问题就是,文本在保存中或者另存为的过程中可能出现保存失败,为了复现这个功能需要使用到try-except进行异常处理。整个过程封装如下

注意:这里是保存和另存为函数下来的内容,只是将相同的内容封装成一个函数,减少代码量,不需要将这部分函数添加到command参数中

def _write_to_file(self, file_name):
	try:
		content = self.content_text.get(1.0, 'end')  #先获取文本框中的所有数据
		with open(file_name, 'w') as the_file:
			the_file.write(content)					 #将数据写入到本地的文件中
		self.title("%s - EditorPlus" % os.path.basename(file_name)) #这一步就是显示当前窗口的标题不变,可以尝试注释一下这行代码
	except IOError:    
		messagebox.showwarning("保存", "保存失败!")   #如果保存失败的话,会弹出消息对话框

→ 输出的结果为:(刚开始在新建的文件窗口上输入“保存文件”,这时候没有文件的名称,所以点击保存就相当于另存为文件(命名为2.txt),然后将该文件的内容修改为“另保存文件”,点击另存为3.txt,这时候再在3.txt文件上随机打入文字,点击保存,后重新打开2.txt和3.txt来检测保存文件和另存为文件的功能正常,至此文件保存和另存为功能实现)
在这里插入图片描述

1.6 退出程序

这里可以直接调用之前已经设置好的主窗口退出的函数,然后将这个函数添加command参数中,如下

def exit_editor(self):
	if messagebox.askokcancel('退出?','确定退出吗?'):
			self.destroy()

#函数封装完毕后,需要把函数名称添加到command参数之后	
file_menu.add_command(label='退出',accelerator = 'Alt+F4', command=self.exit_editor)

→ 输出的结果为:(至此,“文件”菜单栏所有的功能全部实现)
在这里插入图片描述

2. 快捷键绑定

在菜单栏上设置的有快捷键操作的提示,但是真正要实现快捷键调用函数的功能还需要进行文本内容的绑定,也就是说快捷键的使用是要在文本栏存在的情况下设置(只要主程序窗口打开,文本栏默认是存在的)。在_create_body_函数下设置相应的内容,如下

self.content_text.bind('<Control-N>', self.new_file)
self.content_text.bind('<Control-n>', self.new_file)
self.content_text.bind('<Control-O>', self.open_file)
self.content_text.bind('<Control-o>', self.open_file)
self.content_text.bind('<Control-S>', self.save)
self.content_text.bind('<Control-s>', self.save)
self.content_text.bind('<Control-Shift-S>', self.save_as)
self.content_text.bind('<Control-Shift-s>', self.save_as)
self.content_text.bind('<Alt-F4>', self.exit_editor)

→ 输出的结果为:(分别进行了新建,另存为,打开,保存和关闭的快捷键操作)
在这里插入图片描述

3. 全部代码

实现该部分功能的全部代码如下

def _create_body_(self):

	#创建文本输入框
	self.content_text = Text(self, wrap='word')
	self.content_text.pack(expand='yes',fill='both')
	self.content_text.bind('<Control-N>', self.new_file)
	self.content_text.bind('<Control-n>', self.new_file)
	self.content_text.bind('<Control-O>', self.open_file)
	self.content_text.bind('<Control-o>', self.open_file)
	self.content_text.bind('<Control-S>', self.save)
	self.content_text.bind('<Control-s>', self.save)
	self.content_text.bind('<Control-Shift-S>', self.save_as)
	self.content_text.bind('<Control-Shift-s>', self.save_as)
	self.content_text.bind('<Alt-F4>', self.exit_editor)
	
def _create_menu_bar_(self):
	menu_bar = Menu(self)  #实例化菜单栏对象

	#文件菜单
	file_menu = Menu(menu_bar, tearoff = 0)  			#基于菜单栏实例化“文件”关联选项栏对象
	file_menu.add_command(label='新建',accelerator = 'Ctrl+N',command=self.new_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_menu.add_command(label='另存为',accelerator = 'Ctrl+Shift+S',command=self.save_as)
	file_menu.add_separator()
	file_menu.add_command(label='退出',accelerator = 'Alt+F4', command=self.exit_editor)

	menu_bar.add_cascade(label='文件',menu = file_menu) 	#将“文件”关联选项栏放在“文件”菜单栏上

def new_file(self, event=None):
		self.title("New - EditorPlus")
		self.content_text.delete(1.0, END)
		self.file_name = None

def open_file(self, event=None):
	input_file = filedialog.askopenfilename(
		filetypes=[("所有文件", "*.*"), ("文本文档", "*.txt")])
	if input_file:
		self.title("%s - EditorPlus" % os.path.basename(input_file))
		self.file_name = input_file
		self.content_text.delete(1.0, END)
		with open(input_file, 'r') as _file:
			self.content_text.insert(1.0, _file.read())

def save(self, event=None):
	if not self.file_name:
		self.save_as()
	else:
		self._write_to_file(self.file_name)

def save_as(self, event=None):
	input_file = filedialog.asksaveasfilename(
		filetypes=[("All Files", "*.*"), ("文本文档", "*.txt")])
	if input_file:
		self.file_name = input_file
		self._write_to_file(self.file_name)

def _write_to_file(self, file_name):
	try:
		content = self.content_text.get(1.0, 'end')
		with open(file_name, 'w') as the_file:
			the_file.write(content)
		self.title("%s - EditorPlus" % os.path.basename(file_name))
	except IOError:
		messagebox.showwarning("保存", "保存失败!")
		
def exit_editor(self):
		if messagebox.askokcancel("退出?", "确定退出吗?"):
			self.destroy()
  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以为您提供一些代码,帮助您实现这个文本编辑器。 首先,需要导入tkinter库,以及一些其他必要的库: ```python import tkinter as tk from tkinter import filedialog from tkinter import messagebox from tkinter import scrolledtext import os ``` 然后,可以创建一个名为TextEditor的类,并在其中定义一些方法,如下所示: ```python class TextEditor: def __init__(self, master): self.master = master master.title("文本编辑器") self.textarea = scrolledtext.ScrolledText(master, wrap=tk.WORD, width=80, height=30) self.textarea.pack(expand=True, fill='both') self.filename = None # 创建菜单 self.menu_bar = tk.Menu(master) self.file_menu = tk.Menu(self.menu_bar, tearoff=0) self.edit_menu = tk.Menu(self.menu_bar, tearoff=0) self.menu_bar.add_cascade(label="文件", menu=self.file_menu) self.menu_bar.add_cascade(label="编辑", menu=self.edit_menu) master.config(menu=self.menu_bar) # 添加文件菜单中的选项 self.file_menu.add_command(label="打开", command=self.open_file) self.file_menu.add_command(label="保存", command=self.save_file) self.file_menu.add_command(label="另存为", command=self.save_as) self.edit_menu.add_command(label="撤销", command=self.undo) self.edit_menu.add_command(label="重做", command=self.redo) self.edit_menu.entryconfig("撤销", state="disabled") self.edit_menu.entryconfig("重做", state="disabled") # 添加撤销/重做功能 self.undo_stack = [] self.redo_stack = [] self.textarea.bind('<Key>', self.on_key_press) ``` 接下来,可以定义一些方法,用于实现打开、保存、另存为、撤销和重做功能: ```python def open_file(self): file = filedialog.askopenfile(mode='r', title='打开文件', defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]) if file is not None: self.filename = file.name content = file.read() self.textarea.delete(1.0, tk.END) self.textarea.insert(tk.END, content) file.close() def save_file(self): if self.filename is None: self.save_as() else: content = self.textarea.get(1.0, tk.END) with open(self.filename, 'w') as file: file.write(content) def save_as(self): file = filedialog.asksaveasfile(mode='w', title='另存为', defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]) if file is not None: self.filename = file.name content = self.textarea.get(1.0, tk.END) file.write(content) file.close() def on_key_press(self, event): if event.keysym not in ['Control_L', 'Control_R', 'Alt_L', 'Alt_R', 'Shift_L', 'Shift_R']: self.undo_stack.append(self.textarea.get(1.0, tk.END)) if len(self.undo_stack) > 50: self.undo_stack.pop(0) self.edit_menu.entryconfig("撤销", state="normal") self.edit_menu.entryconfig("重做", state="disabled") self.redo_stack = [] def undo(self): if len(self.undo_stack) > 1: self.redo_stack.append(self.undo_stack.pop()) self.textarea.delete(1.0, tk.END) self.textarea.insert(tk.END, self.undo_stack[-1]) if len(self.undo_stack) == 1: self.edit_menu.entryconfig("撤销", state="disabled") if len(self.redo_stack) > 0: self.edit_menu.entryconfig("重做", state="normal") def redo(self): if len(self.redo_stack) > 0: self.textarea.delete(1.0, tk.END) self.textarea.insert(tk.END, self.redo_stack[-1]) self.undo_stack.append(self.redo_stack.pop()) if len(self.redo_stack) == 0: self.edit_menu.entryconfig("重做", state="disabled") if len(self.undo_stack) > 1: self.edit_menu.entryconfig("撤销", state="normal") ``` 最后,在主程序中创建一个TextEditor对象即可: ```python if __name__ == '__main__': root = tk.Tk() editor = TextEditor(root) root.mainloop() ``` 完整的代码如下所示:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lys_828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值