------教程-----iPro7中关于模版管理的源代码分析
大家好我是小马,前面我分析了有关数据库和文件管理器2的源代码分析,今天我来给大家分析下模版管理的源代码
======================教程开始================================
class Mould(object, ) :#模块管理,用过iPro7的应该都知道吧
__module__ = __name__
def __init__(s, dir, pos_dir):#仍然是初始化操作,这里提供了两个参数一个是存储模块的路径,一个是存储模块光标路径的
s.dir = dir
s.pos_dir = pos_dir
if not (os.path.isdir(dir)) : #如果这个路径不存在就创建这个路径
try :
os.makedirs(dir)
except :
ui.note(zw('模板功能出错'), 'error')
pass
if not (os.path.isdir(pos_dir)) : #如果这个路径不存在就创建这个路径
try :
os.makedirs(pos_dir)
except :
ui.note(zw('模板功能出错'), 'error')
pass
def _add_mould(s): #添加模块
ask_mould = file_manager.AskFile(ext = ['.py', '.txt'], dirs = eval(db['work_dirs']), multi = False)#调用文件浏览函数浏览要添加的模块,这里的ext为后缀限制,dirs为默认打开的路径,你会问了为什么要使用eval呢,有什么作用?eval() 函数通常用来执行一条包含返回值的表达式,这里是返回我们设置的工作目录,其中db['work_dirs']得到的是一个字符串,经过eval函数之后就变成了py可执行的代码,要不然会出错的
if ask_mould == [] : #如果用户选择了取消,直接返回
return None
ask_mould = ask_mould[0] #这里不知道为何这么写,不过这不影响程序的运行,我感觉去掉这一句没什么问题,现在得到的ask_module是一个文件路径
mould_path = zw(s.dir) + (u'%s.py' % zw(os.path.splitext(os.path.basename(ask_mould))[0]))#使用os.path.basename(ask_mould)得到文件名有后缀的,然后用os.path.splitext(os.path.basename(前面得到的文件名))[0]得到文件的文件名没有后缀
while True :
if os.path.exists(en(mould_path)) : #如果想要添加的模块已经有相同的名字,弹出对话框询问用户如何执行
ask_cover = ui.popup_menu([zw('重命名'), zw('覆盖')], zw('同名模板已存在'))
if ask_cover is None : #用户选择取消直接返回
return None
elif ask_cover == 0 : #用户选择重命名,弹出对话框提示用户输入新的名字
name = ui.query(zw('模板名'), 'text')
if name is None : #如果没有重命名而选择了取消,就直接返回退出while循环
return None
mould_path = s.dir + name + u'.py' #更新moudle_path为重命名后的路径
else : #如果用户选择了覆盖,直接退出while因为程序本来就会直接覆盖写入的
break
pass
else : #如果没有存在相同的文件直接退出while循环,复制选择的模块到我们定义的模块文件夹里
break
try :
e32.file_copy(mould_path, ask_mould) #调用e32模块里的file_copy函数进行文件的复制
s.mould_list.insert(0, os.path.splitext(os.path.basename(mould_path))[0]) #在s.mould_list列表里插入我们刚才选择的模块
s.lb.insert(0, ui.Item(s.mould_list[0])) #在我们看到的模块列表里插入我盟刚才添加的模块
s.lb.set_current(0) #把光标定位到第一个模块
except :
ui.note(zw('无法添加'), 'error')
def _edit_pos(s): #编辑光标位置
try :
f = open(s.dir + en(s.lb.current_item().__dict__['title']) + '.py') #使用s.lb.current_item().__dict__['title']来得到当前模块的名字不含后缀,这个是文件是模块
try :
length = len(f.read().decode('u8')) #得到这个模块文件的总长度
finally :
f.close() #关闭打开的文件,减少内存的占用等
except :
ui.note(zw('模板错误'), 'error') #如果打开失败提示用户并返回
return None
try :
f = open(s.pos_dir + en(s.lb.current_item().__dict__['title']) + '.py') #使用s.lb.current_item().__dict__['title']来得到当前模块的名字不含后缀,这个文件是保存我们设定的模块里的光标的文件
try :
old_pos = int(f.read()) #使用内置函数int把读取的数值转换为int型
finally :
f.close() #关闭文件
except : #如果读取出错把光标位置 默认设置为文件的长度
old_pos = length
ask = ui.query(zw('光标位置'), 'number', old_pos) #询问用户设定光标的位置
if ask is None : #如果取消直接返回
return None
elif ask > length : #如果用户输入的值比文件的长度还要长,默认置为文件长度
ask = length
ui.note(zw('光标位置超出模板长度,已自动更改为模板长度'))
try : #打开存放模版光标位置的文件,并把刚才用户输入的值写入,进行更新
f = open(s.pos_dir + en(s.lb.current_item().__dict__['title']) + '.py', 'w')
try :
f.write(str(ask)) #这里得到的ask是int型的我们要转换成str字符串型材可以写入的
finally :
f.close()
except :
ui.note(zw('无法保存设置'), 'error')
def _edit(s): #编辑模版
try :
f = open(s.dir + en(s.lb.current_item().__dict__['title']) + '.py') #打开模版文件
except :
ui.note(zw('无法打开编辑'), 'error')
return None
try :
try :
fr = f.read().decode('u8').replace(u'\r\n', u'\n') #读取模版中的内容,并使用'\n'替换'\r\n'换行,注意这里也是我们第一次读取到的内容,后面我们会用到的,这里你会有疑问,"\r\n"是什么,注意:unicode中的换行是"\r\n" 前面我们不是使用了decode("u8")把读到的u8编码的内容转换成unicode编码,然后用"\n" 替换"\r\n"
finally :
f.close()
except :
ui.note(zw('无法打开编辑'), 'error')
return None
old_title = ui.app.title #保存原来的标题
old_menu = ui.app.menu #保存原来的菜单项
old_exit_key = ui.app.exit_key_handler #保存原来的退出键功能
old_body = ui.app.body #保存原来的程序主界面
def edit_pos(): #设定光标位置
try :
f = open(s.pos_dir + en(s.lb.current_item().__dict__['title']) + '.py', 'w') #打开光标文件
try :
f.write(str(w.get_pos())) #默认取得当前光标的位置并写入光标文件中
ui.note((zw('光标位置已更改为\n%d') % w.get_pos()), 'conf')
finally :
f.close()
except :
ui.note(zw('无法保存设置'), 'error')
def back(ask = True): #
if ask and w.get() != initial : #这里的initial是我上面提到过的第一次读取到的内容,这句是判断用户是否进行了修改
ask_save = ui.popup_menu([zw('保存'), zw('取消')], zw('文件已修改')) #如果用户进行了改动,退出的时候提示用户是否保存修改
if ask_save is None : #如果用户取消直接返回
return None
elif ask_save == 0 : #如果用户选择保存,打开文件并把修改后的内容写入文件中
try :
f = open(s.dir + en(s.lb.current_item().__dict__['title']) + '.py', 'w')
except :
ui.note(zw('无法保存'), 'error')
return None
try :
f.write(w.get().replace(u'\u2029', u'\n').encode('u8')) #这里又会有疑问,"\u2029"是什么东西,别着急我们从程序总读到的内容是Python的源码,而在python中默认的换行就是"\u2029",unicode默认的换行是"\r\n" 而u8的换行标志是"\n" 这下子就不会乱了吧
f.close()
except :
ui.note(zw('文件错误'), 'error')
return None
pass
pass
ui.app.title = old_title #还原原来的标题
ui.app.body = old_body #还原原来的程序主体
ui.app.menu = old_menu ##还原原来的菜单项
ui.app.exit_key_handler = old_exit_key ##还原原来的退出键功能
ui.app.body.bind(8, s._del_mould) #设置快捷方式,删除键为删除功能,bind也就是绑定的意思喽
ui.app.title = s.lb.current_item().__dict__['title'] #设定编辑界面下的标题为当前选择列表中的标题
ui.app.body = w = ui.Text() #设定标记界面下的程序主题为Text()界面
initial = fr.replace(u'\n', u'\u2029') #文件的初始化读取到的内容应该是Python的源代码,也就是说换行标志是"\u2029"
try :
w.set(fr) #把读取到的内容输出到屏幕上
except :
ui.note(zw('无法打开编辑'), 'error')
back(ask = False) #如果打开失败了,把ask设置为False在选择返回的时候就不会询问用户是否保存了
return None
ui.app.menu = [(zw('设定光标'), edit_pos), (zw('返回'), back)] #设置编辑界面的菜单项
ui.app.exit_key_handler = back #设置编辑界面下的退出键的功能,这样避免与主界面的退出键的功能发生冲突
def _rename(s): #对模版进行重命名
ask = ui.query(zw('重命名'), 'text', s.lb.current_item().__dict__['title']) #询问用户输入新的名字
if ask is None : #如果用户选择取消,直接返回
return None
try : #如果用户输入了新的名字,调用os模块的rename函数进行重命名功能
os.rename(s.dir + en(s.lb.current_item().__dict__['title']) + '.py', s.dir + en(ask) + '.py') #注意这里的rename里有两个参数,第一个是源文件的名字,第二个是我们想要改成的目标文件的名字
try :
os.rename(s.pos_dir + en(s.lb.current_item().__dict__['title']) + '.py', s.dir + en(ask) + '.py') #上面我们只是修改了模块的名字,记得我们还有模块光标文件的名字没有修改,这个是修改光标文件的名字的
except :
pass
except :
ui.note(zw('无法重命名'), 'error')
return None
s.lb.current_item().__dict__['title'] = ask #上面的语句只是更改了文件的名字,这里是修改我们看到的列表的名字
s.lb[s.lb.current()] = s.lb[s.lb.current()] #刷新当前光标所在的列表显示,(也就是我们刚才重命名的那个列表行)
def _del_mould(s): #删除模版
if len(s.lb) == 0 : #如果一个模版也没有直接返回
return None
index = s.lb.current() #获取当前光标所在的列表,也就是想要删除的列表
if ui.query((zw("删除\n'%s'?") % s.mould_list[index]), 'query') : #删除s.mould_list中我们选中的那个模版
try :
os.remove(s.dir + en(s.mould_list[index] + u'.py')) #这里执行删除模块任务
try :
os.remove(s.pos_dir + en(s.mould_list[index] + u'.py')) #这里执行删除模块相应的光标文件的任务
except :
pass
if index == (len(s.lb) - 1) : #如果要删除的是列表里的最后一个
s.lb.set_current((index - 1)) #把光标移动到刚才删除的模块的前面,也就是现在的列表的最后一个
del s.lb[index] #执行删除任务,
del s.mould_list[index] #删除s.module_list里的那个项目
except :
ui.note(zw('无法删除'), 'error')
pass
def _del_all_mould(s): #删除所有模版
if ui.query(zw('删除所有模板?'), 'query') : #询问用户是否全部删除
new_mould_list = [] #新建一个列表new_module_list来保存删除异常的模版
for m in s.mould_list: #依次遍历s.module_list里的文件
try :
os.remove(s.dir + en(m + u'.py')) #尝试删除
except :
ui.note((zw("无法删除\n'%s'") % m), 'error')
new_mould_list.append(m) #出现异常无法删除后把无法删除的模版保存到我们新建的new_module_list列表里
del s.mould_list[:] #删除全部模版
s.mould_list.extend(new_mould_list) #现在用s.module_list保存着无法删除后的模版
del s.lb[:] #清空s.lb列表
s.lb.extend([ui.Item(x) for x in s.mould_list]) #现在s.lb里保存这无法删除后的模版
def manager(s, back_callback): #管理模版
s.lb = ui.Listbox2([]) #创建一个列表,不过这个列表是appuifw2里面的Listbox2实例,目前我还不是很理解,如果有懂的麻烦给解释下哈
s.mould_list = [zw(os.path.splitext(x)[0]) for x in os.listdir(s.dir)] #用s.mould_list来保存模版路径下的模版文件名列表,我认为应该是一个中间变量,方便我们使用创建的
s.lb.extend([ui.Item(x) for x in s.mould_list]) #列出所有的模版
ui.app.body = s.lb #设置模版管理界面的主体是列表
ui.app.title = zw('模板管理')
ui.app.body.bind(8, s._del_mould) #设置快捷键,删除键为删除功能
ui.app.exit_key_handler = back_callback #设置退出键为传进来的参数函数,这个功能在program类里面有空我会写那个分析的
ui.app.menu = [(zw('添加'), s._add_mould), (zw('编辑'), s._edit), (zw('光标'), s._edit_pos), (zw('重命名'), s._rename), (zw('删除'), s._del_mould), (zw('清空'), s._del_all_mould)] #设置模块管理界面的菜单项
#今天的分析就到这里了,好吧就到这里吧,有疑问的还是请跟帖或者邮箱等
[ 本帖最后由 563255107 于 2011-4-1 17:20 编辑 ]
评分次数:1 次 财富值: +10
|