PalmOS开发教程-3.2
再谈事件
从第二章可以了解到,Palm OS程序,类似于Mac OS程序和Windows程序,都是以事件驱动为基础的。程序不用做任何事情(大部分是这样),直到用户的输入到来,比如按下了按钮,用输入笔或手指接触了屏幕等。
当用到文本框的时候,我们关心以下四个事件。第一,penDownEvent和penUpEvent。每一次装置的屏幕被接触时会有PenDownEvent发生。同样地,每一次输入笔离开屏幕时会有P enUpEvent发生。
对Palm OS的用户来说,界面元素事件,包括文本框的事件,被转换成为对FrmDispatchEvent()函数的调用。对于文本框事件FrmDispatchEvent() 函数其实就是转化成了其它三个事件:fldEnterEvent,fldChangedEvent和keyDownEvent。只要文本框被敲击选中,就发送FldEnterEven t。只要文本框调整它的外观,例如,水平滚轴,就发送FldChangedEvent。只要手写输入特征被识别并发送到文本框中,就发送keyDownE vent。
如果你不处理事件的话,就应该在事件处理器中返回false值。这样的话,我刚才描述的极好的自动产生事件的特性就没用了。如果事件处理器中返回t rue值,FrmDispatchEvent()处理下一个事件;如果返回false值, DispatchEvent()就调用FrmHandleEvent(),FrmHandleEvent()函数实质是把多个简单事件转化成若干复杂事件来处理的函数。以处理文本框事件为例,F rmHandleEvent()函数调用FldHandleEvent()就产生了我们刚才讨论的文本框事件。除非是在非正常的环境中,我不推荐调用FrmHandleEv ent()函数或FldHandleEvent()函数。当你想进一步地处理特殊的事件时,请留意从你的事件处理器中返回的false值。
现在让我们来修改Contacts项目中的代码,调用标注了日期的刚创建的新资源。使用资源管理器,复制另一个Hello.c副本到Contacts项目的S rc文件夹中。把它重命名为Contacts.c,然后通过选中Project | Add Files命令把它重新加入到项目中。使用新的Contacts_res.h头文件来替代hello_res.h,在Contacts.c文件中包含它。做完这些后,为了使代码能成功编译并连接,你还必需将引用从H elloForm改到ContactDetailForm。到现在,虽然我们还在使用错误的资源文件,但程序已经可以工作了,因为表示HelloForm窗体的ID与表示C ontactDetailForm窗体的ID是相同的。构造器经常从1000开始赋窗体的ID值的。
其它的需要修改的内容是case语句,在程序中找到处理ctlSelectEvent事件的case语句。下面就是要找的,它表示按钮被按下的事件:
//CH.2 The botton was pressed
case ctlSelectEvent;
SndPlaySystemSound(sndAlarm);
return(false);
到现在为止,Contacts程序中的case语句还没有做完。由于窗体中并没有按钮,所以根本没有机会收到ctlSelectEvent事件。那么就让我们通过改变c ase语句来捕获penDownEvent事件吧,它会使你更有信心的。用下面的代码替换上面的case ctlSelectEvent代码:
//CH.3 The pen touched down
case penDownEvent;
SndPlaySystemSound(sndAlarm);
return(false);
选中Project | Make(在Project | Debug下)来调试已修改的代码。在调试窗口点击运行按钮运行已修改的应用程序,当你每次点击文本框时,它可能发出只有紧急事件产生时才有的警报声。事实上,无论你点击窗体的任何地方都会听到警报声,因为都有p enDownEvent事件被触发产生。你也可以试着把penDownEvent替换为penUpEvent,make,debug,然后运行程序。现在警报声就在输入笔点击后离开屏幕时发出了。
再试着把penUpEvent替换为fldEnterEvent,make,debug,并运行程序。可以发现直到输入笔碰到窗体的文本框部分时,警报声才响起。现在我们可以很容易地可以用精确事件去来替换未明了的事件了,像p enDownEvent和penUpEvent事件。这样做不但相当的简单,而且它还会给人一种用户界面的感觉,这与其它Palm OS应用程序的风格是一致的。所以,知道有关penDownEvent和penUpEvent事件很有益,但是我的建议只是在很多精确的事件不可用的情况下才使用它们。
试着把fldEnterEvent替换为fldChangedEvent。make,debug,并运行应用程序。这次如果你在文本框中输入了相当多的字符的话,文本框将出现水平滚动条,警报就会消失。
试着把fldEnterEvent替换为keyDownEvent。make,debug,并运行应用程序。现在只要在输入区域产生一个正确的字形,警报就会响起了。如果在输入板引擎还未决定你是否已经输入正确的内容前,你就已经抬起了笔,那么就可以看到一些很有趣地东西。这并不容易做到(至少对我来说)。
注意:在事件产生时播放声音通常是一个较好的方法,这样可以正确地看到在什么环境下什么时候一个特殊的事件会发生。这是一个很好的实验方法,用来帮助你采集操作系统的状态。
焦点
有50种以上的Palm OS函数,允许你以不同的方法操作文本框和你输入的数据。在下一部分,我们将处理大多数基本功能调用,你可能经常用到(至少对文本框来说,并不是直接连接数据库中的数据)。文本框功能中剪切,复制,删除,粘贴,和撤消最受欢迎,我们在用到菜单和快捷菜单时,将处理这些问题。
你需要先点击文本框来才能够向文本框中写入字符。换句话说,文本框需要先获得焦点才能够接收输入。
让我们调用FrmSetFocus()函数来满足点击文本框后获得焦点的需要吧。这个函数必须紧跟着画窗体的语句出现,因为在窗体出现前获得焦点函数是不起作用的。所以,对它来说最合适的位置应该是在P ilotMain()中的FrmDrawForm()后。为了用使用FrmSetFocus()函数,你必须首先调用FrmGetObjectIndex()函数得到目标对象索引。这样,在你m ake,debug,并且运行代码后,在你点击输入之前,就可以看到在文本框中有一个闪动的指针。你加入的新代码应该如下:
//CH.3 Initialize our form
form=FrmInitForm(ContactDetailForm);
FrmSetEventHandler(form,myHandleEvent);
FrmSetActiveForm(form);
FrmDrawForm(form);
//CH.3 Get the index of our field
index=FrmGetObjectIndex(form,ContactDetailFirstNameField);
//CH.3 Set the focus to our field
FrmSetFocus(form,index);
//CH.2 Our event loop
do
{
向文本框输入字符
现在我们该向文本框中输入一些字符了。在这样做之前,你有必要学习一点有关文本框使用Palm OS存储器方面的知识。一旦对文本框进行编辑后,就会相应的引起数据库内存被直接编辑,与文本框有关的一切操作都被对应到一块可以进行操作和自由改变大小的存储片。在P alm OS的术语中,这些存储片被叫做块(chunk)。
文本框需要用到这些特殊的数据结构来保存用户输入的数据,因为这种数据结构具有根据输入数据改变大小的特性。现在假定我们已经分配了两个块的内存给两个文本框了。每个块的初始大小是8 0个字节:
XXXXXXXXYYYYYYYY
这时就存在这样一个问题,如果需要扩大第一个文本框的容量到100个字节,但因为第二个文本框分配的块紧挨着它的下面分布,所以就没有空间可以用来扩展第一个内存块了。此时如果我们不准备放弃,不限制文本框小一些并且不改变字符总数的话,文本框中就会丢失一些内容。
为了解决这个问题,人们扩展了内存处理(memory handle)的概念。采用把指针放在内存指针列表中的方法代替了直接返回指针给每一个被分配的存储片的方法。操作系统可以利用空闲的时间来调整块的位置,这样就可以允许块的扩展了,
XXXXXXXXXXXXYYYYYYYY
当内存块正在使用的时候,我们通过锁定内存块来阻止操作系统试图移动内存块的操作。在我们还没有完成操作之前,内存块一直处于锁定的状态。
在先前的简单文本框例子中,当我们开始向文本框加入字符时,Palm OS就自动分配了一个内存块给文本框,并实现了内存块和文本框的自动绑定。如果想在程序一开始就得到一个带字符的文本框,我们就必须先给文本框分配一个内存块,向内存输入文本,并且把内存与文本框绑定。让我们在C ontacts.c中加入C代码,使我们能够在Contacts.c的开头部分分配并初始化内存块:
//CH.3 Our field memory handle
static Handle htext; //CH.3 Handle to the text in our edit field
#define HTEXT_SIZE 81 //CH.3 Size of our edit field
//CH.2 The main entry point
Dword PilotMain(Word cmd,Ptr,Word)
{
FormPtr form; //CH.2 A pointer to our form structure
CharPtr ptext; //CH.3 Points to the text in the edit field
Word index //CH.3 A general purpose index
FieldPtr field; //CH.3 Used for manipulating fields
EventType event; //CH.2 Our event structure
//CH.2 If this is not a normal launch don’t lauch
if(cmd!=sysAppLaunchCmdNormalLaunch)
return(0);
//CH.3 Allocate our field chunk
htext=MemHandleNew(HTEXT_SIZE);
if(htext= =NULL)
return(0);
//CH.3 Lock the memory,get the pointer
ptext=MemHandleLock(htext);
//CH.3 Initialize it
StrCopy(ptext,”hello”);
//CH.3 Unlock the field’s memory
MemHandleUnlock(htext);
在上面的代码中可以看到四个Palm OS的新功能。
MemHandleNew()分配一个内存块。MemHandleLock()锁定内存块,防止Palm OS移动存储器。StrCopy()就像C语言函数strcpy(),它从存储器的一个地方复制一个零界限字符串到另一个地方——这样,就可以复制一个常量的值到我们的内存块了。M emHandleUnlock()告诉操作系统,我们已经解锁了一个内存块。这条语句后,任何对ptext指针的调用都会变得危险,因为内存块在任何时候都可能被移动的。
若发生Palm设备内存溢出这样的悲惨事件的话,MemHandleNew()将返回NULL。以上的代码可以使应用程序安静的退出,但是这还远不是一种理想的解决方案。在下一章中你将会学到如何发送带有警告的错误信息给你的用户。
剩下要做的就是把我们的内存块丢给文本框了。可以在画窗体前做以下这些工作:
//CH.3 Initialize our form
form=FrmInitForm(ContactDetailForm);
FrmSetEventHandler(form,myHandleEvent);
FrmSetActiveForm(form);
//CH.3 Get the index of our field
index=FrmGetObjectIndex(form,ContactDetailFirstNameField);
//CH.3 Get the pointer to our field
field=FrmGetObjectPtr(form,index);
//CH.3 Set the editable text
FldSetTextHandle(field,htext);
//CH.2 Draw the form
FrmDrawForm(form);
这里稍有一些技巧的函数是FldSetTextHandle()。为了调用这个函数,你必须有一个指针指向文本框。你可以调用FrmGetObjectPtr()来取得这个指针。可以看到F ldSetTextHandle()必须在FrmGetObjectPtr()前被调用,否则你输入到内存块的文本就不能与窗体部分一起画上。调用后面的FldDrawFie ld()来画出整个窗体。
你把经过上面修改的代码加入到Contacts.c后,再一次make,debug,并运行你的项目。初始值”hello”就将会显示在文本框中了。
本文来源:嵌入式在线 作者:
热点资讯(一周点击率)
最受工程师关注文章
热评博文
快乐大本营
无线时代来临,移动产业生态系统将发生一些根本变化。今日头条推荐“芯片是嵌入式4G技术的关键 产业生态系统将发生变化”。
想了解嵌入式开发工具的市场情况吗?先来体验下我们的在线调查吧!填写调查问卷。

