PalmOS开发教程-7
第七章 列表框和排序 |
在这一章中,将接触到一些新的控件和数据库操作技巧。我们先生成一个窗体来显示contact数据库中的所有记录,然后创建一个下拉框供选择排序标准,最后添加代码进行排序,并使新创建或修改过的记录也能够在列表中正确排列。 保存工程 按我们的习惯先保存工程,步骤如下: 1. 运行Windows浏览器; 2. 找到保存现有工程的文件夹; 3. 按下CTRL-C复制; 4. 选择目的文件夹; 5. 按下CTRL-V将现有工程粘贴到目的文件夹; 6. 将其重命名为容易记忆的名字,我将其命名为Contacts CH.6。 列表框 列表框能够显示许多文本条目并允许从中选择,我们可以对每个条目进行浏览或选择。我们还可以通过调用函数浏览列表或选择条目。当然,我们可以画出自己的列表框,在缺省情况下,列表框由Palm系统绘制。 Contacts.rsrc的内容添加 在这一部分中,我们将向应用程序添加一个新的窗体。此窗体将以列表的形式显示数据库记录,并允许我们浏览或选择。如果选中了其中的一条记录,记录内容将从Contact Detail 窗体上显示出来。 Contact Detail 窗体的内容添加 由于Contact Detail 窗体被调用来返回一条记录内容,所以我们需要添加一个Done按钮。步骤如下: 1. 运行构造器; 2. 打开资源文件Contact.rsrc,它位于工程文件夹的src文件夹里面; 3. 双击打开; 4. 选择Windows Catalog打开控件模板; 5. 向Contact Detail 窗体拖动一个按钮; 6. 设置按钮属性Object Identifier为Done,Left Origin=1,Top Origin=147,Label为Done; 7. 添加完成后,所得按钮如下图所示,选择右上角的X按钮关闭编辑器。 在Contact List窗体上创建菜单栏 在创建Contact List窗体前,我们先创建一个菜单;这样当设置窗体的属性时,就可以直接写入此菜单栏的ID了。 1. 在Resource Type and Name 列表框中选择Menu Bars并按下CTRL-K,于是一个新的菜单就产生了,将其重命名为Contact List; 2. 双击打开; 3. 拖动Option菜单到Contact List菜单栏上; 4. 完成后应如下图所示,点击右上角的X按钮关闭菜单栏。 创建Contact List窗体 现在我们来创建Contact List 窗体,步骤如下: 1. 点击Forms,并按下CTRL-K创建一个新的窗体; 2. 点击窗体名称将其命名为Contact List; 3. 在窗体编辑器中双击打开Contact List 窗体; 4. 为Contact List 添加标题,并使菜单栏的ID和Contact List 窗体的菜单栏的ID相匹配。 创建列表框(List) 1. 从Catalog窗口中拖动一个列表框(List)到窗体上。它的属性如表7-1所示; Object Identifier 在资源头文件中,构造器用之代表资源ID List ID 列表框的资源ID Left Origin 水平方向上控件的最左端位置 Top Origin 垂直方向上控件的最顶端位置 Width 列表的宽度 Usable 决定此控件是否可见能用,如果没有选中,也可在通过函数调用来实现其可见 Font 列表项的字体 Visible Items 列表框可显示的行数。注意,实际的列表条目数比此值可多可少 List Items 动态的初始化列表条目,如果想添加条目,按CTRL-K 2. 设置属性Object Identifier 为List,Left Origin=0,Top Origin=12,Width=160,Visible Items=12; 3. 完成后窗体如下图所示,按下右上角的X按钮关闭窗体,并选File Save保存所做修改。 添加内存错误警告 在这一章里,我们将开始添加错误处理代码。在内存溢出时,系统将发出警告信息: 1. 点击Resource Type and Name列表中的Alerts 并按下CTRL-K创建一个新的警报; 2. 将其命名为MemoryError; 3. 双击,在编辑器中打开; 4. 设置属性Alert Type 为Error,标题(title)为Fatal Error,信息(message)为“I have run out of memory.” 5. 完成后,如下图所示: Contact.c的内容添加 现在添加代码以完成新窗体的功能。首先,先在前几章中异常处理的忽略处添加代码进行异常处理。 异常处理 在这一章中,有很多地方可能会造成内存溢出。因此,我们必须添加严密的异常处理程序。下面我们将利用异常处理器(Error Manager)来完成,在The Palm OS SDK Reference 中对异常处理器有详细的论述。 首先,在PilotMain()前,定义异常退出(Exit)宏: // CH.7 The error exit macro #define errorExit(alert) { ErrThrow( alert ); } 异常处理函数ErrThrow()有些与众不同,它与宏ErrTry和ErrCatch()配合作用,类似C++和Java的形式给出异常处理。如果在ErrTry模块中的任何代码调用了ErrThrow()函数,控件就会立即调用ErrCatch()函数。下面我们看看在PilotMain()中做了哪些修改。 在事件loop 产生前先添加宏ErrTry: // CH.7 Begin the try block ErrTry { // CH.2 Our event loop do { 结束宏ErrTry并添加ErrCatch() 函数: // CH.7 End the try block and do the catch block } ErrCatch( errorAlert ) { // CH.7 Display the appropriate alert FrmAlert( errorAlert ); } ErrEndCatch 此函数将根据ErrThrow()传给ErrCatch()的ID号显示其相应的异常警报。然后,应用程序将在catch模块后正常退出,正常执行关闭数据库诸如此类的操作。最后,PilotMain()将控制权归还给Palm OS。 Contact List 窗体的切换 下面,我们添加代码来实现Contact List 窗体和Contact Detail窗体之间的切换。在PilotMain()中,修改初始化Contact Detail窗体的代码如下: // CH.7 Choose our starting page // CH.5 If there are no records, create one if( numRecords == 0 ) { newRecord(); FrmGotoForm( ContactDetailForm ); } else FrmGotoForm( ContactListForm ); 在切换到Contact List窗体时,判断如果数据库中没有记录,就要创建一条新记录;一般情况下,数据库中都是有记录的,我们可以直接调用Contact List窗体。 为使Contact List窗体能正确的初始化,在loop事件中的frmLoadEvent处理代码中再添加case项: // CH.7 Contact List form case ContactListForm: form = FrmInitForm( ContactListForm ); FrmSetEventHandler( form, contactListHandleEvent ); break; 下面的代码是如何处理Contact Detail 窗体中的Done按钮事件: // CH.7 Done button case ContactDetailDoneButton: { // CH.7 Load the contact list FrmGotoForm( ContactListForm ); } break; 为了在窗体间切换,而不是弹出窗体,我们使用了函数FrmGotoform()来初始化。这个函数首先调用frmCoseEvent关闭前一个窗体,然后调用frmLoadEvent和frmOpenEvent打开新的窗体。 Contact List窗体事件处理函数 下面我们为Contact List 窗体来添加事件处理函数。首先,在文件的开头加入原型: static Boolean contactListHandleEvent( EventPtr event ); 另外,还需要两个变量表示给列表框分配内存的句柄: // CH.7 Contact list variables static VoidHand hchoices; // CH.7 Handle to packed choices static VoidHand hpchoices; // CH.7 Handle to pointers 下面是事件处理函数: // CH.7 Our Contact List form event handler function static Boolean contactListHandleEvent( EventPtr event ) { FormPtr form; // CH.7 A form structure pointer // CH.7 Get our form pointer form = FrmGetActiveForm(); // CH.7 Parse events switch( event->eType ) { // CH.7 Form open event case frmOpenEvent: { // CH.7 Draw the form FrmDrawForm( form ); // CH.7 Build the list buildList(); } break; // CH.7 Form close event case frmCloseEvent: { // CH.7 Unlock and free things here MemHandleUnlock( hpchoices ); MemHandleFree( hpchoices ); MemHandleUnlock( hchoices ); MemHandleFree( hchoices ); hchoices = 0; } break; // CH.7 Respond to a list selection case lstSelectEvent: { // CH.7 Set the database cursor to the selected contact cursor = event->data.lstSelect.selection; // CH.7 Go to contact details FrmGotoForm( ContactDetailForm ); } break; // CH.7 Respond to a menu event case menuEvent: return( menuEventHandler( event ) ); // CH.7 Respond to the popup trigger case popSelectEvent: { // CH.7 If there is no change, we're done if( sortBy == event->data.popSelect.selection ) return( true ); // CH.7 Modify sort order variable sortBy = event->data.popSelect.selection; // CH.7 Sort the contact database by the new criteria DmQuickSort( contactsDB, (DmComparF*)sortFunc, sortBy ); // CH.7 Rebuild the list buildList(); } break; } // CH.7 End of the event switch statement // CH.7 We're done return( false ); } 事件处理函数以十分标准的形式开始:首先建立了一个窗体指针变量,它将在调用frmOpenEvent时被调用;然后窗体被绘制并调用了一个新的函数buildList(),这个函数在下一部分将详细讨论。 我们调用frmCloseEvent释放用来储存列表框内容的内存。之所以在关闭(close)事件中释放内存,是因为只要列表框可见、窗体在使用的时候,这一部分内存就一直被Palm OS使用。在这一点上,列表控件和其它控件有所不同,一般的控件都有自己的内存,而对于列表控件来说,它需要另外分配内存。 下面,讲述一个新的事件处理函数――lstSelectEvent。当列表的条目被选中时,此事件将被触发。变量selection标明哪一个条目被选中,列表得记录从0开始。这样我们使用起来就十分方便了,只要将当前记录等于列表变量selection的值,然后调用Contact Detail窗体,窗体就会使用前面所设置的变量cursor产生正确的记录。 最后,对本程序菜单事件的处理和对Contact Detail窗体的菜单处理几乎相同。这样,对Contact List窗体的处理程序就算完成了。 函数buildList() 下面我们来讨论这个实用函数buildList(),这个函数通过浏览数据库,为每条记录创建一文本字符串,然后使用这些字符串填充List对象的各个条目。 static void buildList( void ) { FormPtr form; // CH.6 A form structure pointer Int choice; // CH.7 The list choice we're doing CharPtr precord; // CH.7 Pointer to a record Char listChoice[dateStringLength + 1 + // CH.7 We timeStringLength + 1 + // build DB_FIRST_NAME_SIZE + // list DB_LAST_NAME_SIZE]; // choices here // CH.7 The current list choice CharPtr pchoices; // CH.7 Pointer to packed choices UInt offset; // CH.7 Offset into packed strings VoidPtr ppchoices; // CH.7 Pointer to pointers to choices // CH.6 Get our form pointer form = FrmGetActiveForm(); 在声明变量后,函数象往常一样获取窗体指针。这里面最有趣的变量是char array ,它将保证列表字符串的连续性。为使阵列(array)有足够的大小来保存任何Palm OS的系统时间和日期,可以使用Palm OS常量dateStringLength和timeStringLength。 // CH.7 Put the list choices in a packed string for( choice = 0; choice < numRecords; choice++ ) { // CH.7 Get the record hrecord = DmQueryRecord( contactsDB, choice ); precord = MemHandleLock( hrecord ); // CH.7 Get the date and time MemMove( &dateTime, precord + DB_DATE_TIME_START, sizeof( dateTime ) ); 首先,浏览数据库的所有记录,然后获取记录将变量dateTime设置为在所得记录中的时间和日期。注意到我们使用了DmQueryRecord()函数来获取记录句柄。此函数只给我们提供一个只读的记录副本。 下面,我们创建表示记录的字符串: // CH.7 Clear the list choice string *listChoice = ' Tags:作者:佚名评论内容只代表网友观点,与本站立场无关! 评论摘要(共 0 条,得分 0 分,平均 0 分)
查看完整评论
本类热门阅览相关文章 |