Palm 手持设备开发入门






4.75/5 (4投票s)
使用经典的“Hello World!”示例编写您的第一个Palm应用程序。
引言
最近在Code Project的各个论坛里有几个人在问Palm掌上设备的问题,虽然Code Project主要是一个Windows编程网站,但我认为添加一些Palm的文章也会有所裨益。所以,废话不多说,先来点东西让您尝尝鲜。
Palm开发资源
演示应用程序和源代码是使用Metrowerk的CodeWarrior for PalmOS IDE(6.0版)创建的。资源是使用Constructor for PalmOS制作的。我相信您可以从Metrowerks下载试用版。此外,您可以从Palm下载Palm模拟器,在那里也能找到大部分开发信息。
如果您想要完全免费的开发工具,Palm也有一个GNU编译器。演示应用程序不是用GNU编译器设计的,所以我不知道它是否能工作。
当您编写生产级的Palm应用程序时,您需要注册一个唯一的4位数字ID,该ID将区分您的应用程序资源和其他任何资源(有点像GUID,但没那么复杂)。
Palm应用程序术语
所有操作系统都有自己的术语,PalmOS也不例外。以下是一些在PalmOS编程中更相关的术语列表:1Window
一个矩形区域,应用程序在此区域中绘制对话框、表单和菜单等。
表单
一个覆盖整个屏幕的应用程序窗口。一个表单还可以包含控件、文本区域和菜单。一次只允许一个活动表单。
数据库
一组持久内存块。有资源数据库和记录数据库。
Resource
存储在资源数据库中的数据块。由资源类型和编号标识。
Record
由唯一记录ID标识的数据结构。应用程序数据通常存储在记录数据库中。
启动代码
传递给应用程序的参数,指定应用程序执行时应执行的操作。
警告
一个需要用户确认的警告或信息对话框。
与Microsoft Windows一样,PalmOS是一个事件驱动的操作系统。一次只能打开一个应用程序,所有应用程序都包含一个事件循环,该循环检索事件并对其做出反应。
Palm应用程序结构
每个Palm应用程序的入口点是PilotMain
函数。UInt32 PilotMain(UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags)
2
第一个参数cmd
是应用程序的启动代码。有几个可用的启动代码,但要正常启动应用程序,请使用常量sysAppLaunchCmdNormalLaunch
。
第二个参数cmdPBP
是指向包含任何启动命令特定参数的结构的指针,如果没有启动代码,则为NULL。MemPtr
本质上是一个void *。
最后一个参数launchFlags
指示应用程序的全局变量是否可用,您的应用程序是否是当前活动应用程序,它是否已经是活动应用程序,等等。
/* Here is an example PilotMain */ UInt32 PilotMain( UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags) { switch (cmd) { case sysAppLaunchCmdNormalLaunch: AppEventLoop(); FrmCloseAllForms(); break; default: break; } return 0; }
PiltoMain
函数调用主事件循环函数。在此函数中,我们不断地处理我们的应用程序和系统的事件(请参阅图1以获取说明)。我们首先使用EvtGetEvent
函数获取事件,然后将该事件分派给4个事件处理程序。如果事件处理程序返回true,则事件已被处理,将不再进一步处理。如果未处理,它将被发送给每个后续的处理器进行处理。循环继续,直到收到appStopEvent
。/* Here is an example main event loop */ static void AppEventLoop(void) { UInt16 error; EventType event; do { EvtGetEvent(&event, evtWaitForever); if (! SysHandleEvent(&event)) if (! MenuHandleEvent(0, &event, &error)) if (! ApplicationHandleEvent(&event)) FrmDispatchEvent(&event); } while (event.eType != appStopEvent); }
SysHandleEvent
和MenuHandleEvent
分别处理Palm系统事件和菜单事件,而ApplicationHandleEvent
和FrmDispatchEvent
是Palm应用程序中大部分实际操作的发生地。ApplicationHandleEvent
函数是您使用void FrmSetEventHandler (FormType *formP, FormEventHandlerType *handler)
为所有表单设置事件处理程序的地方。表单事件处理程序例程的形式是:Boolean FormEventHandlerType (EventType *eventP)
。您基本上是将一个回调函数设置为事件处理程序(就像Windows的WindowProcedure一样)。// the app event handler static Boolean AppHandleEvent(EventPtr eventP) { UInt16 formId; FormPtr frmP; Boolean bRetVal = false; if (eventP->eType == frmLoadEvent) // is a form loading? { // Load the form resource. formId = eventP->data.frmLoad.formID; frmP = FrmInitForm(formId); // load a form resource FrmSetActiveForm(frmP); // make this the active form // Set the event handler for the form. The handler of the currently // active form is called by FrmHandleEvent each time is receives an // event. switch (formId) { case MainForm: FrmSetEventHandler(frmP, MainFormHandleEvent); break; default: break; } bRetVal = true; } return bRetVal; }
FrmDispatchEvent
例程提供间接的表单特定事件处理。为了提供这一点,FrmDispatchEvent
调用表单的事件处理程序(上面示例中的MainFormHandleEvent)。
“Hello World!”示例
作为编写第一个Palm应用程序的示例,我将使用永不令人厌倦的“Hello World!”示例。我将打开一个带有按钮的表单,当按下该按钮时,会在屏幕中央显示“Hello World!”。
演示源代码的PilotMain
和主事件循环几乎与我们在“Palm应用程序结构”部分涵盖的内容相同,唯一的例外是FrmGotoForm
函数调用。void FrmGotoForm (UInt16 formId)
会向当前活动表单发送一个关闭事件,并向由fromId
指定的表单发送加载和打开事件。应用程序事件处理程序将为给定formId
的此表单设置表单事件处理程序。所以总而言之,FrmGotoForm
关闭当前表单并打开一个新表单。
当表单上的“Say Hello”按钮被按下时,一个ctlSelectEvent
事件被发送到表单,然后该事件被传递给表单按钮处理程序例程MainFormButtonHandler
。
static Boolean MainFormButtonHandler(FormPtr formP, EventPtr eventP) { Boolean handled = false; switch (eventP->data.ctlEnter.controlID) { case MainSayHelloButton: SayHello(); handled = true; break; default: break; } return handled; }上面的switch语句会找到被选中的控件并调用我的SayHello函数(如下所示)。
static void SayHello() { short nCharWidth = 0; short width = 0, height = 0; Char* pText = (Char*) MemPtrNew(13); // allocate 13 bytes // copy Hello World! into the char ptr StrCopy(pText, "Hello World!"); // get the width of the string nCharWidth = FntCharsWidth(pText, StrLen(pText)); // get the width and height of the string WinGetWindowExtent(&width, &height); // draw the text in the center WinDrawChars(pText, StrLen(pText), (width/2) - (nCharWidth/2), height/2); // free the text memory MemPtrFree(pText); }大多数Palm代码与标准的C/C++类似,但字符串和内存函数针对该平台进行了优化。使用标准的C/C++函数可能会增加编译后可执行文件的大小,而在Palm上,大小很重要。
首先,我们使用
MemPtrNew
函数为“Hello World!”字符串分配13个字节,该函数的作用与malloc
类似。然后,我们使用Palm的
StrCopy
函数代替标准的strcpy
。FntCharsWidth
使用当前字体返回字符串的像素宽度。WinGetWindowExtent
获取Palm屏幕区域的宽度和高度。您不应再假定Palm屏幕为160x160(新的Palm Tungsten T拥有320x320的屏幕区域)。在获取屏幕大小和字符串大小后,我们最终使用
void WinDrawChars (const Char *chars, Int16 len, Coord x, Coord y)
将字符绘制到屏幕中央。然后,我们使用
MemPtrFree
释放为字符串分配的内存。打完招呼后,演示应用程序将在此等待您的输入,直到您使用Palm上的标准Home按钮关闭应用程序。
结论
我希望您觉得这篇文章易于理解且有趣。Palm平台肯定会继续存在,并且很有趣去开发,所以我鼓励您尝试一下。
如果您对更多文章感兴趣,请告诉我,它们可能会包含有关如何创建和使用Palm数据库以及Palm“Conduit”开发的信息。
另外,我没有在演示项目中包含PalmOS.h文件,因为它可以在Palm SDK中找到,而Palm SDK可以从PalmOS网站下载。
来源
1 Rhodes, McKeehan: "Palm Programming The Developer's Guide, First Edition", 67-69。2 Palm Inc., System Manager {online} 可从 http://lovecraft.die.udec.cl/prog_lang/PalmOS/SystemManager.html#941792 获取,2001年。
有用的链接
Palm OS®程序员API参考