563255107
排长

UID 9780224
精华
0
积分 291
帖子 291
威望 0 点
财富值 370 塞班币
贡献值 0 点
好评度 0 点
交易信用 0 点
原创小红花 0 朵
人气值 0 点
阅读权限 10
注册 2009-5-23 手机型号
状态 离线
|
|
|
------教程-----iPro7中关于文件管理器2的源代码分析
大家好,我是小马,上一节我分析了iPro7中关于数据库的源代码分析今天来讲解iPro7的文件管理器2的源代码分析,代码很长很长还希望想学习的可以认真看完,写的很清楚,如果还有哪里不懂的可以联系我,跟帖,内信或者邮箱 563255107@qq.com====================================好了教程开始==============================================
class File_Manager2(object, ) :
__module__ = __name__
def prepare(s):#调用文件管理器时用到的准备,比如说快捷方式的设定,这个与一个类里面的__init__初始化类似
try :#异常处理,防止程序出错,先尝试执行下面的语句块,如果遇到意外不能执行,则执行except里的语句块
from keycapture import KeyCapturer as KeyCapturer#引入keycapture模块为下面的快捷键做铺垫
s.select_capture = KeyCapturer(lambda p, : s.select() )#创建KeyCapture对象,这里的lambda p, : s.select() 是创建了一个匿名对象
s.backward_capture = KeyCapturer(lambda p, : s.backward() )
s.next_page_capture = KeyCapturer(lambda p, : s.next_page() )
s.last_page_capture = KeyCapturer(lambda p, : s.last_page() )
try :
from key_codes import EKeyRightArrow as EKeyRightArrow#引入key)codes模块,方便我们定义快捷方式
from key_codes import EKeyLeftArrow as EKeyLeftArrow
from key_codes import EKeyStar as EKeyStar
from key_codes import EKeyHash as EKeyHash
except :
EKeyRightArrow, EKeyLeftArrow, EKeyStar, EKeyHash = (63496, 63495, 42, 35)#这里依次对应导航键的左键,右键,*键,#键
s.select_capture.keys = (EKeyRightArrow, )#定义相应函数要捕获的按键,这里定义导航右键为选择键
s.backward_capture.keys = (EKeyLeftArrow, )
s.next_page_capture.keys = (EKeyHash, )#这里定义#键为向下翻一页
s.last_page_capture.keys = (EKeyStar, )#这里定义*键为向上翻一页
s.capture_tuple = (s.select_capture, s.backward_capture, s.next_page_capture, s.last_page_capture)#把所有要捕获的按键集中起来方便捕获
except :
pass#这里的pass的意思是什么也不做
s.PM = ui.popup_menu#你可以暂时把这里的ui理解为appuifw
def start_capture(s):#开始按键捕获
try :#异常处理跟上面的一样
map(lambda x, : x.start() , s.capture_tuple)#map函数,把上面我们定义的要捕获的按键元祖依次代入start函数进行执行
except :
pass
def stop_capture(s):#停止按键捕获
try :
map(lambda x, : x.stop() , s.capture_tuple)#跟上面的开始捕获一样的,不多解释
except :
pass
def return_ui(s):
pass
def select(s):#定义选择文件
if s.list == [] : #如果得到的列表为空则直接返回
return None
else : #如果列表不为空的话
try :
import keypress
try :
from key_codes import EKeySelect as EKeySelect#从key_codes模块导入EKeySelect 注:导航中间的确定键
except :
EKeySelect = 63557
s.direction = 0 #这里的s.direction 参数是为了表明是在当前目录下,如果为-1 则表示后退返回上一级目录,如果为1 则表示前进到下一级目录
keypress.simulate_key(EKeySelect, EKeySelect)#调用keypress模块里的simulate_key函数,模拟按确定键
except :
pass
pass
def backward(s):#定义返回上一级
if s.list == s.disks : #这里是为了排除隐患,如果一直返回的话会返回到跟目录(注:c:,d:,e:,z ,如果到根目录还返回的话会出错的,这里定义到了根目录直接退出这个函数
return None
else : #如果没到根目录,接着返回上一级
try :
import keypress
try :
from key_codes import EKeySelect as EKeySelect
except :
EKeySelect = 63557
s.direction = -1 #注意到这里没,这里就是我前面提到的返回上一级目录的标识
keypress.simulate_key(EKeySelect, EKeySelect)
except :
pass
pass
def next_page(s):#定义向下翻页
try :
import keypress
try :
from key_codes import EKeyDownArrow as EKeyDownArrow
except :
EKeyDownArrow = 63498
map(lambda x, : keypress.simulate_key(EKeyDownArrow, EKeyDownArrow) , range(6))#map函数,具体这里的range(6) ,我不清楚为何这样使用,不过这里的作用是使光标向下连续移动6下
except :
pass
def last_page(s):#定义向上翻页
try :
import keypress
try :
from key_codes import EKeyUpArrow as EKeyUpArrow
except :
EKeyUpArrow = 63498
map(lambda x, : keypress.simulate_key(EKeyUpArrow, EKeyUpArrow) , range(6))#这里跟上面的向下翻页是一样的
except :
pass
def focus(s, fg):#定义转到后台时执行的动作
if s.path != '历史文件\' : #如果路径不为历史文件这个路径的话
if fg : #如果程序在前台运行,执行快捷键的准备,并开始捕获
s.prepare()
s.start_capture()
else : #如果程序转到后台了停止按键捕获
s.stop_capture()
pass
elif fg : #如果路径是历史文件,并且程序在前台运行,因为我们定义了历史管理,所以这里我们就停止按键捕获
s.prepare()
s.stop_capture()
def history_manager(s):#历史管理
history_list = [h for h in history.list if os.path.isfile(en(h)) ]#这里的history.list是历史文件里的文件路径,这里用到了列表里的一个技巧,首先去history.list里的一个文件,判断是否是一个文件,如果是就把它加入到history_list里面,如果不是就接着判断下一个
list = [(u'%s(%s)' % (os.path.basename(i), os.path.dirname(i))) for i in history_list]#这里的%s代表一个字符串,与后面的元素一一相对应,分别为文件的名字和文件的路径名
if history_list == [] : #如果得到的历史列表为空,提示用户无历史记录,然后返回
ui.note(zw('无历史记录'))
return None
ask = ui.popup_menu(list, zw('历史文件'))#如果记录不为空,弹出菜单请用户选择一个历史记录
if ask is None : #如果用户选择取消,直接返回
return None
else : #如果用户选择了一个历史记录,返回选择的文件的路径
return history_list[ask]
def AskDir(s, path = '', title = '选择目录'.decode('u8'), disks = e32.drive_list(), dirs = [], auto_return_ui = False, body_process = False):#目录浏览
s.prepare()#准备快捷键处理
s.title = title
s.disks = [en(i) for i in disks]#这里也等于["C:","D:","E:","Z:"]
s.disks.extend([i[0].upper() + i[1 : ] for i in dirs])#这里的i[0].upper()处理是为了把某个文件的路径的第一个字母,比如c,e等等转换成大写字母,至于为什么呢,因为用e32.drive_list()得到的都是大写字母,不知道大家发现没有,这里转换成大写是为了避免出错
s.path = path
if len(s.path) > 0 : #如果参数path不为空,且不是以"\"结尾的,就在路径后面加上一个"\"
if not (s.path.endswith('\\')) :
s.path += '\\'
s.path = path[0].upper() + path[1 : ]#这里的处理同样是为了把第一个字母转换成大写的,
if not (os.path.isdir(s.path)) : #如果提供的参数path不是一个存在的路径那么直接把path置为空
s.path = ''
s.direction = 1#工作方式设置为1,表示前进,进入下一级
s.old_focus = ui.app.focus#保存程序原来的焦点(也就是程序在前台还是后台)
ui.app.focus = s.focus#调用focus函数
s.start_capture()#开始按键捕获
while True : #这里是核心,比较重要,要好好分析才能理解
① if s.path == '' : #如果提供的参数path为空,则把列表设置为根目录,让用户选择
s.find = s.disks
s.list = [zw(i) for i in s.disks]
s.choose = s.PM(s.list, s.title)
③ else : #如果提供的参数path不为空
try :
s.find = [i for i in os.listdir(s.path) if os.path.isdir(s.path + i) ]#把path路径下的文件夹加入到s.find列表中
except OSError :
s.find = []
s.list = [(u'[%s]' % zw(i)) for i in s.find]#转换成中文,并以"[文件夹路径]"这样的形式显示
s.list.insert(0, (zw('/%s/') % zw(s.path.split('\\')[-2])))#在显示的列表的第一行插入上一级的路径的名字,例如提供的path为"e:\\system\\iPro7",经过上面的处理后path变为"e:\\system\\iPro7\\",加入我们现在进入到了iPro7这个文件夹下,那么第一行会显示/iPro7/,然后下面的才是iPro7下的文件夹
s.choose = s.PM(s.list, s.title)#弹出可供选择的路径,供用户选择
④ if s.choose is not None : #如果用户选择了,把s.choose的值减1
s.choose -= 1
pass
if s.choose is None : #如果用户没有选择,判断提供的参数path是否为空,不为空则表示返回上一级,如果path为空,则停止按键捕获,并且返回
if not (s.path == '') :
s.direction = -1
else :
s.stop_capture()
ui.app.focus = s.old_focus
return None
pass
⑤ if s.choose == -1 and s.direction != -1 : #如果用户选择了第一个(注:上一级路径),且s.direction标识不是-1(注:返回上一级路径),停止按键捕获,返回选择的路径(注:这里先判断s.direction != -1是判断用户是否选择了返回上一级,否则容易乱的)
s.stop_capture()
ui.app.focus = s.old_focus
return s.path
② elif s.direction == 1 : #如果s.direction标识为1(注:表示进入到下一级目录),则更新现在的path路径值为用户当前选择的路径,注意这里并没有退出while循环,如果path不以"\"结尾,在path路径末尾加上"\"
s.path += s.find[s.choose]
if not (s.path.endswith('\\')) :
s.path += '\\'
pass
elif s.direction == 0 : #如果用户不是选择第一个且s.direction标识为0(注:表示选择当前目录),则更新现在的path路径值为用户当前选择的路径,现在已经完成了任务,退出while循环并返回用户选择的路径,如果path不以"\"结尾,在path路径末尾加上"\"
s.path += s.find[s.choose]
if not (s.path.endswith('\\')) :
s.path += '\\'
s.stop_capture() #停止按键捕获
ui.app.focus = s.old_focus
return s.path #退出while循环
elif s.direction == -1 : #如果s.direction 的标识为-1(注:返回上一级目录)
if s.path[ : -1] in s.disks : #如果已经返回到根目录了把s.path的值置为空,这里要注意为何是s.path[:-1]呢,因为现在的根目录已经变成["C:\","D:\","E:\","Z:\"]其中的一个,这里使用-1 表示不包括"\"正好达到我们的要求
s.path = ''
else : #这里是处理返回上一级目录的核心代码,注意了!
for i in range((len(s.path) - 2), -1, -1): #注意这里是为了得到s.path的长度-2的值且倒数输出,(这里不太好理解,我举个例子:for i in range(5,-1,-1):print i, 将会输入5,4,3,2,1,0 ) 你会又疑惑了为什么要减2呢,(我再举个例子:s.path="e:\system\iPro7\" 减2之后就把s.path里面的最后的那个"\"屏蔽掉了,注意现在s.path[0]是e ,从零开始计数的,所以我们要减2)
if s.path == '\\' : #这里一直在for中循环,直到找到倒数第二个"\"标志为止,好了现在我们已经得到上一级的目录了,厉害吧
s.path = s.path[ : (i + 1)] #这里把s.path[ : (i + 1)] 是为了让s.path中最后保留下"\"符号
break
pass
pass
s.direction = 1 #设置默认的工作方式为1,(进入到下一级目录)
#哇 ,好长啊,有点看不懂了都,没关系慢慢来多看几遍就理解了,下面我会举几个例子来让你好好理解下程序是如何执行这段代码的:假如我们为path提供的参数为空,首先呈现给我们的应该是根目录这里执行①,然后我们选择E盘这里执行到②了,因为我们默认的工作方式就是s.direction = 1,然后执行③因为现在的path已经不是空了而是我们选择的"E:\"了,然后我们选择第一个,并摁导航中间的确定键,或者导航右键则执行到④,紧接着会执行⑤,至此退出while循环,其他的运行方式跟这个很类似了我就不多举例了(具体测试方法可以在iPor7中把浏览器设置为浏览器2,然后再工作目录中,选择添加目录进行测试)
def AskFile(s, path = '', title = '选择文件'.decode('u8'), disks = e32.drive_list(), ext = [], dirs = [], auto_return_ui = False, body_process = False, history_read_only = False, multi = False, able_history = True):#文件浏览,跟目录浏览基本差不多
s.prepare()#仍然是快捷键的准备
s.title = title
s.disks = [en(i) for i in disks]
s.disks.extend([i[0].upper() + i[1 : ] for i in dirs])
if able_history : #是否显示历史文件目录,默认显示历史文件
s.disks.insert(0, '历史文件')#在显示的根目录下插入"历史文件"这一项
s.path = path
if s.path != '历史文件\\' : #判断提供的path参数如果不是"历史文件\\"这个路径,进一步判断path的长度,如果不为空且不是以"\\"结尾的,在path结尾添加"\\"
if len(s.path) > 0 :
if not (s.path.endswith('\\')) :
s.path += '\\'
s.path = path[0].upper() + path[1 : ] #把路径的第一个字母转换成大写字母
if not (os.path.isdir(s.path)) : #判断所给路径是否是真是路径,如果不是把path的值置为空
s.path = ''
pass
s.ext = [x.lower() for x in ext] #把提供的后缀转换成小写字母
s.direction = 1 #设置默认工作方式为进入下一级目录
s.old_focus = ui.app.focus #取得程序原来的焦点
ui.app.focus = s.focus #当程序焦点变化时调用focus函数
s.start_capture()
e32.ao_sleep(0.1) #暂停0.1秒的时间
while True : #这里有是核心代码了,注意了一直循环直到用户选择文件或者取消选择
if s.path == '' : #如果提供的path为空把s.find置为根目录
s.find = s.find_dir = s.disks
s.find_file = [] #创建一个空列表来存储查找到的文件
s.list = [zw(i) for i in s.find_dir] #把列表设置为根目录
elif s.path == '历史文件\\' : #如果提供的path为"历史文件"则停止按键捕获,调用前面我们提供的history_manager函数来处理
s.stop_capture()
ask_history = s.history_manager()#从历史记录中打开想找的文件
if ask_history is None : #如果用户选择了取消,把path路径置为空,并开始按键捕获,重头开始选择文件(相当于退出了历史文件管理)
s.path = ''
s.start_capture()
continue #后面的语句块都不会执行,直接从while开始重新执行,并选择文件
else : #如果选择了文件,还原程序原来的焦点退出while循环,返回选择的文件的路径
ui.app.focus = s.old_focus
return [en(ask_history)]
pass
else : #如果提供的path不为空也不是"历史文件\\"
try :
s._find = os.listdir(s.path) #使用s._find来存储s.path路径下的文件夹和文件
except OSError : #如果出现异常,则把s.find置为空列表
s._find = []
s.find_dir = [i for i in s._find if os.path.isdir(s.path + i) ] #把s.find列表里的文件夹分离出来保存到s.find_dir里
if len(s.ext) > 0 : #如果存在后缀限制,把s._find里符合后缀限制的的文件分离出来
s.find_file = [i for i in s._find if os.path.isfile(s.path + i) and os.path.splitext(i)[-1].lower() in s.ext ]
else : #如果没有后缀限制,把所有的文件分离出来
s.find_file = [i for i in s._find if os.path.isfile(s.path + i) ]
s.find = s.find_dir + s.find_file #把两个列表组合,得到所有的文件夹和文件
s.list = [(u'[%s]' % zw(i)) for i in s.find_dir] #把文件夹以"[文件夹名字]"的形式添加到s.list列表中
s.list.extend([zw(i) for i in s.find_file]) #把文件以名字的形式添加到s.list列表中,这就是为什么前面我们把文件夹和文件分开
if s.list == [] : #如果得到的列表为空,比如说我们找到某个空目录之后等等情况,使用全局提示用户无内容
import globalui
s.stop_capture()
globalui.global_msg_query(zw('无内容'), s.title)
s.start_capture()
s.choose = None #没有内容当然就没有选择了,把它置为None下面我们判断会用到的
s.direction = -1 #设置工作方式为返回上一级,这个目录都没有我们想要的文件了当然得返回了,哈哈
else : #如果列表不为空,显示供选择的列表,让用户选择
s.choose = s.PM(s.list, s.title)
if s.choose is None : #如果用户选择取消或这目录为空(上面我提到过的)
if s.path != '' : #判断路径是否为空,不为空设置工作方式为返回上一级
s.direction = -1
else : #如果路径为空的话(这种可能应该是用户已经回到了根目录仍然选择返回,也就是返回程序主界面,编辑界面)停止按键捕获并返回一个空列表
s.stop_capture()
ui.app.focus = s.old_focus
return []
pass
if s.direction == 0 or s.direction == 1 : #根据上面我们得到的工作方式来执行相应的动作,如果工作方式为0 或者1
s.path += s.find[s.choose] #更新s.path为选择一个文件或这路径之后的路径
if s.find[s.choose] in s.find_file : #如果选择了一个文件则停止捕获并返回选择的文件的路径,例如选择了"e:\\data\\iPro7\\text.py"则返回"e:\\data\\iPro7\\text.py"
s.stop_capture()
ui.app.focus = s.old_focus
return [s.path]
else : #如果选择的是一个文件夹,判断当前的s.path 是否以"\\"结尾,如果不是就添加,并设置工作方式为进入下一级目录,继续while循环
if not (s.path.endswith('\\')) :
s.path += '\\'
s.direction = 1
continue
pass
elif s.direction == -1 : #这里就是我们处理前面我们设置的工作方式了
if s.path[ : -1] in s.disks : #如果返回到了根目录,把s。path的值置为空
s.path = ''
else : #如果没到根目录,
for i in range((len(s.path) - 2), -1, -1):#注意这里是为了得到s.path的长度-2的值且倒数输出,(这里不太好理解,我举个例子:for i in range(5,-1,-1):print i, 将会输入5,4,3,2,1,0 ) 你会又疑惑了为什么要减2呢,(我再举个例子:s.path="e:\system\iPro7\" 减2之后就把s.path里面的最后的那个"\"屏蔽掉了,注意现在s.path[0]是e ,从零开始计数的,所以我们要减2)
if s.path == '\\' : #这里一直在for中循环,直到找到倒数第二个"\"标志为止,好了现在我们已经得到上一级的目录了,厉害吧
s.path = s.path[ : (i + 1)] #这里把s.path[ : (i + 1)] 是为了让s.path中最后保留下"\"符号
break #跳出while循环
pass
s.direction = 1 #设置默认的工作方式是进入下一级目录
#真不容易啊,这个文件管理器终于分析完了,还是老规矩哪里不懂的可以联系我,或者跟帖提问我会尽量回答的
后面我会相继分析模块管理,等等
评分次数:1 次 财富值: +12
|

[fly]小马专用[/fly]
|
|
|
|
|