用户登录  |  用户注册
首 页商业源码原创产品编程论坛
当前位置:PB创新网文章中心编程技巧编程其他

PalmOS开发教程-7

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2009-03-16 19:36:39
第七章 列表框和排序
     在这一章中,将接触到一些新的控件和数据库操作技巧。我们先生成一个窗体来显示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%(0)

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
PB创新网ourmis.com】Copyright © 2000-2009 . All Rights Reserved .
页面执行时间:22,406.25000 毫秒
Email:ourmis@126.com QQ:2322888 蜀ICP备05006790号