  
- UID
- 1
- 威望
- 1240 点
- 金钱
- 24019 金币
- 点卡
- 317 点
|
所需阅读权限 1 [分享]Brew&J2ME:在差别中联合(3)
[UploadFile=7_30.zip.info][这个帖子最后由cnangel在 2004/05/26 12:39pm 第 3 次编辑]
作者:Radu Braniste
这是本系列的第二篇文章,主要面向那些更习惯使用J2ME的手机开发者,或者那些对更轻便和更有效的代码生成感兴趣的BREW开发者。在上一篇文章中《BREW&J2ME:在差别中联合(一)》《BREW&J2ME:在差别中联合(二)》,我们给出了一个主要受Java GUI模型启示的基本框架,它减轻了开发者采用BREW编写高级别接口代码的难度。这部分,我们将扩展和重分解这个框架,以便正确处理现实生活中的问题。
目录
案例
其他说明
包装
下载样品程序
我们以多控制屏幕这个基本范例为例,来详细讨论框架的内部机制。
案例
我们直接以双屏的应用程序为例:- class BJApp : public IMidlet
- {
- typedef ListImpl<BJApp> List;
- typedef DateCtlImpl<BJApp> DateCtl;
- typedef List Command;
- private:
- void BuildDateCtl(int year)
- {
- DateCtl* l =
- (DateCtl*) getRegistered("DATE_CTL");
- if (!l)
- {
- l = DateCtl::createDateCtl("DATE_CTL",
- this);
- if (!l) return ;
- Command* c = BuildDateCtlCommand(1);
- if (!c) return ;
- l->setScreen(8,20,110,60);
- l->installEventHandler(dateCtlHdl);
- l->installEventHandler(dateCtlHdl,
- TAB);
- l->setTitle("Select a Date");
- l->addDisplayable(c);
- l->addDisplayable(l);
- }
- l->setDate(year,12,31);
- l->setCurrent();
- }
- bool dateCtlHdl( DateCtl* l)
- {
- l->setCurrentAt(0);
- return true;
- }
- Command* BuildDateCtlCommand(int ix)
- {
- Command* c =
- (Command*) getRegistered("DATE_CTL_COMMAND");
- if (c)
- return c;
- c = Command::createCommand("DATE_CTL_COMMAND",
- this);
- if (!c) return 0;
- c->installEventHandler(dateCtlCmdHdl);
- c->installEventHandler(dateCtlCmdTabHdl,
- TAB);
- WString a[] = {"Nowhere","Back"};
- c->append(a,SIZE_OF(a));
- c->setSelection(ix);
- return c;
- }
- bool dateCtlCmdTabHdl( Command* l)
- {
- setActive("DATE_CTL");
- return true;
- }
- bool dateCtlCmdHdl( Command* l)
- {
- int pos = l->getSelection();
- if (pos == INDEX_OUT_OF_BOUNDS)
- return false;
- if (pos == 1)
- {
- Command* c =
- (Command*)getRegistered("DATE_COMMAND");
- if (!c) return false;
- c->setSelection(0);
- BuildInputList(0, "INPUT_LIST_0");
- }
- return true;
- }
- void BuildInputList(int focus,
- const String& lst)
- {
- List* l = (List*) getRegistered(lst);
- if (!l)
- {
- l = List::createList(lst, this);
- if (!l) return;
- Command* c = BuildDateCommand(0);
- if (!c) return;
- l->installEventHandler(inputListHdl);
- l->installEventHandler(inputListTabHdl,
- TAB);
- l->setTitle("Start");
- l->setFullScreen(120);
- l->addDisplayable(c);
- l->addDisplayable(l);
- }
- l->setCurrentAt(focus);
- }
- bool inputListHdl( List* l)
- {
- int pos = l->getSelection();
- if (pos == INDEX_OUT_OF_BOUNDS)
- return false;
- Command* c =
- (Command*)getRegistered("DATE_COMMAND");
- if (!c)
- return false;
- if (c->getSelection() == 0)
- BuildDateCtl(2003);
- else if (c->getSelection() == 1)
- BuildDateCtl(2004);
- else
- BuildDateCtl(9999);
- return true;
- }
- bool inputListTabHdl( List* l)
- {
- l->setCurrentAt(0);
- return true;
- }
- Command* BuildDateCommand(int ix)
- {
- Command* c =
- (Command*) getRegistered("DATE_COMMAND");
- if (c)
- return c;
- c = Command::createCommand("DATE_COMMAND",
- this);
- if (!c) return 0;
- c->installEventHandler(dateCmdTabHdl);
- c->installEventHandler(dateCmdTabHdl,
- TAB);
- WString a[] = {"2003","2004" };
- c->append(a,SIZE_OF(a));
- c->setSelection(ix);
- return c;
- }
- bool dateCmdTabHdl( Command* l)
- {
- int pos = l->getSelection();
- return dateManipulation(pos);
- }
- bool dateManipulation(int pos)
- {
- switch (pos)
- {
- case 0:
- {
- String s("INPUT_LIST_0");
- List* k = (List*) getRegistered(s);
- if (k && !k->size())
- {
- WString a[] = {"Conference","DevDay"};
- k->append(a,SIZE_OF(a));
- }
- BuildInputList(1,s);
- break;
- }
- case 1:
- {
- String s("INPUT_LIST_1");
- BuildInputList(1,s);
- List* k = (List*) getRegistered(s);
- if (k && !k->size())
- {
- WString a[] = {"Training","Vacation"};
- k->append(a,SIZE_OF(a));
- }
- BuildInputList(1,s);
- break;
- }
- default:
- return false;
- }
- return true;
- }
- public:
- virtual bool onStart()
- {
- setColor(CLR_SYS_ITEM_SEL , 0,0, 255);
- setColor(CLR_USER_TEXT , 0,0, 255);
- BuildInputList(0, "INPUT_LIST_0");
- return true;
- }
- };
复制代码 本例中的所有小器件都登记为EVT_CTL_TAB 和 EVT_COMMAND事件,并可作为单独的器件进行登记和按名检索。所有的UI逻辑可以方便的在事件处理器内部实现。
应用从onStart()内开始,它首先创建一个列表(INPUT_LIST_0) 和一个命令 (DATE_COMMAND)。
INPUT_LIST_0 两个小器件都有。EVT_CTL_TAB 切换焦点,EVT_COMMAND实现某些与数据相关的逻辑并通过BuildDateCtl将屏幕切换到DATE_CTL 。
DATE_COMMAND 通过同一个处理器(dateCmdTabHdl)处理这两个事件。在选择的基础上,创建了一个新的列表(INPUT_LIST_1),它与DATE_COMMAND 和给定焦点,或者可移回到INPUT_LIST_0的焦点,相关联。
BuildDateCtl 使用简单的UI逻辑创建了DATE_CTL 和DATE_CTL_COMMAND之间的关联——"back" 命令可将应用带回到INPUT_LIST_0 状态。
其他说明
我们的应用处理三个GUI小器件:列表、命令和DateCtl。实际上,列表和命令是同一个基本类型ListImpl的变种,但却用于不同目的。所有的应用都继承于IMidlet ,他们都优先于onStart()、onStop()、 onResume()、和onSuspend()回调。IMidlet现在展示一个未测试过的setColor() 函数。
有一个新的机制可用于实现小器件的持续性。onStart()在BuildInputList内部创建了一个名为"INPUT_LIST_0"的列表。小器件现在可以按名检索(在以前的实现中,只能通过指针检索),这样就不必在类的范围内明确的声明他们:- List* l = (List*) getRegistered(lst);
复制代码 小器件总是可以通过使用"Named Constructor Idiom"[2],采用createXXX(const String& name, T* t) 或者createXXX(T* t)的格式来创建。第一种格式允许按名检索,并可在例中扩展性的使用。请注意方法名的变化:现在createXXX()取代了getXXX()。
事件处理是一般化的。有一个新方法可取代setCbk()——无效的installEventHandler(F f, LIST_EVT evt)。基本上,这个方法对于每个事件都登记一个回调,就像在LIST_EVT 定义中定义的一样:- typedef enum {TAB,CMD, EVT_SIZE} LIST_EVT;
- // EVT_SIZE is a guard value
- //currently only CMD & TAB supported
- //CMD = EVT_COMMAND
- //TAB = EVT_CTL_TAB
- f 就是一个应用程序的方法。
复制代码 实现细节:事件处理作为一个单独的服务封装:- template <class T, class F>
- class EvtHandler;
复制代码 命令(DATE_COMMAND) 在BuildDateCommand()内创建。命令是软件密匙包装,从BREW 的方面来看,它也是列表的小型规范。
现在进入最令人感兴趣的部分:装配小器件到更丰富的显示中。我们的UI层与J2ME有点类似——开头是Displayables,接着是从Displayables继承而来的屏幕(这是层的新的添加物),最后是继承于屏幕的命令、列表和其他小器件。从BREW 的观点来看,IDisplayable相当于IControl。屏幕增加了容器功能——每个屏幕都能够包含任何其他的Controls (IDisplayable), 包括他自己。- class Screen: public IDisplayable
- {
- public:
- void addDisplayable(IDisplayable* d);
- void setDisplayableAt(IDisplayable* d, UINT pos);
- void setCurrent(bool isRedrawing = true);
- void setCurrentAt(UINT mainDisplayable, bool isRedrawing = true);
- virtual ~Screen()
- {}
- protected:
- Screen(IMidlet* m):IDisplayable(m->getDisplayableRegistry()),
- m_(m)
- {}
- private:
- void setCurrentImpl(IDisplayable* displayable,
- bool isRedrawing );
- void redrawDisplayables();
- private:
- DISPLAYABLES displayables_;
- IMidlet* m_;
- };
复制代码 小器件在屏幕的开头实现,这使得配置非常灵活。例如:命令可以包含列表,诸如此类。下列代码更好的解释了这个概念:- List* l = List::createList("lst", this);
- Command* c = Command::createCommand("cmd", this);
- l->addDisplayable(c);
- l->addDisplayable(l);
- l->setCurrentAt(0);
复制代码 列表 l 包含命令 c 和它自身(l),最后他们都呈送到屏幕上,而且c 被激活(setCurrentAt(0) )。setCurrentAt(index) 使用了一个基于零的指针符号,但是基于字符串(名字)的实现同样有可能——有一点点性能降低。快捷方式(setCurrent())是可行的—— 直接在容器内设置焦点。
正如上文提到的一样,指针可以自动生成,它在相当程度上简化了项的操作。指针操作封装在一个指定的类Indexes中,它可被所有有权限的组织(主要是小器件)使用:- class Indexes
- {
- public:
- void append(int id);
- int size() const;
- template <class P>
- int getIDImpl(int ix);
- private:
- BrewVector<int> indxs_;
- };
复制代码 另一个有用的机制也被添加到IMidlet中。如前所述,setCurrent() 和 setCurrentAt()有双重功能:他们都可以刷新屏幕,并且可在综合视图内设置激活的小器件。在内,setCurrent()和setCurrentAt() 使用IMidlet::setActive(),它唯一的用途就是保存到激活的IDisplayable 的引用。
当不必刷新屏幕时就可以使用IMidlet::setActive(),例如:- bool dateCtlCmdTabHdl( Command* l)
- {
- setActive("DATE_CTL");
- return true;
- }
复制代码 在DateIml.h内实现了一个DateCtl (PickCtl是它的较小变种)。
包装
这个框架很容易扩展——只要添加必要的新控制和新事件即可。它比原来的BREW API要容易使用,因为它与J2ME模型相似,它提供了自动存储管理。所有前面描述的框架(见Generic Connection Framework和Cooperative Multitasking) 都很容易装配到这个框架里面。
上面是下载样品程序
原文地址:http://www.developer.com/ws/j2me/article.php/3116331
参考文献:
1.BREW and J2METM—A Complete Wireless Solution for Operators Committed to Java—Qualcomm http://www.qualcomm.com/brew/images/about/pdf/brew_j2me.pdf
2.Design Patterns: Elements of Reusable Object-Oriented Software—ErichGamma, RichardHelm, RalphJohnson, and John Vlissides, Addison-Wesley, 1994
3.String in BREW Revisited—a BrewString Generalization—http://www.developer.com/ws/brew/article.php/2229051
4.Emulating C++ Exception Handling—Gregory Colvin, C/C++ Users Journal, December 1994
5.For Brew Developers, There Are New Kids in Town: IThread & IRscPool, Part 2—http://www.developer.com/ws/brew/article.php/3105131
关于作者
Radu Braniste 是Epicad的技术主任。联系他请发邮件到: rbraniste@epicad.com |
我是一个呼吸着现在的空气而生活在过去的人
这样的注定孤独,孤独的身处闹市却犹如置身于荒漠
我已习惯了孤独,爱上孤独
他让我看清了自我,还原了自我
让我再静静的沉思中得到快乐和满足
再孤独的世界里我一遍又一遍
不厌其烦的改写着自己的过去
延伸到现在与未来
然而那只是泡沫般的美梦
产生的时刻又伴随着破灭的到来
在灰飞烟灭的瞬间我看到的是过程的美丽
而不是结果的悲哀。。。
|
|