在laszlo应用开发过程中大部分编码过程集中在对系统组件的熟练应用比如取值传值刷新组件状态等等但是很多情况下尤其是项目的初始编码阶段需要定义一些满足项目特定要求的界面组件这就需要自定义组件了 自定义组件开发首先需要对lzx的语法系统组件结构开发文档有全面而且深刻的理解然后通过不断的锻炼按照由间到繁的实践过程才能逐渐成为开发高手 理解组件的基本原理 原理介绍类模型视图控制器(MVC) class与组件 LZX语言是一种面向对象的基于原型的编程语言而class是LZX编程语言的核心使用class你可以生成定制的可重用的组件来提高代码编写效率(LZX is an objectoriented prototype based language that allows you to create custom reusable classes to streamline and minimize code Classes are at the heart of LZX programming) 下面看看一个简单的class: <class name=MyClass width= height= bgcolor=#CFDAB> <text align=center valign=middle>Hello World!</text> </class> 这就定义了一个简单的classclass在LZX语法中继承自LzView所以它可以有高度宽度背景色等属性 在canvas里这样使用它 <MyClass name=myFirstInstance/> 就是说把已经定义的类名当作一个标签的名称放在canvas里就可以了如果你愿意可以给它起个实例名比如myFirstInstance还可以指定它的位置等等 (详见Software Engineers Guide:Chapter Introduction to Classes and Object Oriented Programming) 这是一个简单的class但也是一个简单的组件如果把这个class扩展一下添加一些属性事件数据模型那么它就可以构成一个可重用的组件 解析LzButton 一个功能完整的组件应该由个部分组成MVC M: A model that represents the data for the application V: The view that is the visual representation of that data C: A controller that takes user input on the view and translates that to changes in the model (引自A Swing Architecture Overview) M表示模型模型代表着组件的数据内容 V表示视图视图代表着组件的视觉形象 C表示控制器控制器接收用户输入并对其做出响应 下面看看一个Openlaszlo系统组件中最常用也是最简单的一个组件button 打开C:\Program Files\OpenLaszlo Server \Server\lps\lps\components\lz 下面的buttonlzx 会看到个<include/>标签这是button组件需要的父类组件 接下来的<resource/>是button组件需要的视图资源大多是flash图片背景 注意第行<class name=button extends=basebutton …这才是组件真正定义的开始可以看出button继承自父类basebutton也就是说button的基本行为来自于basebuttonbasebutton定义了button组件的基础控制部分即MVC中的C 接下来是一些属性定义<attribute name=someproperty value=valuecorresponding/>name表示属性名称value是对应的值 这些attribute标签是组件需要的属性这些属性一般都要默认的值如果需要修改在使用组件时重载这些属性就可以了 接下来这些<method name=…/>代表组件的C即控制部分 最后是<view name=…这些代表组件的V视图部分前面定义的resource在这里用到 因为按钮组件不需要数据来填充也就是说它不是用来展现数据所以就没有M模型部分 解析List list组件和button组件不同的地方在于它有对其内部数据进行操作的部分即modelM还是在刚才的目录打开源文件listlzx 在第行<class name=list extends=baselist…可以看出list也是继承自其父类baselistlzx即list组件的控制部分 当然基础组件的定义不完全是控制部分也包含部分模型部分但是组件的定义则包含了MVC三个部分 比如baselistlzx中<method name=getSelection> <method name=getNumItems> <method name=getItemAt args=index > <method name=getItem args=value> <method name=addItem args=text value > <method name=removeItem args=value > …… 这些都是属于数据操作部分也定义在了父类中这个没有严格区分 而在listlzx中数据操作只定义了<method name=addItem args=txt val >也是重载了父类的方法 通过superaddItem(txtval)来重新定义了 制作一个简单的自定义button 通过了解系统组件的结构看来自定义一个组件也不是什么难事了如何下手做呢还是找个例子先 打开参考文档找到Base Classes第一个就是basebutton点击查看说明文档和例子原来这么简单只要给basebutton加上资源 就是一个按钮了那么自己再修改一下不就是自己想要的按钮了吗? 首先按钮文字是必须要加的那么需要一个属性来保存文本字符 <attribute name=text type=html value=/> 然后需要一个text组件来显示按钮文字 <text name=txt align=center valign=middle resize=true fgcolor=# text=${parenttext}/> 接下来需要添加鼠标事件来让按钮上的文字做出点击响应 <method event=onmousedown> txtsetX(txtx+) txtsetY(txty+) </method> <method event=onmouseup> txtsetX(txtx) txtsetY(txty) </method> 这样就完成了一个具备基本功能的按钮了 <class name=mybutton width= height= extends=basebutton resource=longbtn_rsc> <attribute name=text type=html value=/> <text name=txt align=center valign=middle resize=true fgcolor=# text=${parenttext}/> <method event=onmousedown> txtsetX(txtx+) txtsetY(txty+) </method> <method event=onmouseup> txtsetX(txtx) txtsetY(txty) </method> </class> 在canvas里通过<mybutton name=buttonname text=clickMe> <handler name=onclick> //do something; </handler> </mybutton> 就可以使用了 扩展一个系统组件 在开发RIA项目时往往会遇到比较复杂的业务需求或者大数据量展现等任务这时能满足这些任务的组件就显得分外重要笔者在开发第一个任务时需要在tree组件上进行操作而这个tree的节点又很多视图的渲染过程往往花费十几秒以上有时竟然让IE崩溃郁闷之极 幸得网友的指点找到一个lazytree组件才解决了这个问题这是一个扩展了系统tree组件功能的组件 它重载了tree节点生成的过程由原来得一次全部生成变成逐步生成大大降低了初始渲染时间 <class name=lazytree extends=tree> <! Turn off autorecursion for tree Get child nodes when tree is opened > <attribute name=recurse value=false type=boolean/> <attribute name=haveChildren value=false type=boolean/> <method event=onopen args=o><![CDATA[ // If we already have children dont fetch them again if (thishaveChildren) return; if (o) { // Now set recurse to true This value is used in basetrees // createChildTrees() method See // lps/components/base/basetreelzx for and // lps/components/lz/treeelzx source code thissetAttribute(recurse true) createChildTrees() thissetAttribute(recurse false) // We have child nodes thissetAttribute(haveChildren true) } ]]></method> </class> 如注释所书Turn off autorecursion for tree Get child nodes when tree is opened关闭了自动递归过程 只有当前节点打开时生成下一级节点 由此可见理解系统组件的结构和原理是何等重要! 开发高级的自定义组件 表格是界面开发常用的组件但是laszlo的grid不够漂亮和精练所以构建自己的grid就显得必要了 以openria网站的资源下载表格为例需要列而且有一列要能提供下载内容的点击操作经过构思步骤如下 第一步构建表格体包括表头和表体 <view name=header… <text x= text=ID /> <text x= text=名称 /> <text x= text=描述 /> <text x= text=分类/> <text x= text=链接 /> </view> <view name=rowcontainer… <view name=columns… … </view> 第二步构建表格头背景和表格体中的行 表头背景 <view name=bg width=$once{parentwidth}… <view name=whitebg x= y=… 动态行 <view name=columns datapath=${parentdatapath} width=$once{parentwidth}> <simplelayout axis=y spacing=/> <view datapath=*… <text x= datapath=@id width=/> <text x= datapath=@name width=/> … </view> 第三步添加事件和滚动条 <text x= datapath=@status width= fgcolor=#ff> <method event=onclick> </method> <method event=onmouseover> </method> <method event=onmouseout> </method> </text> 滚动条 <scrollbar/> 最后完成的组件代码是 <class name=downloadgrid datapath= width= height=> <view name=bg width=$once{parentwidth} height=$once{parentheight} bgcolor=#/> <view name=whitebg x= y= width=$once{parentwidth} height=$once{parentheight} bgcolor=#FFFFFF/> <view name=header x= y= width=$once{parentwidth} height= bgcolor=#CEFA> <text x= text=ID /> <text x= text=名称 /> <text x= text=描述 /> <text x= text=分类/> <text x= text=链接 /> </view> <view name=rowcontainer x= y= datapath=${parentdatapath} width=$once{parentwidth} height=$once{parentheight} clip=true> <view name=columns datapath=${parentdatapath} width=$once{parentwidth}> <simplelayout axis=y spacing=/> <view datapath=* width=$once{parentwidth} height= bgcolor=#FFF> <text x= datapath=@id width=/> <text x= datapath=@name width=/> <text x= datapath=@describe width=/> <text x= datapath=@category width=/> <text x= datapath=@status width= fgcolor=#ff> <method event=onclick> var hashref = parentdatapathphasAttr(href) if(hashref){ var address = parentdatapathpgetAttr(href) LzBrowserloadURL(address _blank) } </method> <method event=onmouseover> thissetColor(x) </method> <method event=onmouseout> thissetColor(xFF) </method> </text> </view> </view> <scrollbar/> </view> </class> 总结 组件是laszlo应用的重要组成部分每次的项目开发都会涉及到组件的开发而且关系到项目产品的质量和效果这也是考验一个RIA开发人员水平的重要依据laszlo的demo中有很多值得研究的组件网上也有开发人员的作品供大家分享每次openlaszlo新版本的发布都会有新的组件添加进来这要感谢众多contributor的慷慨开源软件正是在这种开放的环境中不断成长起来的让我们写好laszlo组件共同促进RIA的发展 |