返回列表 回复 发帖
所需阅读权限 1

[分享]BREW&J2ME:在差别中联合(2)

[这个帖子最后由cnangel在 2004/05/25 05:48pm 第 1 次编辑]

作者:Radu Braniste什么是List?
包装
前景
源代码下载
原文地址
参考文献
关于作者

什么是List?

BREW不提供List,而是提供MenuCtl。简单的说,“List就是一个暴露MenuCtl功能的IDisplayable。”
  1. template <class T,
  2.           class P=ListStrategy,
  3.           class E = ErrorHandler>
  4. class ListImpl : public IDisplayable
  5. {
  6. typedef bool (T::*FNC)(ListImpl<T,P,E>*);
  7. public:
  8.   static ListImpl* getList(
  9.            const WString& title, T* t)
  10.   {
  11.     ListImpl* l = createList(t);
  12.     if (l)
  13.     {
  14.       l->setTitle(title);
  15.       l->setFullScreen();
  16.     }
  17.     return l;
  18.   }
  19.   virtual ~ListImpl()
  20.   {
  21.     if (list_) IMENUCTL_Release(list_);
  22.   }
  23.   void append(const WString& item)
  24.   {
  25.     if (!rr_)
  26.       return;
  27.     int id = rr_->getNextAvailableID();
  28.     IMENUCTL_AddItem(list_, 0, 0, id,
  29.                   const_cast<AECHAR*>
  30.                     (item.toCharArray()), 0);
  31.     indxs_.append(id);
  32.   }
  33.   void append(const WString items[]s, int sz)
  34.   {
  35.     for(int i=0; i < sz; ++i)
  36.     {
  37.       append(items[i]);
  38.     }
  39.   }
  40.   virtual IControl* getControl() const
  41.   {
  42.     return reinterpret_cast<IControl*>(list_);
  43.   }
  44.   bool onCmd()
  45.   {
  46.     if (fnc_ && t_)
  47.       return (*t_.*fnc_)(this);
  48.     return false;
  49.   }
  50.   int getSelectedIndex() const
  51.   {
  52.     return selected_;
  53.   }
  54.   virtual bool containsItem(int ix)
  55.   {
  56.     selected_ = getIDImpl(ix);
  57.     return (selected_ != INDEX_OUT_OF_BOUNDS);
  58.   }
  59.   virtual int getID() const
  60.   {
  61.     return id_;
  62.   }
  63.   void setCbk(FNC f)
  64.   {
  65.     fnc_ = f;
  66.   }
  67.   void setSelection(int id)
  68.   {
  69.     int lid = IMENUCTL_GetItemID(list_, id);
  70.     IMENUCTL_SetSel(list_, lid);
  71.   }
  72.   int size() const
  73.   {
  74.     return indxs_.size();
  75.   }
  76.   void setTitle(const WString& title)
  77.   {
  78.     if (title.length())
  79.       IMENUCTL_SetTitle(list_, NULL, 0, const_cast<AECHAR*>
  80.                        (title.toCharArray()));
  81.   }
  82. private:
  83.   
  84.   ListImpl( T* t, AEECLSID cid ): list_(0), t_(t) , rr_(0),
  85.           shell_(getShell()), selected_(0)
  86.   {
  87.     if (shell_)
  88.       ISHELL_CreateInstance(shell_, cid, (void **)&list_);
  89.     if (!list_)
  90.     {
  91.       E::onMemAllocError(WString(__FILE__),
  92.                          WString((long)__LINE__));
  93.       return;
  94.     }
  95.     rr_ = t_->getDisplayable();
  96.     if (rr_)
  97.       id_ = rr_->registerResource(this);
  98.   }
  99.   static ListImpl* createList( T* t, AEECLSID cid =
  100.                                      AEECLSID_MENUCTL)
  101.   {
  102.     ListImpl* l = new ListImpl( t, cid);
  103.     if (!l->list_)
  104.     {
  105.       delete l;
  106.       return 0;
  107.     }
  108.     return l;
  109.   }
  110.   void setFullScreen();
  111.   int getIDImpl(int ix);
  112. private:
  113.   IMenuCtl *  list_;
  114.   FNC fnc_;
  115.   T* t_;
  116.   DisplayableRegistry* rr_;
  117.   int selected_;
  118.   int id_;
  119.   IShell * shell_;
  120.   BrewVector<int> indxs_;
  121. };
复制代码
下一个概念就是事件处理。显然,BREW 和Java之间存在的重要差别包括:一个唯一的ID、事件循环机制配对一个固有的,基于监视器的机制。我说“显然”,那是因为机制之间可以自由切换。甚至J2ME可以共享BREW的缺陷——命令听取者的实现与BREW事件循环紧密关联——这个缺陷通常是一个难于维护的、巨大的“转换”。在此之上,听取者是一个类型很差的构造,它暴露一个不得不被用户抛弃的Displayable接口。我们的框架提供一个更安全的方法,它拥有类型安全的、J2SE风格的听取者。例如, ListImpl 类可定义一个听取者:
  1. typedef bool (T::*FNC)(ListImpl<T,P,E>*);
  2. 实现如下:
  3.   bool myListUsage( List* l)
  4.   {
  5.     int pos = l->getSelectedIndex();
  6.     return (pos == INDEX_OUT_OF_BOUNDS) ?
  7.             false : BuildCommand(pos), true;
  8.   }
  9. 并且登记如下:
  10. l->setCommandListener(myListUsage);
复制代码
Java有一个更好的getSelected() 机制来取代传送到IMENUCTL_AddItem 的唯一标志。通过使用普遍存在的DisplayableRegistry,我们可以很容易的实现它,这段时间内产生的唯一标志在内部可作为ID使用。请注意在某些特殊的情况下使用政策可加快ID的检索。

BREW 和Java之间的一个明显差别在于故障处理,基于RTTI的异常处理在BREW中不可用或者使用成本过高。使用setjmp/longjmp 模拟try/catch机制由于销毁自动对象有问题不能直接应用,但是其他的技能是可用的。为了方便,我们将ErrorHandler当作政策——适当提供异常追踪信息的一种方式——来提供。

包装

让我们使用上述技巧从头开始写一个应用程序。

框架封装在cppapp和brewJ2ME内。一个应用就是一个类——与文件MyApp.h 中的Midlet差不多。以下是编写应用的步骤:

1.将 "MyApp.h"包括在cppapp.h之内。

2.创建一个继承于IMidlet 的Midlet 类。

3.将APPLICATION_TYPE 的类型定义为 Midlet。

结果产生的框架为:
  1. class Midlet : public IMidlet
  2. {
  3. };
  4. typedef Midlet APPLICATION_TYPE ;
复制代码
我们的简单应用将处理两个清单,每一个都包含四项——{"1","2","3","4"} 和{"A","B","C","D"}。例如,按下"1,",我们将看到相应的"A," ,按下 "C" 就转换为"3,",以此类推。这种逻辑可嵌入到两个事件处理器内:my14ListUsage和myADListUsage。
  1. class Midlet : public IMidlet
  2. {
  3. typedef ListImpl<Midlet> List;
  4. private:
  5.   bool my14ListUsage( List* l)
  6.   {
  7.     int pos = l->getSelectedIndex();
  8.     return (pos == INDEX_OUT_OF_BOUNDS) ?
  9.             false : BuildADList(pos), true;
  10.   }
  11.   bool myADListUsage( List* l)
  12.   {
  13.     int pos = l->getSelectedIndex();
  14.     return  (pos == INDEX_OUT_OF_BOUNDS)  ?
  15.              false : Build14List(pos), true;
  16.   }
  17.   List * Init14List()
  18.   {
  19.     List* l = List::getList("List14", this);
  20.     if (!l) return 0;
  21.     l->setCbk(my14ListUsage);
  22.     WString a[] = {"1","2","3","4"};
  23.     l->append(a,SIZE_OF(a));
  24.     return l;
  25.   }
  26.   List * InitADList()
  27.   {
  28.     List* l = List::getList("ListAD", this);
  29.     if (!l) return 0;
  30.     l->setCbk(myADListUsage);
  31.     WString a[] = {"A","B","C","D"};
  32.     l->append(a,SIZE_OF(a));
  33.     return l;
  34.   }
  35.   void BuildADList(int ix )
  36.   {
  37.     if (!lAD_)
  38.     {
  39.       lAD_ =InitADList();
  40.     }
  41.     BuildList(lAD_, ix);
  42.   }
  43.   void Build14List(int ix )
  44.   {
  45.     if (!l14_)
  46.     {
  47.       l14_ = Init14List();
  48.     }
  49.     BuildList(l14_, ix);
  50.   }
  51.   void BuildList(List* l , int ix)
  52.   {
  53.     if (!l || (l->size()-1)<ix) return;
  54.     l->setSelection(ix);
  55.     getDisplayable()->setCurrent(l);
  56.   }
  57. public:
  58.   virtual bool onStart()
  59.   {
  60.     l14_ = 0;
  61.     lAD_ = 0;
  62.     BuildADList(2);
  63.     return true;
  64.   }
  65. private:
  66.   List* l14_;
  67.   List* lAD_;
  68. };
复制代码
我们真正感兴趣的不是代码的明显简化,而是事件处理的透明性。

前景

这个最初的尝试并没有包括重要内容如多-控制屏幕、处理事件而不是处理EVT_COMMAND、以及控制登记过的资源。下一个部分将讨论所有这些内容以及扩展该框架的机制。

相关原版下载例子

                     我是一个呼吸着现在的空气而生活在过去的人
               这样的注定孤独,孤独的身处闹市却犹如置身于荒漠
                                     我已习惯了孤独,爱上孤独
                                 他让我看清了自我,还原了自我
                             让我再静静的沉思中得到快乐和满足
                                   再孤独的世界里我一遍又一遍
                                   不厌其烦的改写着自己的过去
                                             延伸到现在与未来
                                       然而那只是泡沫般的美梦
                                 产生的时刻又伴随着破灭的到来
                         在灰飞烟灭的瞬间我看到的是过程的美丽
                                      而不是结果的悲哀。。。
返回列表