-
[XUL学习]出现wabtags.h的编译错误
这是我第二次编译Mozilla了,第一次首先是没有在我的VC6.0上安装SP5的包,结果到了一个Jpeg的地方报错。安装之后,编译继续。但最后出现了一个C1004错,是说wabtags.h文件有问题。原以为是我的环境有问题,没有细究,结果把Mozilla的源码删了,就没再编译。结果昨天我试着又编译了一次,仍然是报wabtags.h错,到网上查一查发现一篇文章:从一个微软的有意思的bug想到的,结果才发现,这个问题原来是VC本身的问题。在VC98的include目录下打开wabtags.h文件,结果发现有一些注释的结束*/变成了?/,全部改过来,保存再编译,终于成功了。
-
[XUL学习]XUL Tutorial(27) -- Adding Event Handlers
前面我们基本结束了界面生成部分,下面开始进入交互部分。
XUL的事件处理方式与HTML中的基本类似。对于需要响应事件的元素,只要在元素中增加相应的事件处理函数即可。如:
<menuitem label="Close" accesskey="c" oncommand="window.close();"/>
...
<button id="cancel-button" label="Cancel"
oncommand="window.close();"/>
这个例子并未使用自定义的函数,而是直接使用DOM对象的方法进行调用。对于自定义的方法可以在XUL文件中设置script元素,将代码放在script代码中即可。或者在script中设置src属性,指向javascript代码文件。在XUL中目前都是使用javascript来进行程序处理的。
基本可响应的事件可以看原教程。
事件模型
XUL使用与DOM2 Events描述的事件模型一样。(至于DOM2 事件模型到底怎么回事我也没仔细看过,如果需要再了解好了)简单地说,一个事件的发送有两个状态:捕获状态和冒泡状态。在捕获状态,一个事件先发送到document,然后按照元素的分级结构层层传递,直到触发事件的元素。冒泡状态是反方向传递。
在处理路径上,如果事件被某个元素处理,那么事件传递即结束,如果没有被处理,则继续传到下一个元素。如果都没有处理,则缺省的处理被执行。这就意味着,不一定要把事件处理放在触发事件的元素上,而是放在它的父元素中进行处理。
如果一个事件被处理,处理函数应该返回true,如果返回false则表示未被处理。因此,有时可以在处理了事件后,仍然返回false,从而使事件可以继续传递。
你可以使用event对象的target属性来得到触发事件的元素,如:
<window
onclick="alert(event.target.tagName); return false;"
.
.
.
>
当你在窗口中点击任何一个元素时,都会引发一个alert对话框,它将显示被点击的元素的名字。
-
[XUL学习]XUL Tutorial(26) -- Advanced Rules
模板可以让我们从RDF中自动生成需要的元素。当我们需要做特殊处理时,我们可以通过rule来进行不同的处理。那么前面我们学习了一些rule元素的使用,但那些其实都只是简写。完整的rule元素有三个子元素:conditions, bindings, action。
mozilla在处理的时候,模板生成器会先根据conditions中的条件对资源进行匹配,如果匹配成功,则调用相应的action中的内容进行复制处理。
条件
conditions元素是rule中用来进行匹配使用的条件,它有三个子元素:content, member, triple。
- content
只能写一次。它用来将包含模板的元素中的rel所指的起始根对应到一个变量中。如:<content uri="?var"/>
uri的属性值将对应rel中的根资源。?表示后面的标识符是一个变量。var是变量名,可以随便写。
- member
用来映射每条资源的变量。<tree id="citiesTree" datasources="weather.rdf"
ref="http://www.xulplanet.com/rdf/weather/cities">
<template>
<rule>
<conditions>
<content uri="?list"/>
<member container="?list" child="?city"/>
</conditions>
</rule>
</template>
</tree>
从本例可以看出list对应http://www.xulplanet.com/rdf/weather/cities。这样container对应list变量,child对应的值放在city变量中。那么content与member给我的感觉就是用来定义变量。content用来定义根变量,child用来定义每条资源。
triple
它是一个三元组,用来定义匹配规则。一个triple由三要素组成:主题(subject), 谓词(predicate), object(目标),这一点我们在讲RDF时讲过。不过这里使用triple是用来检查一条资源是否之定义的规则相匹配。
<conditions>
<content uri="?list"/>
<member container="?list" child="?city"/>
<triple subject="?city"
predicate="http://www.xulplanet.com/rdf/weather#prediction"
object="Cloud"/>
</conditions>
这里定义了一个triple,它用来检查一条资源的天气是否与目标相一致。主题就是city变量对应的资源,谓词就是http://www.xulplanet.com/rdf/weather#prediction,目标在这里就是"Cloud"。当目标是一个值时,那么做判断处理。但是当它设为一个变量时,如"?pred",那么处理时就是将对应的值放在pred变量中,同时判断它是否不为空。条件中可以放置多个triple。
那么conditions元素的作用一方面是进行条件的匹配,一方面是将相应的值放在变量中。不过现在还不清楚是否有更复杂的条件判断功能。
内容创建
在匹配成功后,生成器会自动调用action子元素中的内容进行处理。在action中你可以使用conditions中定义的变量。在rule的简单语法中,你使用uri="rdf:*"来指明内容应该从哪里生成。在全语法中,你应该设置uri为conditions中的变量。通常使用member元素中的child属性所对应的变量。下面是一个完整的例子:
<tree id="weatherTree" flex="1" datasources="weather.rdf"
ref="http://www.xulplanet.com/rdf/weather/cities">
<treecols>
<treecol id="city" label="City" primary="true" flex="1"/>
<treecol id="pred" label="Prediction" flex="1"/>
</treecols>
<template>
<rule>
<conditions>
<content uri="?list"/>
<member container="?list" child="?city"/>
<triple subject="?city"
predicate="http://www.xulplanet.com/rdf/weather#name"
object="?name"/>
<triple subject="?city"
predicate="http://www.xulplanet.com/rdf/weather#prediction"
object="?pred"/>
</conditions>
<action>
<treechildren>
<treeitem uri="?city">
<treerow>
<treecell label="?name"/>
<treecell label="?pred"/>
</treerow>
</treeitem>
</treechildren>
</action>
</rule>
</template>
</tree>
从例子我们可以看出,action元素中,uri="?city",而city是在member中的child属性对应的变量。treecell对应的值分别为"?name"和"?pred"。这个例子所对应的wheather.rdf文件在原教程中有,大家可以把它保存到自已的测试目录下,运行看一看。运行结果为:

从例子我们注意到这里没有设置flags="dont-build-content ",因此这例子的内容不是直接从RDF文件中得到的。如果我们设置flags="dont-build-content ",那么需要把上面的content元素改为treeitem。大家可以自行测试。
增加额外的绑定
bindings元素中可以定义多个binding元素,那么它的语法与triple很相似,主要的作用就是将信息与变量关联,如:
<bindings>
<binding subject="?city"
predicate="http://www.xulplanet.com/rdf/weather#temperature"
object="?temp"/>
</bindings>
那么它与triple不同之处就是不作判断处理。当指定的谓词不满足时,变量值为空。
-
[XUL学习]XUL Tutorial(25) -- RDF Datasources
Mozilla内置了一些数据源,它们与bookmarks相似,不过字段与可用的起始root可能有所区别。这里我不想多说了,看原教程吧。
那么我真正感兴趣的就是如何生成自已的RDF,但教程中并没有详细的介绍。考虑到RDF可以为列表和树之类的模板提供数据,那么它需要定义结点集,通过seq, bag, alt来定义。而真正的结点是通过description来定义的。这样一个RDF基本上需要定义两种东西:
- 表示结点集合的seq, bag, alt
- 表示结点的description
这样我们在使用这个RDF时,datasource即为这个RDF文件的URL,而rel为结点集的某个层次结点,如根结点或某个子结点。通过结点集就可以得到真正的结点数据。
从原教程所提供的RDF可以看出来,每种动物及分类都使用了一个description来定义,最后seq将分类与具体的动物结合起来。在使用模板时,就是从seq级别中选取某个层次作为起始的root进行处理。
不过XML这种格式的文件的确很冗长,如果没有好的工具来支持手工处理会很麻烦。
-
[XUL学习]XUL Tutorial(24) -- Trees and Templates
摘要:从前面我们了解了从RDF读取数据后,利用模板生成元素有两种生成器,一是内容生成器用于绝大多数元素;二就是树生成器只用于tree元素。下面我们就介绍树和它的模板。象同其它的元素一样,你需要在tree元素中加入datasource和rel两个属性。下面一个例子是把history作为数据源: (全文共3405字)——点击此处阅读全文
-
[XUL学习]XUL Tutorial(23) -- Templates
摘要:那么在前面我们学习了生成列表、树这样的元素的生成,但是手工生成的。其中我还谈到可以通过RDF来生成,这对于大量数据是一个很方便的方式。这些数据或者来源于RDF文件,或者来源于内部的数据源(datasource)。Mozilla提供了象bookmarks, history和邮件信息这样的数据源。 (全文共4577字)——点击此处阅读全文
-
[XUL学习]XUL Tutorial(22) -- Introduction to RDF
下面我们进入复杂的RDF知识的学习,说实在的,学了半天也只明白个大概,而且我还不能保证我理解得一定正确,因此建议大家多找资料学习,如果有心得一定分享一下啊。这里是一个链接,放在Mozilla中,它是一系列的文章。阅读这里
RDF介绍
什么叫RDF -- Resource Description Framework(资源描述框架)
它是用来做什么的呢?
我的理解就是描述资源之间关系用的一种模型。那么它的存储表示其实有多种,我们常用的是XML格式的表示,因此也称为RDF/XML。也就是说RDF与XML不是一个东西,而RDF/XML只是RDF的一种表示的格式。在RDF中有两种东西,一种是资源(resource),一种是文本(literal)。文本相当于具体的字符串,而资源相当于是一个抽象概念。那么RDF主要就用来描述由这两者对象构成的世界中个体的关系。
RDF怎么进行描述呢?它使用Triple方法,可以称为三元组的方法,它们是:主语(或主题)、谓语(或谓词)和宾语(或目标)。其中主语与宾语就是资源。而谓语是两个资源之间的关系。举一个例子:
<http://www.xulplanet.com/rdf/people/Sandra> -> name -> Sandra
这里<http://www.xulplanet.com/rdf/people/Sandra>就是resource,它使用URI的表示方法,它只是一个名字,怎么起都行,使用尖括号括起来。Sandra就是literal(文本)。name就是关系。上面的意思就是<http://www.xulplanet.com/rdf/people/Sandra>的名字叫Sandra。三者之间使用->连起来。当然这并不是XML文件,这只是一种表示triple关系的方法。那么RDF基本上就是通过这种三元表示法来描述资源之间的关系的。注意,因为泛泛的资源(Resource)与具体的类型(resource)单词一样,不好区分。这样在描述具体的资源的类型时我使用英文resource,在泛泛谈资源而不区分它的类型时我就用中文。
使用URI来表示resource并不表示在处理RDF时,要从相应的链接得到数据,它只是一个标识符。 如果在一个RDF中出现一样的URI,那就表示是同一个resource。使用triple可以表示从resource到literal和resource到resource的关系。有时,谓词也可以使用resource的表示方法。
有时我们需要表示一个对象是属于某一类的情况,即实例与类的关系,那么我们可以使用rdf:type这个谓词来定义实例与类的关系,如:
<http://www.xulplanet.com/rdf/people/Sandra> -> rdf:type ->
http://xmlns.com/wordnet/1.6/Person
上面就表示Sandra是一个Person。
有时我们还需要表示一类事物,把它们组织成列表。那么RDF提供了seq、bag、alt来定义。seq为顺序列表,bag为无序表,alt定义了多个备选值,但应该只有一个可用。
我不想在这里讲得过细了,让我们看一看在RDF/XML中的一些规范吧。
RDF/XML
前面我已经说过,RDF/XML只算是RDF的一种表示或方言,但也是我们常用的表示方法。针对上面我们所讲的资源表示与关系表示,我们分别举例来说明如何使用。
使用RDF/XML要按XML的要求声明XML的相应的头和名字空间:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:people="http://www.xulplanet.com/rdf/people/">
</rdf:RDF>
其它的内容就放在这里面。
resource到literal三元组
<rdf:Description rdf:about="http://www.xulplanet.com/rdf/people/Sandra"
people:name="Sandra"/>
可以看出,一个Description描述了一个三元组。resouce为它的rdf:about属性值。literal为people:name的属性值。而谓词就是people:name。这样我们了解了,在RDF/XML中三元组可以使用属性来描述。属性名可能表示资源的类型和关系。而属性值可能表示革resource的URI或literal的字符串。
因为一个resource可能与其它的资源之间有多个关系,那么可以把这些关系简单地写在一起,如:
<rdf:Description rdf:about="http://www.xulplanet.com/rdf/people/Sandra"
people:name="Sandra"
people:gender="female"/>
这实际上定义了两个关系,名字和性别关系。
resource到resource三元组
例如:
<rdf:Description rdf:about="http://www.xulplanet.com/rdf/people/Sandra"
people:name="Sandra">
<people:sibling rdf:resource="http://www.xulplanet.com/rdf/people/Kevin"/>
</rdf:Description>
这里面定义了两个关系,一个是people:name,还有一个是people:sibling。而rdf:resource定义的是目标resource。
从这里我们还可以看到,三元组还可以使用子元素来描述。而且多种关系也可以放在一起混合进行表示:有的用属性表示,有的用子元素进行表示。非常灵活。当然,尽可能以简洁清晰为好。
还要提醒的是rdf:about表示主题,而rdf:resource表示目标。
type关系
前面说了rdf:type表示实例与类之间的关系,就是一个实例是属于某个类别。例如:
<rdf:Description rdf:about="http://www.xulplanet.com/rdf/people/Sandra"
<rdf:type resource="http://xmlns.com/wordnet/1.6/Person"/>
</rdf:Description>
这里就不多说了。rdf:type是RDF内置的谓词。
列表类型关系
有三种列表形式:seq, bag, alt,举例如下:
<rdf:Seq rdf:about="http://www.xulplanet.com/rdf/people/KarensKids">
<rdf:_1 rdf:resource="http://www.xulplanet.com/rdf/people/Sandra"/>
<rdf:_2 rdf:resource="http://www.xulplanet.com/rdf/people/Kevin"/>
<rdf:_3 rdf:resource="http://www.xulplanet.com/rdf/people/Jack"/>
</rdf:Seq>
那么这里使用了rdf:_1来表示顺序。还有一种简化的方法就是把rdf:_1改为rdf:li,如:
<rdf:Seq rdf:about="http://www.xulplanet.com/rdf/people/KarensKids">
<rdf:li rdf:resource="http://www.xulplanet.com/rdf/people/Sandra"/>
<rdf:li rdf:resource="http://www.xulplanet.com/rdf/people/Kevin"/>
<rdf:li rdf:resource="http://www.xulplanet.com/rdf/people/Jack"/>
</rdf:Seq>
不过,你要是使用RDF Api的话你得不到li这个谓词,而你只能得到相应的数值。
由于Mozilla使用的RDF比较早,它与标准的处理有区别。一个就是about和resource属性不需要有rdf:的限定。另外就是对于rdf:type,在Mozilla是使用rdf:instanceOf。
-
[XUL学习]PyXPCOM在Windows下的安装经历
xpcom是Mozilla中的一种组件技术,它可以允许Javascript调动本地对象,以完成Javascript所不具备的功能。那么它也有一个 Python 绑定,叫PyXPCOM,它是由ActiveState(发布ActiveState Python的公司)开发的,现在源代码已经并入Mozilla中。访问地址
不过Mozilla并未在安装包中提供PyXPCOM的二进制包,因此,如果你想安装,那么要自已编译。(是真的吗?)这几天我尝试着编译Mozilla,但工具不全,因此一直还未成功。不过,在网上我发现一个叫mozpython的网站,它提供了一个叫MozPython的模块,可以在Mozilla中调用Python程序,不过我还是不清楚到底有什么用。因为它所演示的Python代码并不是嵌入到XUL页面中,而是独立的 Python 程序,它的执行结果要输出为HTML格式,然后供Mozilla进行显示。如果只把Mozilla当做 Python 代码的一个调用器还有点用,但现在我想实现的是用Python进行Mozilla的开发,象MozPython这样的效果想不出有什么用。希望Mozilla快点支持Python脚本的执行。不讲这个了,还是说PyXPCOM的下载吧。在MozPython的网站我发现了作者已经编译了几个版本,不过最新的是1.7版的。可以从这里下载。下载完的文件名是PyXPCOM_1.7_2.3_win32.zip。虽然版本有点低(我用的是1.7.5),但为了学习就无所谓了。怕有版本的问题,我还专门下载和安装了Mozilla 1.7版本。
安装PyXPCOM的经历并不轻松,安装说明在ActiveState网站上,可以阅读这里。不过它是从编译开始讲,我就只讲我是如何装的吧。
在讲述如何安装之前还要向大家交待一下:GRE。这里可不是出国考研要考的GRE英语。它是Gecko Runtime Environment的简称。Gecko就是Mozilla产品系统所用的引擎。那么大家可以读这篇文章来了解一下GRE的知识。那么它的作用就是将最小运行环境作为象Java的运行环境(JRE)一样的效果,公共的东西大家共享,这样可以减少安装所要的空间,便于维护。
安装XPCOM组件,有一个注册的步骤,就是要执行regxpcom.exe这个程序。但是在Mozilla 1.7下(它在Mozilla的安装目录下)如果你直接执行regxpcom.exe,那么很有可能不会成功,会报告:
Can not initialize XPCOM Glue
Can not aquire component registrar
这是为什么?我查了半天的资料(向大家提供一个邮件列表归档的网站很不错Mail Archive,其中我找到了mozilla.xpcom邮件列表)才大概明白,regxpcom.exe的执行需要有xpcom.dll才可以。但是在我的Mozilla安装目录下并没有。这是怎么回事,难到是Mozilla根本不包括这个东西吗?其实它就是放在GRE中的。那么这个GRE目录在我的机器上是:
C:\Program Files\Common Files\mozilla.org\GRE
它有一个子目录是跟版本相一致的。那么在这个目录下你会找到所有想要的东西。(我发现Mozilla越学东西越多,学习曲线是否有些太陡了吧。)那么把xpcom.dll所在的目录加入PATH环境变量中就可以了。在我的机器上是:
MOZ_GRE=C:\Program Files\Common Files\mozilla.org\GRE\1.7_2004061609
PATH=%PATH%;%MOZ_GRE%
那么regxpcom已经可以执行了。下一步就是把下载的PyXPCOM_1.7_2.3_win32.zip解压到上面这个目录下。那么因为PyXPCOM有Python代码,因此需要Python来执行,并且可以被Python进行调用。因此还要把解开后的python子目录加入到PYTHONPATH中。在我的机器上就是:
PYTHONPATH=%MOZ_GRE%\python
然后,我的做法是把Mozilla安装目录下的components子目录中的compreg.dat和xpti.dat文件删除。启动Mozilla,这样就会自动进行注册。这样就应该安装完毕了,剩下的找些例子试一试吧。
下面我小结一下:
- 如果不自行编译那么先要下载PyXPCOM
- 把GRE路径加进PATH中
- 解压PyXPCOM包到GRE目录中
- 把GRE的python目录加入到PYTHONPATH
- 删除Mozilla安装目录/components下的compreg.dat和xpti.dat文件
- 重启Mozilla
有些步骤也是多次试出来的,希望以后的Mozilla版本能够内置这一组件,简化操作。有问题欢迎交流。
-
[XUL学习]XUL Tutorial(21) -- Trees
XUL中的Tree元素是一种比较复杂的元素。它除了可以生成分级结构,而且还可以生成分级的列表结构。这在许多GUI中都是比较复杂的东西。象windows下的资源管理器,就只是树状结点,而不是分级列表。那么它既有分级的特性,又可以同时具备列表特性。不过,tree只能包括文本或图片,而不象列表可以包含任何元素。
有几种生成tree的方法,最简单、直接的就是直接生成tree的结点。其它的方法还可以使用数据源,利用模板来生成,这是后话。我们先学习简单的方法。
简单树
我们先不考虑分级的情况。先看一个例子:
<tree flex="1">
<treecols>
<treecol id="sender" label="Sender" flex="1"/>
<treecol id="subject" label="Subject" flex="2"/>
</treecols>
<treechildren>
<treeitem>
<treerow>
<treecell label="joe@somewhere.com"/>
<treecell label="Top secret plans"/>
</treerow>
</treeitem>
<treeitem>
<treerow>
<treecell label="mel@whereever.com"/>
<treecell label="Let's do lunch"/>
</treerow>
</treeitem>
</treechildren>
</tree>
- tree
用来生成树结构。可以指定rows属性来设置缺省显示的记录条数。如果不指定缺省为0。如果指定了flex属性,说明树是可变的,就不必再指定rows属性了。 - treecols
用来生成树的表头。相当于listbox当中listhead。 - treecol
用来生成表头列,这里定义了两列,同时定义的宽度的占比。 - treechildren
用来生成表格体。所有记录行都包含在这个标签内。 - treeitem
用来生成一条记录, 它可以包含用treerow表示的单行,也可以包含用treechildren表示的多行。 - treerow
用来定义一条记录,应该放在treeitem内。 - treecell
用来定义一条记录的某个字段。应该放在treerow内。
例子的效果为:

从上图我们可以看到,这个简单的tree与列表框差别不大,因为它没有分级。不过,当一列的内容显示不完全时,会采用chop方式来显示其中的元素。同时在表头的最右边还有一个按钮可以调整要显示的列。Mozilla已经为我们提供了许多好的特性。
如果你不想显示右上角的按钮(叫columnpicker),可以设置tree的hidecolumnpicker为"true"即可。不过要保证你已经设置了id属性。
此时用户可以在一个tree中进行多选(点击时按shift或ctrl键),如果不想允许多选,则可以把tree的single属性设为"true"即可。
分级树
分级树是通过在某个treeitem中嵌套treechildren来实现的。
- 在需要分级的treeitem元素中,设置containter属性为"true"。这样就允许用户可以通过双击来打开和关闭内部的行。通过设置open属性为"true"或"false",就可以设置初始状态下内部行的打开和关闭。
- 将表头中的主要列设置primary属性,这样就可能在有分级情况的这一列单元格的前面显示一个小三角或加号。一旦某列被设为primary,用户是无法关闭的。
- 在某个需要分级的treeitem中嵌入treechildren元素。注意不要放在treerow中,那样做无效。
下面是一个分级树的例子:
<tree flex="1">
<treecols>
<treecol id="firstname" label="First Name" primary="true" flex="3"/>
<treecol id="lastname" label="Last Name" flex="7"/>
</treecols>
<treechildren>
<treeitem container="true" open="true">
<treerow>
<treecell label="Guys"/>
</treerow>
<treechildren>
<treeitem>
<treerow>
<treecell label="Bob"/>
<treecell label="Carpenter"/>
</treerow>
</treeitem>
<treeitem>
<treerow>
<treecell label="Jerry"/>
<treecell label="Hodge"/>
</treerow>
</treeitem>
</treechildren>
</treeitem>
</treechildren>
</tree>
其中红字是我们要注意的。从上面蓝色背景的代码可以看出,只定义了第一个字段。如果第二个字段不定义则为空。定义也是可以的。
执行效果为:

上面的例子是把第一列设为primary,你也可以把其它列设为primary。这样小三角或加号就显示在相应的列上。可以试一试,很有趣。
其它特性
如果设置tree元素的enableColumnDrag,则用户可以拖拽表格头重新安装每列的顺序。
如果想改变列的宽度,你可以在表头处的每个treecol之间放置一个splitter。这样一个小条就会出现的每列之间。然后你还可以使用CSS来设置splitter的max-width样式为0,这样,小条就看不见了,但你仍然可以拖拽。你也可以使用全局CSS样式类tree-splitter来实现这一目的。
你可以在treecol中设置hidden属性为"true"来初始显示时隐藏某一列。用户可以通过修改clumnpicker来显示隐藏列。
好,让我们继续完善findfile.xul,加入如下代码:
<tree flex="1">
<treecols>
<treecol id="name" label="Filename" flex="1"/>
<treecol id="location" label="Location" flex="2"/>
<treecol id="size" label="Size" flex="1"/>
</treecols>
<treechildren>
<treeitem>
<treerow>
<treecell label="mozilla"/>
<treecell label="/usr/local"/>
<treecell label="2520 bytes"/>
</treerow>
</treeitem>
</treechildren>
</tree>
<splitter collapse="before" resizeafter="grow"/>
红色部分将替换掉iframe元素。splitter也增加了collapse属性。运行效果为:

-
[XUL学习]XUL Tutorial(20) -- More Listbox Features
列表框使用listbox元素,还记得吗?看到这里我的确已经忘了,看来学习与熟练区别很大。那么它除了生成单列的列表框,还可以生成多列的列表框。在内部是通过grid来实现的,但列表框有自已的元素标签,还是有一些区别的。列表框中的每个单元可以放置任何元素,不过通常只是用来放置文本。
下面是一个列子:
<listbox>
<listcols>
<listcol flex="1"/>
<listcol flex="2"/>
</listcols>
<listitem>
<listcell label="George"/>
<listcell label="House Painter"/>
</listitem>
<listitem>
<listcell label="Mary Ellen"/>
<listcell label="Candle Maker"/>
</listitem>
<listitem>
<listcell label="Roger"/>
<listcell label="Swashbuckler"/>
</listitem>
</listbox>
它生成二列三行的一个列表。类似grid,listcols用来定义列字段集。listcol用来定义每列的外观,这里定义了第一列的宽度是第二列的一半。它没有rows这样的行记录集的定义,直接使用listitem定义一行(单列列表框就是使用这个元素来定义每一行的),而每个单元使用listcell来定义。
上面的例子如果你运行,你会发现它没有表头。
如果想要表头,使用listhead和listheader来定义表头。例如:
<listbox>
<listhead>
<listheader label="Name"/>
<listheader label="Occupation"/>
</listhead>
<listcols>
<listcol flex="1"/>
<listcol flex="2"/>
</listcols>
<listitem>
<listcell label="George"/>
<listcell label="House Painter"/>
</listitem>
<listitem>
<listcell label="Mary Ellen"/>
<listcell label="Candle Maker"/>
</listitem>
<listitem>
<listcell label="Roger"/>
<listcell label="Swashbuckler"/>
</listitem>
</listbox>
运行效果为:
