在上一章中我添加了一个保存文件内容的菜单选项,但遗憾的是当我点击 "保存" 选项时编辑器并不会真正地保存我的文件内容,他只是一个单纯的选项,不会执行任何的关于文件读写的操作。
今天,让我继续改造这个文本编辑器,使它可以保存我的文件内容。
如果忘记了上一章的内容,下面是上一章中的完整源码。
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, title, size=(600,400)):
wx.Frame.__init__(self, parent=parent, title=title, size=size)
# 文本编辑框
self.text_control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
# 菜单
file_menu = wx.Menu()
file_menu_save = file_menu.Append(wx.ID_SAVE, '保存', '将会保存输入框中的内容')
window_menu = wx.MenuBar()
window_menu.Append(file_menu, '文件')
self.SetMenuBar(window_menu)
# 窗口状态栏
self.CreateStatusBar()
self.Show(True)
app = wx.App()
window = MainWindow(None, '文本编辑器')
app.MainLoop()
嗯...,复习完上一章的内容,别急着打开代码编辑器写代码,先了解事件处理的思想:GUI 应用程序的核心是对各种交互事件的处理程序。应用程序一般在完成建立图形界面 等初始化工作后都会进入一个事件循环(例如WxPython的
app.MainLoop()
),等待事件发生并触发相应的事件处理程序。
我一直坚信学习是一个把复杂内容简化后存入脑子的过程,所以上面一段话我简化为:“我转动汽车的钥匙,汽车使用电瓶替我发动了汽车”
额外的提示:事件的概念。
事件!简单的理解,事件就是你的行为所触发的....额.....一些..东西。例如你点击了程序中的一个按钮,可以称为一个 “点击事件”
那我保存文件的过程可以是这样的:
- 我点击“保存”菜单选项
- WxPython为我调用一个方法,替我把文件内容保存到硬盘中
大概了解后,打开代码编辑器,开始为程序添加处理 “保存” 事件的功能。
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, title, size=(600,400)):
wx.Frame.__init__(self, parent=parent, title=title, size=size)
# 菜单
file_menu = wx.Menu()
file_menu_save = file_menu.Append(wx.ID_SAVE, '保存', '将会保存输入框中的内容')
window_menu = wx.MenuBar()
window_menu.Append(file_menu, '文件')
self.SetMenuBar(window_menu)
# 文本编辑框
self.text_control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
# 窗口状态栏
self.CreateStatusBar()
# 新内容
# 关联事件
self.Bind(wx.EVT_MENU, self.save_file_content, file_menu_save)
self.Show(True)
# 新内容
# 保存输入框架内容
def save_file_content(self, event):
print('保存文件')
app = wx.App()
window = MainWindow(None, '文本编辑器')
app.MainLoop()
代码解读
Bind() 方法
函数原型:Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)
参数event
(必须):指定发生的事件类型
参数handler
(必须):指定事件发生后调用的事件处理方法
参数source
(可选):事件发生者(或者说事件的来源)
参数id
(可选):此参数使用wx.ID_ANY让Widgets自行选择
参数id2
(可选):此参数使用wx.ID_ANY让Widgets自行选择
self.Bind(wx.EVT_MENU, self.save_file_content, file_menu_save)
参数(wx.EVT_MENU):指定事件类型为菜单事件
参数(self.save_file_content):指定处理事件的方法为save_file_content()
参数(file_menu_save):此参数为file_menu.Append(wx.ID_SAVE, '保存', '将会保存输入框中的内容')
返回的控件的句柄(或者说控件的标识)。
def save_file_content(self, event):
这是处理保存事件的方法,用于保存输入框内容到文件中
参数(event):发生的事件,事件处理方法已被WxPython写死,只能接收一个参数
现在我拥有了一个处理 “保存” 事件的方法: save_file_content()
,当我点击菜单中的 “保存” 选项时就会调用此方法来处理我的事件。现在来测试下我们的劳动成功
点击 “保存” 选项时确实调用了
save_file_content()
来处理我保存事件,而
save_file_content()
的作用就是在控制台打印
保存文件
继续!,完善 save_file_content()
。
def save_file_content(self, event):
'''
保存文件内容
与菜单中的保存选项绑定
'''
self.dir_name = ''
fd = wx.FileDialog(self, '把文件保存到何处', self.dir_name, '.txt', 'TEXT file(*.txt)|*.txt', wx.FD_SAVE)
if fd.ShowModal() == wx.ID_OK:
self.file_name = fd.GetFilename()
self.dir_name = fd.GetDirectory()
try:
with open(os.path.join(self.dir_name, self.file_name), 'w', encoding='utf-8') as f:
text = self.text_control.GetValue()
f.write(text)
save_msg = wx.MessageDialog(self, '文件已保存', '提示')
except FileNotFoundError:
save_msg = wx.MessageDialog(self, '保存失败,无效的保存路径', '提示')
else:
save_msg = wx.MessageDialog(self, '未选择保存路径', '错误')
save_msg.ShowModal()
save_msg.Destroy()
小提示:由于使用了os.path.join()
,需要 导入os
模块
现在save_file_content()
是一个完整的文件保存方法了。
需要注意的是,在完善过程中,我添加了两个新内容,分别是 “文件对话框” 与 “提示对话框,在此章节中,不必学习这两个新内容,但为了文章的可读性,我将会简单介绍下这两个新内容。
文件对话框
# 文件对话框
fd = wx.FileDialog(self, '把文件保存到何处', self.dir_name, '.txt', 'TEXT file(*.txt)|*.txt', wx.FD_SAVE)
# 显示文件对话框
fd.ShowModal()
# 获取文件名
file_name = fd.GetFilename()
# 获取文件所在的目录的路径
dir_name = fd.GetDirectory()
不知道“文件对话框”?,参考下图:
提示对话框
# 提示对话框
save_msg = wx.MessageDialog(self, '文件已保存', '提示')
# 显示对话框
save_msg.ShowModal()
# 销毁对话框
save_msg.Destroy()
不知道“提示对话框”?参考下图:
好的,介绍完新内容,进行新一轮测试,来结束今天的内容。
啊~~,完美。
最后附上完整的示例源码
import wx
import os
class MainWindow(wx.Frame):
def __init__(self, parent, title, size=(600, 400)):
wx.Frame.__init__(self, parent=parent, title=title, size=size)
# 文本编辑框
self.text_control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
# 菜单
file_menu = wx.Menu()
file_menu_save = file_menu.Append(wx.ID_SAVE, '保存', '保存文件内容')
menu_bar = wx.MenuBar()
menu_bar.Append(file_menu, '文件')
self.SetMenuBar(menu_bar)
# 状态栏
self.CreateStatusBar()
# 新内容
# 新内容添加了事件处理功能
# Bind()把事件与时间处理方法绑定
self.Bind(wx.EVT_MENU, self.save_file, file_menu_save)
self.Show()
def save_file(self, event):
'''
保存文件内容
与菜单中的保存选项绑定
'''
self.dir_name = ''
fd = wx.FileDialog(self, '把文件保存到何处', self.dir_name,
'.txt', 'TEXT file(*.txt)|*.txt', wx.FD_SAVE)
if fd.ShowModal() == wx.ID_OK:
self.file_name = fd.GetFilename()
self.dir_name = fd.GetDirectory()
try:
with open(os.path.join(self.dir_name, self.file_name), 'w', encoding='utf-8') as f:
text = self.text_control.GetValue()
f.write(text)
save_msg = wx.MessageDialog(self, '文件已保存', '提示')
except FileNotFoundError:
save_msg = wx.MessageDialog(self, '保存失败,无效的保存路径', '提示')
else:
save_msg = wx.MessageDialog(self, '未选择保存路径', '错误')
save_msg.ShowModal()
save_msg.Destroy()
app = wx.App()
main_window = MainWindow(None, '文本编辑器')
app.MainLoop()