×
Namespaces

Variants
Actions

在Series60中创建自定义列表(LISTBOX)

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

文章
User:Davey 2 在 13 Oct 2007 创建
最后由 hamishwillee 在 30 May 2013 编辑

适用版本:

S60 2nd Edition FP3, S60 3rd Edition


CustomListbox.PNG


1.为什么要自定义 列表是在S60开发中经常用到的一个控件,在SDK中S60已经很周到的为我们提供了许多预定义的列表类型,其中包括CAknSingleGraphicStyleListBox、CAknDoubleStyleListBox等,这些预定义列表基本能够满足开发的需要。然而在一些特殊的场合下,自定义列表仍然有其用武之地,如使用自定义UI的应用程序中,比如在一些游戏中,使用自定义列表可以得到更好的用户体验。

2.如何自定义

2.1列表的MVC模型 在介绍具体的列表自定义方法之前有必要介绍一下列表模型的整体框架,列表使用的是我们常用的MVC模型,即Model-View-Controller模型,其中Model模块用于处理数据存储,View模块是处理数据显示和UI,而Controller则是用来联系两者的桥梁,通过Controller模块的CEikListBox::Model()可以得到Model,同样通过CEikListBox::View()可以得到View。对于自定义列表来说,重点是View模块。 MVC.PNG

2.2使用CListItemDrawer创建自定义列表 下面就可以开始创建自定义列表了,在开始之前我们还要弄清一件事:到底是由谁来完成数据显示的具体绘制工作的,我们可以通过CListBoxView::ItemDrawer()来得到这个对象,它是由CListItemDrawer类派生而来的一个实例。 下面的代码演示了如何从CListItemDrawer派生出自己的ItemDrawer:

      class CMyListItemDrawer: public CListItemDrawer
     {
       public:
       CMyListItemDrawer(const CEikTextListBox& aListBox);
       private: // CListItemDrawer
       void DrawActualItem(TInt aItemIndex, const TRect& aActualItemRect, TBool aItemIsCurrent, TBool aViewIsEmphasized, TBool     aViewIsDimmed, TBool aItemIsSelected) const;
       private:
       const CEikTextListBox& iListBox;
       };

先来看一下构造函数完成了哪些工作吧:

        CMyListItemDrawer::CMyListItemDrawer(const CEikTextListBox& aListBox)
       :CListItemDrawer(),iListBox(aListBox)
       {
       // 设置图形上下文
        iGc = &CCoeEnv::Static()->SystemGc();
       SetGc(iGc);
       }
  在构造函数的参数中包含一个CEikTextListBox的引用,因为在ItemDrawer中要从CEikTextListBox中获得需要显示的文本。另外构造函数还设置了用来绘制列表的图形上下文(graphics context)iGc。

实际的绘制工作是在DrawActualItem这个函数中完成,通过对DrawActualItem、aItemIsSelected这些变量判断当前绘制的是否具有焦点(Focus),然后根据情况来设置当前使用的字体以及画笔和背景的颜色,接着获取需要绘制的文本,这可以通过iListBox.Model()来得到列表的Model,然后由ItemText()函数通过传入的列表项索引号得到,最后完成具体的绘制。下面的代码给出了一个示范:

        void CMyListItemDrawer::DrawActualItem(TInt aItemIndex,
       const TRect& aActualItemRect, TBool /*aItemIsCurrent*/,
       TBool /*aViewIsEmphasized*/, TBool /*aViewIsDimmed*/,
       TBool /*aItemIsSelected*/) const
       {
         .....
         .....
       // 设置绘制的字体,画笔式样和颜色等
        const CFont* font = CEikonEnv::Static()->NormalFont();
       iGc->UseFont(font);
       iGc->SetPenColor(iTextColor);
       iGc->SetPenStyle(CGraphicsContext::ESolidPen);
       iGc->SetBrushColor(iBackColor);
       iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
       // 绘制列表项
       TPtrC itemText = iListBox.Model()->ItemText(aItemIndex);
       TInt baseline = (aActualItemRect.Height() - font->HeightInPixels()) / 2+ font->AscentInPixels();
       iGc->DrawText(itemText, aActualItemRect, baseline);
          ......
          ......
       }

以上的步骤就完成了一个自定义的ItemDrawer的构建,通过改变iTextColor、iBackColor等变量的值我们可以得到自己满意的UI效果。

离成功只剩最后一步了,以上步骤完成了自定义的ItemDrawer,但是并没有告诉列表应该使用我们的ItemDrawer来完成列表的绘制,这一步可以通过重载Controller模块的CEikTextListBox::CreateItemDrawerL()来完成:

        class CMyListBox: public CEikTextListBox
       {
       private: // from CEikTextListBox
       virtual void CreateItemDrawerL()
       { iItemDrawer = new (ELeave) CMyListItemDrawer(*this); }
       };

至此我们已经完成构建一个自定义列表的全部工作,其它的工作就交给系统去完成吧。

3.自定义列表的使用 对于自定义列表的使用与系统提供的其它列表的使用是相同的,以我提供的例子为例,首先创建一个自定义列表的实例

        // 创建一个自定义列表
        iListBox = new (ELeave) CCustomListBox();
       iListBox->ConstructL(this,CEikListBox::ENoFirstLetterMatching|CEikListBox::ENoExtendedSelection);

然后调用CTextListBoxModel::SetItemTextArray().来设置列表项:

        _LIT(KItemTextDouble1, "0\tFirst item\tDescription of the first item");
       _LIT(KItemTextDouble2, "1\tSecond item\tDescription of the second item");
       CDesCArrayFlat* array = new (ELeave) CDesCArrayFlat(2);
       CleanupStack::PushL(array);
       array->AppendL(KItemTextDouble1);
       array->AppendL(KItemTextDouble2);
       CleanupStack::Pop();
       iListBox->Model()->SetItemTextArray(array);

在此有必要解释一下列表项的书写格式,此处是如下格式

        "0\tItem name\tDescription of the item"

与系统提供的书写方式一致,这么做并不是必须的,比如我们可以用"\b"代替"\t"作为分隔符,这样在程序中我们就要搜索"\b",而不是搜索"\t"。但是为了与系统保持一致,建议使用这种表示方式。

最后为自定义列表提供图标,如果没有图标显示,这一步可以省略,同时列表项的数据格式也会有所不同,其中的图标索引号就不再需要了,如下所示:

        "\tItem name\tDescription of the item"
      CArrayPtr<CGulIcon>* iconArray = new (ELeave) CArrayPtrFlat<CGulIcon>(2);
      CleanupStack::PushL(iconArray);
      CCustomListItemDrawer* itemDrawer = static_cast<CCustomListItemDrawer*>(iListBox->View()->ItemDrawer());
      iconArray->AppendL(iEikonEnv->CreateIconL(KIconFileName, EMbmEikonFileclsd, EMbmEikonFileclsm));
      CleanupStack::Pop(); // iconArray
      itemDrawer->SetIconArray(iconArray); // 转移iconArray所属权

SetIconArray()函数会转移iconArray的拥有权(ownership);因此在此我们不用删除iconArray,CCustomListItemDrawer使用完毕以后会负责它的清除。

例子请到以下地址下载: [1]

本文参考antonypranata的Subclassing List Box in Symbian,在此表示感谢

This page was last modified on 30 May 2013, at 07:37.
131 page views in the last 30 days.
×