MobilePython第四章.docx
《MobilePython第四章.docx》由会员分享,可在线阅读,更多相关《MobilePython第四章.docx(36页珍藏版)》请在冰豆网上搜索。
![MobilePython第四章.docx](https://file1.bdocx.com/fileroot1/2023-4/1/b136ec7c-0371-4e72-b3ef-4c8c02a4583e/b136ec7c-0371-4e72-b3ef-4c8c02a4583e1.gif)
MobilePython第四章
第四章应用程序的构建与SMS收件箱
PyS60使你简单的在S60平台上访问用户接构建口框架。
感谢PyS60提供如此简单的处理方法,使得你可以学习怎样构建一个有标题栏、菜单和一些对话框的真正的应用程序,这只需要15行左右的代码。
我们从怎样在Python中定义函数开始。
在4.2部分中我们构建了一个应用程序,它呈现了一个典型的S60应用程序的全部结构。
另外,这一部分介绍了PyS60中的一个最重要的概念,回调函数,它让你可以将任意的动作与各种事件进行绑定。
当我向你展示怎样在应用程序中添加菜单时这个概念将会很有用。
你或许已经迫不及待的想要开始做真正的应用程序了。
在4.3部分,我将介绍怎样处理字符串。
这个将在4.4部分的访问SMS收件箱时会很有用。
例如,我将构建一个功能齐全的应用程序,让你方便的搜索和排序你的SMS消息。
最后,在4.5部分,我展示了一个SMS游戏服务,让你和你的朋友用文本消息玩刽子手游戏。
4.1函数
在前面章节中你尝试的Python脚本是一行一行执行的。
每一行代码执行一个动作,并且直到动作结束,才会转到下一行执行。
对于从头到尾直接处理的任务,这是简单且健壮的方法。
但是,如果我们想要用户来决定做什么,而不是让程序用相同的顺序执行相同的操作,那么我们的代码必须按不同的方式来组织。
典型的,有图形用户界面的应用程序是一种情况,这使得用户通过UI元素的交互来执行不同的动作。
当使用S60的框架来构建用户界面时,执行进程不是按照代码一行一行来进行的。
相反,用户或许通过按、说手机键盘的指定键来启动专门的任务。
在这种情况下,你作为一名应用程序开发者的工作就是绑定指定任务到指定的按键事件上。
当用户选择一个菜单项或者退出时,你的应用程序应该执行这个事件的相关任务。
出于这个目的,你需要创造自己的函数。
在例1中(在这里作为例9再一次出现),我们有三行代码按顺序执行。
第二行触发了一个文本输入域,第三行触发了一个弹出通知框。
例9:
第一个PyS60程序
importappuifw
word=appuifw.query(u"Typeyourname","text")
appuifw.note(u"Greetingsfrom"+str(word))
我们可以定义一个函数,将那两行代码放到函数里。
这是我们在例10中所做的,函数名为askword()。
在函数内部,像以往一样执行进程是按顺序进行。
函数只是一种给定名字,用来分隔和将代码组织成小块的方法
例10:
第一个函数
importappuifw
defaskword():
word=appuifw.query(u"Typeaword","text")
appuifw.note(u"Thewordwas:
"+str(word))
任何时候我们想要执行这个任务,就是想要执行这两行代码,我们只需要调用函数askword():
askword()
askword()
在这种情况下,它两次询问一个字。
在前一个章节中,你已经一直在调用函数了。
例如:
messaging.sms_send("+358...",u"GreetingsfromPyS60")
appuifw.note(u"IloveMobileArt")
这些是较早前例子的代码,调用的是messaging模块的sms_send函数和appuifw模块的note函数。
Python语言课程:
函数
函数是将你的代码分割成具有独立功能的方法。
函数有名字和函数体,并且可以被调用。
函数具有可选的输入变量,叫做参数,同时它可以返回一个值。
这里有一个例子:
defaddvalues(x,y):
print"Valuesare",x,y
returnx+y
关键词def开始函数的定义。
关键词def后跟函数名,这里是add_values。
括号里是函数的参数,用逗号分开。
括号后是冒号。
函数头后的缩进行组成了函数体,当函数被调用时将会一行接一行的执行。
在Python中,缩进产生不同,所有确保函数体的代码行正确对齐。
函数体和if子句以及循环语句一样要遵循同样的缩进风格。
函数体或许会包含一个跟有值的return语句,它将返回给调用行。
return语句是可选的。
调用函数是函数名和其后小括号内的输入值:
z=3
newsum=addvalues(z,5)
print"Theirsumis",newsum
如果没有给定输入值,在括号中就没有任何东西。
返回值可以赋值给变量,如newsum=addvalues(z,5),或者函数调用包含了更复杂的表达式。
例如,上面例子中最后一行代码可以写作:
print"Theirsumis",addvalues(z,5)
这种情况下,你不需要new_sum变量。
正如你猜测的,例子产生如下输出:
Valueare35
Theirsumis8
Python的口号是“包含电池”。
意思是Python附带了广泛的预定义函数库,使得在完成许多复杂任务完全不费力。
4.2应用程序结构
许多S60应用程序共享同样的用户界面布局。
看看图4.1,几乎任何S60移动电话应用程序,包括PyS60解释器,你将会注意到同样的用户界面结构。
(b)
(a)
对话框
appuifw.query()
appuifw.note()
etc.
程序体appuifw.app.body
导航标签
标题appuifw.app.title
图4.1一个典型的用户界面(a)结构(b)基于该结构的截图
图4.1(a)显示了S60用户界面的结构。
对比图4.1(b)中显示的典型用户界面,其为用S60UI框架构建,可以看出图表与实际情况的对应关系。
在下面的叙述中,括号中的文本参照截图中的文本。
在屏幕的顶部,你可以看到程序的标题(Tabs)。
在标题的下方,可以看到一行导航标签(One和Two)程序体中间的大块区域可以用来放置一系列不同的UI元素(列表:
red,green,blue,brown)。
各种对话框,如弹出通知框,会出现在应用程序体,就像我们在第三章中看到的。
在底部,可以看到两个需专用键激活的项目,是手机键盘的左右软键。
如果没有对话框被激活,左软件将激活应用程序菜单(Options),右软键退出正在运行的应用程序(Exit)。
如果有对话框显示,左软键对应于接受,右软键对应于取消。
在PyS60中,你可以通过appuifw模块的app对象访问UI元素。
在4.2部分谈论了更多有关对象的内容。
更改UI元素是简单的,每一个元素(title,body,menu和exit_key_handler)是appuifw.app对象的内部变量,你可以像别的变量那样给它们赋值。
只需要记住用全名,如appuifw.app.title。
无论什么时候你改变了这些变量中的任何一个,相关的UI元素就有相应的改变。
第一个应用程序是使用appuifw模块提供的UI框架的最基本的应用程序。
它不做任何有用的事情,但是它说明了一个可工作应用程序的最小需求。
它将一直运行,直到用户选择退出应用程序,这与以前的例子恰恰相反,以前都是从头到尾执行。
图4.2显示了它正在运行。
图4.2第一个应用程序
这部分包含了两个与应用程序构建相关的语言课程,分别是回调函数和对象。
如果你一次掌握不了也不用担心。
随着后面越来越多的例子,它们将会越来越清晰。
例11:
第一个应用程序
importappuifw,e32
defquit():
print"Exitkeypressed!
"
app_lock.signal()
appuifw.app.exit_key_handler=quit
appuifw.app.title=u"FirstApp!
"
appuifw.note(u"Applicationisnowrunning")
app_lock=e32.Ao_lock()
app_lock.wait()
print"Applicationexits"
在导入常见的appuifw模块的旁边,我们也需要一个叫e32的模块。
这个模块提供了许多有用的低级对象和塞班OS相关功能的函数。
这里我们需要对象e32.Ao_lock()。
我定义了一个新函数quit(),当用户按下退出键时,它用来处理应用程序的关闭事件。
当我们有许多函数来完成各种任务的时候,我们需要告诉Python那个函数专门用来处理退出事件。
这是通过将函数名赋值给特定变量appuifw.app.exit_key_handler来实现的。
当用户按下退出键,该变量指向的函数将会被UI框架调用。
在许多情况下,当一些事件发生时,Python期望你提供相关函数的函数名以供调用。
这种函数就叫做回调函数。
关于回调函数的语言课程将会讲清楚这个概念。
Python语言课程:
回调函数
回调函数就是一个普通的函数,和别的函数定义类似,但是它被用于特殊的目的。
在回调函数和普通函数间没有什么技术上的不同。
典型的,回调函数被PyS60的关联到特定事件的函数调用,例如当用户选择一个菜单项或决定退出应用程序。
相对而言,原始的函数被你的应用程序代码调用是用来处理应用程序的特定任务。
但是,有些情况下,回调函数有可能被你的应用程序直接调用。
将一个函数和一个事件缔合叫做绑定。
一些PyS60对象如Canvas和Inbox,都包含一个函数bind(),用来将一个函数绑定到相关对象的一些事件。
无论什么时候,当PyS60API文档或本书让你提供一个回调函数,都不要再函数名后加上小括号,因为回调函数只在事件发生后被调用。
如果你对C或C++比较熟悉的话,你或许注意到在这些语言中和函数指针的传递类似。
在例11中,我们将应用程序名赋给标题变量appuifw.app.title。
当程序运行时该字符串显示在屏幕的顶部。
像本章开头谈论的那样,目前为止我们看到的PyS60程序是一行接一行执行的,当最后一行执行完后程序退出。
但是,例11不会退出直到用户决定这么做。
因此我们的应用程序在执行完最后一行后不应该退出,应该等待用户的动作。
这可以用模块e32中的一个叫做Ao_lock对象来实现。
该对象包含一个wait()函数,使得应用程序进入等待状态直到函数signal()明确的释放了这个锁。
函数signal()必须在你想要终止应用程序的时候调用,所以我们在函数quit内部调用它。
要看看为什么在应用程序代码的底部建立一个锁很重要,从你的代码中省略app_lock.wait(),运行应用程序。
一个对话框弹出来了,但是应用程序没有进入等待状态,它立即就结束了。
当你运行例11时,你将会在屏幕的顶部看到“FirstApp!
”标题(见图4.2),和一个弹出对话框。
直到你按下退出键(右软键)退出程序外什么都不会发生。
之后,你将在PyS60控制台看到文本“Exitkeypressed!
”和“Applicationexits”。
很难注意到应用程序正在运行。
这是因为PyS60解释器是用同样的应用程序框架构建的,所以它看起来和任何别的PyS60应用程序一样。
Python语言课程:
对象
对象将变量和函数组织起来进行操作。
在许多情况下,函数和变量彼此之间相互关联,如果它们被分开处理显得很没有意义。
对象在大型的复杂的应用程序中相当有用,如果大型应用程序没有被分成小的单元在实际中很难理解。
Python已经为你做了许多这样的工作,所以你可以用Python已经准备好的对象愉快的编码。
用面向对象的方法开发大型的复杂的应用程序已经超出了本书的范围。
在别的书籍和网络上有许多关于面向对象的编程信息。
你会惊奇的发现用Python编写的用来教授面向对象编程的例子一点也不复杂,并且不要求你继承自己的对象。
我们的目的只是让你知道一些函数可以创建对象。
例11中,一个Ao_lock对象被赋值给变量app_lock。
applock=e32.Aolock()
对象自己包含的变量和函数可以用点操作符进行访问,如:
app_lock.wait()
调用该对象的wait()函数。
同样:
appuifw.app.title=u”Helloworld”
给appuifw模块的app对象的title变量赋值。
实际上,你可以将对象看做它们模块的内部模块,是点操作符的延伸。
本章中,你能够发现有许多使用对象的例子。
你已经见过处理标准用户接口的app
对象,以及用来等待用户操作的Ao_lock对象。
实际上,Python中的所有东西都是对象,包括strings、lists和tuples,也包括更多专用结构如Inbox对象,其用来访问SMS消息。
在Python中对象无所不在,你一直在使用它们甚至都没注意到。
4.2.1应用程序菜单
应用程序菜单提供了简单亲切的方式给用户程序了一个可操作的列表。
阅读本部分后,你能够用应用程序菜单构建有用的工具,用来响应用户的请求。
Python语言课程:
元组
元组是一个不可变列表。
在创建之后你不能添加、删除或更改它的值。
元组通常用来组织有关系的值,如坐标、地址线或者配方的组成部分。
元组的定义方式与列表一样,但是取代方括号,值用小括号括起来:
red=(255,0,0)
weekdays=("Mon","Tue","Wed","Thu","Fri","Sat","Sun")
family=(("Mary",38),("John",35),("Josephine",12))
第一行和第二行定义了简单的序列。
最后一行是一个元组的元组。
元组的内部包含了不同类型的值:
字符串和整型。
你可以很容易的将元组的值分拆成单独的值。
这里我们用上面创建的元组red和family:
r,g,b=red
mom,dad,child=family
这种情况下,变量r、g和b是整型,而mom、dad和child是两项目元组。
注意在拆分时你不得不定义和相关元组项目一样多的变量。
你可以像列表一样用索引来引用元组中单独的项目。
相比于列表,如下的赋值操作
family[1]=(“Jack”,25)
是不可能的,因为这将改变元组。
在一些情况下,你需要将列表转成元组或将元组转成列表。
前者用函数tuple()实现,后者用list()。
例如:
printlist(red)
在你的屏幕上产生如下输出:
[255,0,0]
注意方括号表示是一个列表。
例12对例11进行了扩展,它包含一个应用程序菜单(见图4.3)。
图4.3应用程序菜单
例12:
应用程序菜单
importappuifw,e32
defphoto():
appuifw.note(u"Cheese!
")
defdarken():
appuifw.note(u"Ican'tseeathing!
")
deflighten():
appuifw.note(u"Myeyesareburning!
")
defquit():
print"WANNABEPHOTOEDITOREXITS"
app_lock.signal()
appuifw.app.exit_key_handler=quit
appuifw.app.title=u"PhotoEditor"
appuifw.app.menu=[(u"TakePhoto",photo),(u"Editphoto",
((u"Darken",darken),(u"Lighten",lighten)))]
print"WANNABEPHOTOEDITORSTARTED"
app_lock=e32.Ao_lock()
app_lock.wait()
应用程序菜单appuifw.app.menu被定义成一个由元组组成的列表。
列表中的每一项都有格式(u”Itemname”,item_handler),第一个元素定义在应用程序菜单中显示的文本,第二个是当项目被选中时调用的回调函数。
对比图4.3和appuifw.app.menu列表将会更加的简单。
菜单可能有等级,意思是一个菜单项可能会包含一个子菜单。
子菜单的定义与主菜单的元组的列表类似。
例12中,第二个菜单项“Editphoto”打开了一个两项目的子菜单“Darken”和“Lighten”。
在图4.3中,“TakePhoto”和“EditPhoto”作为主菜单显示,“Darken”和“Lighten”作为“Editphoto”的子菜单显示。
三个函数photo()、darken()和lighten(),是绑定到菜单项的回调函数。
本例中,每一个被选中的项目打开一个弹出通知框。
和以前一样,你可以用右软键关闭应用程序。
现在你应该尝试构建菜单和简单的应用程序!
实际上构建应用程序是简单的事。
4.2.2应用程序体
有几个对象可以赋值给应用程序体:
●canvas用来处理屏幕上的图形(参见第五章)
●form用来构建复杂的组合了各种输入域如文本、数字和列表的结构(参见第九章)
●listbox用来显示列表项(参见第九章)
●text对象用来处理自由格式的文本输入(关于该对象的更多信息参见PyS60文档)
你可以用appuifw.app.screen变量增加应用程序预留的区域。
有三个不同尺寸可以用(见图4.4):
appuifw.app.screen="full"
appuifw.app.screen="large"
appuifw.app.screen="normal"
(c)
(b)
(a)
图4.4应用程序屏幕尺寸:
(a)全屏,(b)大屏,(c)一般
4.2.3标签页
在PyS60文档中,你可以找到函数appuifw.app.set_tabs()的描述,它是用来定义导航栏标签页的。
标签页是用字符串和回调函数定义的,与应用程序菜单类似。
4.2.4内容处理器
专用对象Content_handler,是appuifw模块的一部分,可用来打开各种类型的文件,如图像、照片和web页面,使用标准S60平台浏览器应用程序。
第九章将使用该对象。
4.3字符串处理
只有很少的应用程序一点也不处理文本数据。
有些情况下,你对这样的文本不感兴趣,但是你需要将文本转换成其他格式如列表或者整型,用程序处理将会很简单。
最终,当你的应用程序已经处理完数据并想要以文本格式打印输出时,应用程序必须将内部数据结构转换回文本。
幸运的是在Python中这个是简单明了的。
本部分中我将介绍字符串的基本操作,本书中许多例子都将用到。
4.4部分介绍SMS收件箱时,需要一些处理字符串的功能强大的工具。
在Python中字符串也是对象。
实际上这意味着所有的字符串相关的函数将自动可用而不用任何的导入操作,但是你需要记住在调用字符串函数时要使用点操作符,例如txt.find(“is”)。
记住在创建一个字符串后是不可能更改它的。
所有的字符串操作将返回一个新的字符串,而原来的字符串不受影响。
4.3.1定义字符串
有许多方法定义新的字符串:
txt="EpisodeXXXIV"
txt='Bartsaid:
"Eatmyshorts"'
txt="""Homer'sfaceturnedred.Hereplied:
"Whyyoulittle!
""""
第一行用双引号括起来一个字符串。
这是定义字符串最经常用的方法。
第二行用单引号。
如果你的字符串中包含有双引号,它迟早会用到。
最后一行是最后一招,如果字符串既包含双引号又包含单引号以及断行,你可以使用三对双引号将其括起来。
4.3.2访问字符串的一部分
你可以用方括号括起来的索引访问单独的字符,这和列表类似。
如果你想要找出指定子串的起始索引,用find()函数。
例如,下面的代码中第一行输出“h”,第二行输出“i”:
txt="pythonisgreat"
printtxt[3]
printtxt[txt.find("is")]
上面txt.find(“is”)返回值为7,并且索引7所在字符为“i”。
你可以用[start:
end]符号访问子串:
txt="pythonisgreat"
printtxt[:
6]
printtxt[7:
9]
printtxt[10:
]
以上打印语句输出子串为“python”,“is”和“great”。
4.3.3使用字符串做选择
你经常需要使用字符串来做选择。
你可以测试一个字符串是否非空,例如:
txt=""
iftxt:
print"Manycharacters!
"
else:
print"Nocharacters"
这个例子打印输出“Nocharacters”。
你可以用函数len()获得字符串的长度。
下面的例子输出“passwordtooshort”。
Passwd=”secret”
Iflen(passwd)<8:
print“passwordtooshort”
如果你想要知道一个字符串是否包含一个指定子串,可以用find()函数。
如果如法找到子串则返回-1。
url=""
ifurl.find(".com")==-1:
print"Accessdenied!
"
如果子串应该出现在字符串的开头,用startswith()函数:
ifurl.startswith("http:
//"):
print"ThisisavalidURL"
4.3.4输入处理
你经常需要格式化用户的输入,以便于所有的输入是大写或小写。
函数upper()和lower()可完成这项工作:
a="PyTHon"
printa.upper()
printa.lower()
打印语句输出“PYTHON”和“python”。
如果你需要确保字符串不包括前导和后缀空格,用strip()函数。
下面的代码输出字符串“fancymessage”:
a="fancymessage"
printa.strip()
这实际上是最常用到的字符串操作,本书中它用在12个例子中。
当你从一个文件或者从网络连接中获取数据它尤其有用。
你可以用replace()替换一个字符串中的子串。
下面的例子输出“Pythonisthefuture”:
a="Javaisthefuture"
printa.replace("Java","Python")
你也可以替换字符串中的单个字符,这个对于从一个web服务中清除输入、对话很有用。
下面的例子删除了字符串中的所有空格并且输出“1,2,3,4,5,6”。
a="1,2,3,4,5,6"
printa.replace("","")
如果你需要将一个字符串切分成一个子串列表,用split()函数。
默认情况下,split()在字符串的每一个空格处切分。
如果给定split()一个字符串参数,将会用该参数作为定界符。
下面的例子打印输出列表[“one”,”two”,”three”,”four”]。
txt="one:
two:
three:
four"
printtxt.split(":
")
4.3.5格式化输出
Python字符串处理的真正主