<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Power by Result Search &#187; extjs</title>
	<atom:link href="http://www.result-search.com/sty/category/technology/extjs/feed" rel="self" type="application/rss+xml" />
	<link>http://www.result-search.com/sty</link>
	<description>Just another weblog</description>
	<lastBuildDate>Wed, 23 Jun 2010 03:12:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ext2.0简明教程 第 2 章 震撼吧！让你知道ext表格控件的厉害。</title>
		<link>http://www.result-search.com/sty/2009/04/23/ext20-getting-start-the-ext-table-widget.html</link>
		<comments>http://www.result-search.com/sty/2009/04/23/ext20-getting-start-the-ext-table-widget.html#comments</comments>
		<pubDate>Thu, 23 Apr 2009 06:28:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[extjs]]></category>

		<guid isPermaLink="false">http://www.yaaahaaa.com/2009/04/23/ext20%e7%ae%80%e6%98%8e%e6%95%99%e7%a8%8b-%e7%ac%ac-2-%e7%ab%a0-%e9%9c%87%e6%92%bc%e5%90%a7%ef%bc%81%e8%ae%a9%e4%bd%a0%e7%9f%a5%e9%81%93ext%e8%a1%a8%e6%a0%bc%e6%8e%a7%e4%bb%b6%e7%9a%84%e5%8e%89/</guid>
		<description><![CDATA[2.1. 功能丰富，无人能出其右
无论是界面之美，还是功能之强，ext的表格控件都高居榜首。
单选行，多选行，高亮显示选中的行，推拽改变列宽度，按列排序，这些基本功能咱们就不提了。
自动生成行号，支持checkbox全选，动态选择显示哪些列，支持本地以及远程分页，可以对单元格按照自己的想法进行渲染，这些也算可以想到的功能。
再加上可编辑grid，添加新行，删除一或多行，提示脏数据，推拽改变grid大小，grid之间推拽一或多行，甚至可以在tree和grid之间进行拖拽，啊，这些功能实在太神奇了。更令人惊叹的是，这些功能竟然都在ext表格控件里实现了。
呵呵~不过ext也不是万能的，与fins的ecside比较，ext不能锁定列（土豆说1.x里支持锁定列，但是2.0里没有了，因为影响效 率。），也没有默认的统计功能，也不支持excel，pdf等导出数据。另外fins说，通过测试ecside的效率明显优于ext呢。:)




2.2. 让我们搞一个grid出来耍耍吧。



光说不练不是我们的传统，让我们基于examples里的例子，来自己搞一个grid看看效果，同时也可以知道一个grid到底需要配置些什么东西。


首先我们知道表格肯定是二维的，横着叫行，竖着叫列。跟设计数据库，新建表一样，我们要先设置这个表有几列，每列叫啥名字，啥类型，咋显示，这个表格的骨架也就出来了。ext里，这个列的定义，叫做ColumnModel，简称cm的就是它，它作为整个表格的列模型，是要首先建立起来的。
这里我们建立一个三列的表格，第一列叫编号(code)，第二列叫名称(name)，第三列叫描述(descn)。
var cm = new Ext.grid.ColumnModel([
    {header:'编号',dataIndex:'id'},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);
看到了吧？非常简单的定义了三列，每列的header表示这列的名称，dataIndex是跟后面的东西对应的，咱们暂且不提。现在只要知道有了三列就可以了。
有了表格的骨架，现在我们要向里边添加数据了。这个数据当然也是二维了，为了简便，我们学习examples里的array-grid.js里的方式，把数据直接写到js里。
var data = [
    ['1','name1','descn1'],
    ['2','name2','descn2'],
    ['3','name3','descn3'],
    ['4','name4','descn4'],
    ['5','name5','descn5']
];
很显然，我们这里定义了一个二维数据， （什么？你不知道这是二维数组？快改行吧，这里不是你该待的地方。）
这个有五条记录的二维数组，显示到grid里就应该是五行，每行三列，正好对应这id,name,descn，在我们的脑子里应该可以想像出grid显示的结果了，为了让想像变成显示，我们还需要对原始数据做一下转化。
因 为咱们希望grid不只能支持array，还可以支持json，支持xml，甚至支持咱们自己定义的数据格式，ext为咱们提供了一个桥 梁，Ext.data.Store，通过它我们可以把任何格式的数据转化成grid可以使用的形式，这样就不需要为每种数据格式写一个grid的实现了。 现在咱们就来看看这个Ext.data.Store是如何转换array的。
var ds = new Ext.data.Store({
    proxy: [...]]]></description>
			<content:encoded><![CDATA[<h2 class="title" style="clear: both;">2.1. 功能丰富，无人能出其右</h2>
<p>无论是界面之美，还是功能之强，ext的表格控件都高居榜首。</p>
<p>单选行，多选行，高亮显示选中的行，推拽改变列宽度，按列排序，这些基本功能咱们就不提了。</p>
<p>自动生成行号，支持checkbox全选，动态选择显示哪些列，支持本地以及远程分页，可以对单元格按照自己的想法进行渲染，这些也算可以想到的功能。</p>
<p>再加上可编辑grid，添加新行，删除一或多行，提示脏数据，推拽改变grid大小，grid之间推拽一或多行，甚至可以在tree和grid之间进行拖拽，啊，这些功能实在太神奇了。更令人惊叹的是，这些功能竟然都在ext表格控件里实现了。</p>
<p>呵呵~不过ext也不是万能的，与fins的ecside比较，ext不能锁定列（土豆说1.x里支持锁定列，但是2.0里没有了，因为影响效 率。），也没有默认的统计功能，也不支持excel，pdf等导出数据。另外fins说，通过测试ecside的效率明显优于ext呢。:)</p>
<div class="sect1">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both;"><a name="d0e212"></a>2.2. 让我们搞一个grid出来耍耍吧。</h2>
</div>
</div>
</div>
<p>光说不练不是我们的传统，让我们基于examples里的例子，来自己搞一个grid看看效果，同时也可以知道一个grid到底需要配置些什么东西。</p>
<div class="orderedlist">
<ol type="1">
<li>首先我们知道表格肯定是二维的，横着叫行，竖着叫列。跟设计数据库，新建表一样，我们要先设置这个表有几列，每列叫啥名字，啥类型，咋显示，这个表格的骨架也就出来了。ext里，这个列的定义，叫做ColumnModel，简称cm的就是它，它作为整个表格的列模型，是要首先建立起来的。
<p>这里我们建立一个三列的表格，第一列叫编号(code)，第二列叫名称(name)，第三列叫描述(descn)。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    {header:'编号',dataIndex:'id'},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<p>看到了吧？非常简单的定义了三列，每列的header表示这列的名称，dataIndex是跟后面的东西对应的，咱们暂且不提。现在只要知道有了三列就可以了。</li>
<li>有了表格的骨架，现在我们要向里边添加数据了。这个数据当然也是二维了，为了简便，我们学习examples里的array-grid.js里的方式，把数据直接写到js里。
<pre class="programlisting">var data = [
    ['1','name1','descn1'],
    ['2','name2','descn2'],
    ['3','name3','descn3'],
    ['4','name4','descn4'],
    ['5','name5','descn5']
];</pre>
<p>很显然，我们这里定义了一个二维数据， <span class="emphasis"><em>（什么？你不知道这是二维数组？快改行吧，这里不是你该待的地方。）</em></span></p>
<p>这个有五条记录的二维数组，显示到grid里就应该是五行，每行三列，正好对应这id,name,descn，在我们的脑子里应该可以想像出grid显示的结果了，为了让想像变成显示，我们还需要对原始数据做一下转化。</li>
<li>因 为咱们希望grid不只能支持array，还可以支持json，支持xml，甚至支持咱们自己定义的数据格式，ext为咱们提供了一个桥 梁，Ext.data.Store，通过它我们可以把任何格式的数据转化成grid可以使用的形式，这样就不需要为每种数据格式写一个grid的实现了。 现在咱们就来看看这个Ext.data.Store是如何转换array的。
<pre class="programlisting">var ds = new Ext.data.Store({
    proxy: new Ext.data.MemoryProxy(data),
    reader: new Ext.data.ArrayReader({}, [
        {name: 'id'},
        {name: 'name'},
        {name: 'descn'}
    ])
});
ds.load();</pre>
<p>ds要对应两个部分：proxy和reader。proxy告诉我们从哪里获得数据，reader告诉我们如何解析这个数据。</p>
<p>现在我们用的是Ext.data.MemoryProxy，它是专门用来解析js变量的。你可以看到，我们直接把data作为参数传递进去了。</p>
<p>Ext.data.ArrayReader 专门用来解析数组，并且告诉我们它会按照定义的规范进行解析，每行读取三个数据，第一个叫id，第二个叫 name，第三个descn。是不是有些眼熟，翻到前面cm定义的地方，哦，原来跟dataIndex是对应的。这样cm就知道哪列应该显示那条数据了。 唉，你要是能看明白这一点，那你实在是太聪明了。</p>
<p>记得要执行一次ds.load()，对数据进行初始化。</p>
<p>有兄弟可能要问了，要是我第一列数据不是id而是name，第二列数据不是name而是id咋办？嗯，嗯，这个使用就用mapping来解决。改改变成这样：</p>
<pre class="programlisting">var ds = new Ext.data.Store({
    proxy: new Ext.data.MemoryProxy(data),
    reader: new Ext.data.ArrayReader({}, [
        {name: 'id', mapping: 1},
        {name: 'name', mapping: 0},
        {name: 'descn', mapping: 2}
    ])
});</pre>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-01a.png" alt="" align="middle" /></div>
<p>这样如截图所见，id和name两列的数据翻转了。如此这般，无论数据排列顺序如何，我们都可以使用mapping来控制对应关系，唯一需要注意的是，索引是从0开始的，所以对应第一列要写成mapping:0，以此类推。</li>
<li>哈哈，万事俱备只欠东风，表格的列模型定义好了，原始数据和数据的转换都做好了，剩下的只需要装配在一起，我们的grid就出来了。
<pre class="programlisting">var grid = new Ext.grid.Grid('grid', {
    ds: ds,
    cm: cm
});
grid.render();</pre>
<p>注意：上头是ext-1.x的写法，Ext.grid.Grid的第一个参数是渲染的id，对应在html里应该有一个 &lt;div id=&#8221;grid&#8221;&gt;&lt;/div&gt;的东西，这样grid才知道要把自己画到哪里。</p>
<p>创建完grid以后，还要用grid.render()方法，让grid开始渲染，这样才能显示出来。</li>
<li>好了，把所有代码组合到一起，看看效果吧。
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
        {header:'编号',dataIndex:'id'},
        {header:'名称',dataIndex:'name'},
        {header:'描述',dataIndex:'descn'}
    ]);

    var data = [
        ['1','name1','descn1'],
        ['2','name2','descn2'],
        ['3','name3','descn3'],
        ['4','name4','descn4'],
        ['5','name5','descn5']
    ];

    var ds = new Ext.data.Store({
        proxy: new Ext.data.MemoryProxy(data),
        reader: new Ext.data.ArrayReader({}, [
            {name: 'id'},
            {name: 'name'},
            {name: 'descn'}
        ])
    });
    ds.load();

    var grid = new Ext.grid.Grid('grid', {
        ds: ds,
        cm: cm
    });
    grid.render();</pre>
<p>看看吧，这就是咱们搞出来的grid了。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-01.png" alt="" align="middle" /></div>
</li>
</ol>
</div>
<p>html例子是lingo-sample/1.1.1目录下的02-01.html，把这个目录copy到ext-1.x的example目录下，就可以直接打开观看效果。</p></div>
<div class="sect1">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both;"><a name="d0e287"></a>2.3. 上边那个是1.x的，2.0稍微有些不同哦</h2>
</div>
</div>
</div>
<p>首先，Ext.grid.Grid已经不见了，咱们需要用Ext.grid.GridPanel。需要传递的参数也有少许区别。</p>
<pre class="programlisting">var grid = new Ext.grid.GridPanel({
    el: 'grid',
    ds: ds,
    cm: cm
});</pre>
<p>看到了吗？负责指定渲染位置的id放到了{}里边，对应的名字是el。似乎ext2里对这些参数进行了统一，比以前更整齐了。</p>
<p>因为其他地方都一样，我就不多说了，html例子在是lingo-sample/2.0目录下的02-01.html。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-02.png" alt="" align="middle" /></div>
<p>从截图上看，少了斑马条，下边多了一条线，应该只是css有所不同吧。</p>
<p>默认情况下，两个版本的grid都可以拖拽列，也可以改变列的宽度。不知道怎么禁用这两个功能呢。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-03.png" alt="" align="middle" /></div>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-04.png" alt="" align="middle" /></div>
<p>最大的不同应该是1.x里默认支持的右键效果，在2.0里不见了。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-05.png" alt="" align="middle" /></div>
<p>按shift和ctrl多选行的功能倒是都有。区别是，全选后，1.x必须按住ctrl才能取消，直接单击其中一个行，不会取消全选功能，而2.0里只需要任意点击一行，就取消全选，只选中刚才点击的那行。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-06.png" alt="" align="middle" /></div>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-07.png" alt="" align="middle" /></div>
<p>哦，哦，那颜色不要也算是区别吧。</p></div>
<div class="sect1">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both;"><a name="d0e338"></a>2.4. 按顺序，咱们先要把常见功能讲到，让grid支持按列排序</h2>
</div>
</div>
</div>
<p>其实很简单，需要小小改动一下列模型。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    {header:'编号',dataIndex:'id',sortable:true},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<p>如果你英语还可以，或者懂得查字典的话（软件翻译也算），那么你就会知道，多出来的这个sortable属性应该是可以排序的意思。现在咱们试一下改动后的效果。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-08.png" alt="" align="middle" /></div>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-09.png" alt="" align="middle" /></div>
<p>看到了没有？编号的标题上有个小小的箭头，表格里的数据也是按照编号做的逆序排列，如此简单，我们就实现了按列排序。</p>
<p>很有趣的是，2.0加上sortable以后，1.x那种右键功能也跑回来了，不过它用的不是右键，而是下拉菜单似的实现方式。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-10.png" alt="" align="middle" /></div>
<p>什么？你问为什么其他两列无法排序？！嗯，好像是因为你还没有给另两列添加sortable属性。</p>
<p>怎么加？！按编号那样加就行了。</p>
<p>还是不会？！-_-。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    {header:'编号',dataIndex:'id',sortable:true},
    {header:'名称',dataIndex:'name',sortable:true},
    {header:'描述',dataIndex:'descn',sortable:true}
]);</pre>
<p>这样所有列都可以排序了。什么？怎么取消排序？！-_-。</p></div>
<div class="sect1">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both;"><a name="d0e376"></a>2.5. 让单元格里显示红色的字，图片，按钮，你还能想到什么？</h2>
</div>
</div>
</div>
<p>嘿，希望你跟我一样，不愿意只能在grid里看到文字，至少不是单调的，毫无特色的文字。有些人就问了，如果我想改变一下单元格里显示内容，应该怎么办呢？</p>
<p>非常不幸的是，ext的作者，伟大的jack早已经想到了，说真的，你没想到的，他都想到了，不只想到了，他还做出来了。</p>
<p>唉，这就是区别啊。为啥你就不能动手做些东西呢？就知道向别人要这要那，唉。</p>
<p>首先，我宣布，偶们的数据要扩充啦，每个人要加上一个性别字段。</p>
<pre class="programlisting">var data = [
    ['1','male','name1','descn1'],
    ['2','female','name2','descn2'],
    ['3','male','name3','descn3'],
    ['4','female','name4','descn4'],
    ['5','male','name5','descn5']
];</pre>
<p>男女搭配，干活不累撒。而且现在中国就是男多女少，我就还没对象呢。征婚中，单身女性加(QQ)771490531详谈。<strong>(不是我。。。。是这篇文章作者。。。）</strong></p>
<p>你可以试试不改其他的部分，显示的结果是不会改变的，因为原始数据要经过ds的处理才能被grid使用，那么下一步我们就开始修改ds，把性别加进去。</p>
<pre class="programlisting">var ds = new Ext.data.Store({
    proxy: new Ext.data.MemoryProxy(data),
    reader: new Ext.data.ArrayReader({}, [
        {name: 'id'},
        {name: 'sex'},
        {name: 'name'},
        {name: 'descn'}
    ])
});</pre>
<p>添加了一行{name: &#8217;sex&#8217;}，把数组的第二列映射为性别。现在grid可以感觉到sex了，嘿嘿。</p>
<p>不过grid还显示不了性别这列，因为咱们还没改cm。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    {header:'编号',dataIndex:'id'},
    {header:'性别',dataIndex:'sex'},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<p>到现在其实都没什么新东西，但是你不觉得光看平板字，很难分出哪个是GG哪个是MM吗？听说过红男绿女没？要是男的都加上红色，女的都变成绿色，那不是清楚多了。就像下面一样。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-11.png" alt="" align="middle" /></div>
<p>怎么样？是不是效果大不同了。你不会认为很难吧，嗯，确实，如果你对html和css完全搞不明白的话，劝你还是先去学学吧，对自己有信心的往下看。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    {header:'编号',dataIndex:'id'},
    {header:'性别',dataIndex:'sex',renderer:function(value){
            if (value == 'male') {
                return "&lt;span style='color:red;font-weight:bold;'&gt;红男&lt;/span&gt;";
            } else {
                return "&lt;span style='color:green;font-weight:bold;'&gt;绿女&lt;/span&gt;";
            }
        }},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<p>别被吓到，这么一大段其实就是判断是男是女，然后配上颜色。你要是觉得乱，也可以这么做。</p>
<pre class="programlisting">function renderSex(value) {
    if (value == 'male') {
        return "&lt;span style='color:red;font-weight:bold;'&gt;红男&lt;/span&gt;";
    } else {
        return "&lt;span style='color:green;font-weight:bold;'&gt;绿女&lt;/span&gt;";
    }
}
var cm = new Ext.grid.ColumnModel([
    {header:'编号',dataIndex:'id'},
    {header:'性别',dataIndex:'sex',renderer:renderSex},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<p>实际上这个renderer属性至关重要，它的值是一个function，哦，你说不知道js里function可以这么用？那么恭喜你，现在你知道了。</p>
<p>renderer会传递个参数进去，咱们grid里看到的，是这个函数的返回值，怎么样，神奇吧？</p>
<p>同志们，你们也应该看到了，返回html就可以，是html啊，html里有的东西，你返回什么就显示什么，颜色，链接，图片，按钮，只要你愿意，整个网页都可以返回回去。还有什么做不到的？哦，你不会html，那没辙，回去学吧。</p>
<p>咱们先来个图片。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-12.png" alt="" align="middle" /></div>
<pre class="programlisting">function renderSex(value) {
    if (value == 'male') {
        return "&lt;span style='color:red;font-weight:bold;'&gt;红男&lt;/span&gt;&lt;img src='user_male.png' /&gt;";
    } else {
        return "&lt;span style='color:green;font-weight:bold;'&gt;绿女&lt;/span&gt;&lt;img src='user_female.png' /&gt;";
    }
}</pre>
<p>是不是太简单了，下面咱们来玩点儿高级的。</p>
<pre class="programlisting">function renderDescn(value, cellmeta, record, rowIndex, columnIndex, store) {
    var str = "&lt;input type='button' value='查看详细信息' onclick='alert(\"" +
        "这个单元格的值是：" + value + "\\n" +
        "这个单元格的配置是：{cellId:" + cellmeta.cellId + ",id:" + cellmeta.id + ",css:" + cellmeta.css + "}\\n" +
        "这个单元格对应行的record是：" + record + "，一行的数据都在里边\\n" +
        "这是第" + rowIndex + "行\\n" +
        "这是第" + columnIndex + "列\\n" +
        "这个表格对应的Ext.data.Store在这里：" + store + "，随便用吧。" +
        "\")'&gt;";
    return str;
}</pre>
<p>来看看我们可以在render里用到多少参数：</p>
<div class="orderedlist">
<ol type="1">
<li>value是当前单元格的值</li>
<li>cellmeta里保存的是cellId单元格id，id不知道是干啥的，似乎是列号，css是这个单元格的css样式。</li>
<li>record是这行的所有数据，你想要什么，record.data["id"]这样就获得了。</li>
<li>rowIndex是行号，不是从头往下数的意思，而是计算了分页以后的结果。</li>
<li>columnIndex列号太简单了。</li>
<li>store，这个厉害，实际上这个是你构造表格时候传递的ds，也就是说表格里所有的数据，你都可以随便调用，唉，太厉害了。</li>
</ol>
</div>
<p>有个同学就问啦：EXT render的参数，是如何得到的呢。因为你讲的那些都是EXT自己内部的。它是如何把这些参数传递给render的呢？</p>
<p>这个问题其实比较简单，只是你们想复杂了。既然是函数，就肯定有调用它的地方，你找到GridView.js在里边搜索一下renderer，就会看到调用render的地方，这些参数都是在这里传进去的。</p>
<p>好，看看效果吧。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-13.png" alt="" align="middle" /></div>
<p>剩下的，就是发挥各位聪明才智的时候了，舞台已经搭好，看你如何表演了。</p>
<p>html例子，1.x版本在lingo-sample/1.1.1目录下的02-02.html，2.0的版本在lingo-sample/2.0目录下的02-02.html。</p></div>
<div class="sect1">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both;"><a name="d0e471"></a>2.6. 更进一步，自动行号和多选checkbox</h2>
</div>
</div>
</div>
<p>实际上行号和多选checkbox都是renderer的延伸，当然多选checkbox更酷一点儿，两者经常一起使用，所以让我们放在一起讨论好了。</p>
<div class="sect2">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="d0e476"></a>2.6.1. 自动行号</h3>
</div>
</div>
</div>
<p>只需要在cm中加上一行，这一行不会与ds中的任何数据对应，这也告诉我们可以凭空制作列，哈哈。</p>
<p>在之前的例子上改啦。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    {header:'NO.',renderer:function(value, cellmeta, record, rowIndex){
        return rowIndex + 1;
    }},
    {header:'编号',dataIndex:'id'},
    {header:'性别',dataIndex:'sex'},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<p>如吾等所愿，不指定dataIndex，而是直接根据renderer返回rowIndex + 1，因为它是从0开始的，所以加个一。截图如下。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-14.png" alt="" align="middle" /></div>
<p>1.x的例子在lingo-sample/1.1.1/02-03.html</p>
<p>很遗憾的是，2.0里有自己的默认实现了，咱们不能展现自己的手工技艺了，还是乖乖使用jack提供的东东吧。</p>
<p>于是，在2.0里cm就变成了这幅模样。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    new Ext.grid.RowNumberer(),
    {header:'编号',dataIndex:'id'},
    {header:'性别',dataIndex:'sex'},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<p>你绝对会同意我的意见，Jack&#8217;s work is amazing.实在是太神奇了。看看截图就知道。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-15.png" alt="" align="middle" /></div>
<p>2.0的例子在lingo-sample/2.0/02-03.html</p></div>
<div class="sect2">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="d0e509"></a>2.6.2. 全选checkbox的时间了，请允许我让2.0先上场。</h3>
</div>
</div>
</div>
<p>因为2.0里有checkboxSelectionModel，这样完全可以证实用别人的轮子，比自己造轮子要方便。而且咱们造的轮子完全没有jack圆。不信的话，看下面1.x里的实现。</p>
<p>我们一直在修改cm，这次我们也要对它动刀了，不过SelectionModel既sm也要处理一下，这是为了改变单选和多选行的方式，以前这些可以靠shift或ctrl实现，而现在这些都要与checkbox关联上了。</p>
<p>啦啦啦，先看图片，后看代码。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-16.png" alt="" align="middle" /></div>
<p>先看看具体多了什么</p>
<pre class="programlisting">var sm = new Ext.grid.CheckboxSelectionModel();</pre>
<p>神奇的是这个sm身兼两职，使用的时候既要放到cm里，也要放到grid中。代码如下。</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    new Ext.grid.RowNumberer(),
    sm,
    {header:'编号',dataIndex:'id'},
    {header:'性别',dataIndex:'sex'},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);

var grid = new Ext.grid.GridPanel({
    el: 'grid',
    ds: ds,
    cm: cm,
    sm: sm
});</pre>
<p>然后你就可以得到效果啦，代码在lingo-sample/2.0/02-04.html。</p></div>
<div class="sect2">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="d0e533"></a>2.6.3. 1.x时代的全选checkbox。</h3>
</div>
</div>
</div>
<p>理论上只需要给cm再加一列，像自动编号那样，不对应数据，只显示checkbox就可以了。难点就是checkbox与某一行被选择的时候要对应上，用checkbox选择上，sm里也要让这一行被选中，反之亦然。嗯，估计会比较复杂呢。</p>
<p>先放上显示checkbox的代码和截图：</p>
<pre class="programlisting">var cm = new Ext.grid.ColumnModel([
    {header:'NO.',renderer:function(value, cellmeta, record, rowIndex){
        return rowIndex + 1;
    }},
    {header:'&lt;input type="checkbox" onclick="selectAll(this)"&gt;',renderer:function(value, cellmeta, record, rowIndex){
        return '&lt;input type="checkbox" name="cb"&gt;';
    }},
    {header:'编号',dataIndex:'id'},
    {header:'性别',dataIndex:'sex'},
    {header:'名称',dataIndex:'name'},
    {header:'描述',dataIndex:'descn'}
]);</pre>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-17.png" alt="" align="middle" /></div>
<p>与sm对接的方面比较麻烦，好在extjs.com上已经有扩展了，或者你可以看看我们弄下来的。 <a href="http://203.93.254.59:8889/extdoc/html/ext-ch-09.html#anchor.chapter09.01">看看1.x多选树的截图。</a></div>
</div>
<div class="sect1">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both;"><a name="ext-ch-02-07"></a>2.7. 分页了吗？分页了吗？如果还没分就看这里吧。</h2>
</div>
</div>
</div>
<p>如果你有一千条信息，一次都输出到grid里，然后让客户用下拉条一点儿一点儿去找吧。我们这里可是要做一个分页效果了，不用滚动屏幕，或者滚动一下就可以看到本页显示的数据，如果想看其他的只需要翻页就可以了。同志们，加强客户体验呀。</p>
<p>实际上，grid控件挺耗性能的，据土豆讲一个页面上放3个grid就可以感觉到响应变慢，以前看过介绍，grid里显示数据过多，听说是上千条，也会明显变慢。</p>
<p>所以说分页是必不可少滴，而且jack提供了方便集成分页工具条的方式，不用一下实在是太浪费了。</p>
<p>两步走，让grid集成分页。</p>
<div class="sect2">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="d0e562"></a>2.7.1. 表面工作，先把分页工具条弄出来。</h3>
</div>
</div>
</div>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-18.png" alt="" align="middle" /></div>
<p>从图片可以清晰的看到，在grid下边多出来一行东东，包括了前一页，后一页，第一页，最后一页，刷新，以及提示信息。而我们不过写了如下几行代码而已，神奇呀。</p>
<pre class="programlisting">var gridFoot = grid.getView().getFooterPanel(true);

var paging = new Ext.PagingToolbar(gridFoot, ds, {
    pageSize: 10,
    displayInfo: true,
    displayMsg: '显示第 {0} 条到 {1} 条记录，一共 {2} 条',
    emptyMsg: '没有记录'
});</pre>
<p>首先使用grid.getView().getFootPanel(true)，获得grid下边那一条，嘿嘿，人家grid就设计的这么好，脚底下专门留了地方让你放东西。我们老实不客气，把Ext.PagingToolbar放到上边，就可以显示分页工具条了。</p>
<p>这分页工具条可不是个摆设，你按了前一页，后一页，整个grid都要有反应才对，要不咱们费劲弄这个么东西过来干嘛呀？所以，我们在构造 PagingToolbar的时候，不但告诉它，在gridFoot上显示，还告诉它，进行分页跳转的时候，要对ds也进行操作。这个ds就是grid用 来获取和显示数据的，它一变整个grid都发生变化，嘿嘿~这就算共享数据模型了。厉害呀。</p>
<p>知道了分页的玄机，让我们揉揉眼睛，好好看看里边的参数。</p>
<div class="orderedlist">
<ol type="1">
<li>pageSize，是每页显示几条数据。</li>
<li>displayInfo，跟下面的配置有关，如果是false就不会显示提示信息。</li>
<li>displayMsg，只有在displayInfo:true的时候才有效，用来显示有数据的时候的提示信息，中国人应该看得懂汉语，到时候{0},{1},{2}会自动变成对应的数据，咱们只需要想办法把话说通就行了。</li>
<li>emptyMsg，要是没数据就显示这个，jack实在太贴心了，连这些小处都考虑得如此精细。</li>
</ol>
</div>
<p>最好要注意的是，这段代码必须放在grid.render()之后，估计是因为动态生成grid的dom后，才能获得对应的footPanel。</p>
<p>现在给出例子，1.x的例子在lingo-sample/1.1.1/02-05.html。</p></div>
<div class="sect2">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="d0e597"></a>2.7.2. 2.0赐予我们更大的灵活性</h3>
</div>
</div>
</div>
<p>其实，在下，一直，对于：必须先渲染grid才能获得footPanel这事非常愤恨，你想啊，本来分页也应该属于初始化的一部分，现在却要先初始化grid，配置完毕，渲染，回过头来再从grid里把footPanel拿出来，再咕哝分页的配置。真，真，真郁闷呀。</p>
<p>所以2.0里的方式，简直大快民心。</p>
<pre class="programlisting">var grid = new Ext.grid.GridPanel({
    el: 'grid',
    ds: ds,
    cm: cm,
    bbar: new Ext.PagingToolbar({
        pageSize: 10,
        store: ds,
        displayInfo: true,
        displayMsg: '显示第 {0} 条到 {1} 条记录，一共 {2} 条',
        emptyMsg: "没有记录"
    })
});
ds.load();</pre>
<p>嘿嘿，加一个bbar的参数就可以了，bbar就是bottom bar啦，底端工具条。</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-19.png" alt="" align="middle" /></div>
<p>不过还是要注意一点，与1.x中不同的是，如果配置了分页工具条，ds.load()就必须在构造grid以后才能执行，否则分页工具条会不起作用。看来分页工具条会把自己和ds做一些关联，来完成与grid共享数据模型的。</p>
<p>对了，还有一点不同，1.x中分页条不会随着浏览器的大小改变，自动放缩，这点在2.0中也解决了。</p>
<p>2.0的例子在lingo-sample/2.0/02-05.html。</p></div>
<div class="sect2">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="d0e619"></a>2.7.3. 迫不得已，要加上后台脚本了。</h3>
</div>
</div>
</div>
<p>grid会每次都显示ds中所有的数据，咱们没法利用静态数据好好演示分页，于是，必须写后台脚本，让ext与后台进行数据交互才能看到真实的分页效果。</p>
<p>咱们尽量在原来的基础上修改啊，把注意力集中在关键部位，一次性突破。</p>
<p>我不会其他语言，后台就用jsp写啦。有个好消息是只要返回的数据格式一样，ext才不管后台是什么写的呢。也就是这样，不管你以后用什么实现后台，前台的ext代码都一样。</p>
<pre class="programlisting">&lt;%
String start = request.getParameter("start");
String limit = request.getParameter("limit");
try {
    int index = Integer.parseInt(start);
    int pageSize = Integer.parseInt(limit);

    String json = "{totalProperty:100,root:[";
    for (int i = index; i &lt; pageSize + index; i++) {
        json += "{id:" + i + ",name:'name" + i + "',descn:'descn" + i + "'}";
        if (i != pageSize + index - 1) {
            json += ",";
        }
    }
    json += "]}";
    response.getWriter().write(json);
} catch(Exception ex) {
}
%&gt;</pre>
<p>下面我们来解读这段jsp代码：</p>
<div class="orderedlist">
<ol type="1">
<li>在进行操作之前，我们先要获得ext传递过来的两个参数：start和limit，start指的从第几个数据开始显示，limit是说从start开始，一共要用多少个数据，当然返回的数据可能会小于这个值。</li>
<li>咱们在后台模拟对100条数据进行分页，在获得了start和limit之后再生成json格式的数据。何谓json？在理论讲解之前先看看实例，让我们能有个感性认识，至于以后能不能升华到理性认识，就看各位的悟性了。
<p>模拟ext访问后台，并传递两个参数start=0&amp;limit=10，把获得的数据稍微整理一下，是这个样子。</p>
<pre class="programlisting">{totalProperty:100,root:[
    {id:0,name:'name0',descn:'descn0'},
    {id:1,name:'name1',descn:'descn1'},
    {id:2,name:'name2',descn:'descn2'},
    {id:3,name:'name3',descn:'descn3'},
    {id:4,name:'name4',descn:'descn4'},
    {id:5,name:'name5',descn:'descn5'},
    {id:6,name:'name6',descn:'descn6'},
    {id:7,name:'name7',descn:'descn7'},
    {id:8,name:'name8',descn:'descn8'},
    {id:9,name:'name9',descn:'descn9'}
]}</pre>
<p>请记住这个数据格式，不管后台是什么，只要满足了这样的格式要求，ext就可以接收处理，显示到grid中。</p>
<p>我这里就不好好介绍json，现在只需要知道json里头除了name（名称）就是value（值），值有好几种格式，如果是数字就不用加引号，如果加了引号就是字符串，如果用[]包裹就是数组，如果出现{}就说明是嵌套的json。诸如此类。</p>
<p>简 单瞄了json一眼，开头就是totalProperty:100，这告诉ext：“俺这里有100个数据呢。”，然后就是root: []，root对应着一个数组，数组里有10个对象，每个对象都有id呀，name呀，descn呀。这10个数据最后就应该显示到表格里。</li>
<li>jsp里用for循环生成root数组里的数据，这样我们翻页的时候可以看到数据的变化，要不每次都是一样的数据，你怎么知道翻页是不是起作用了呢？最后我们把得到的json字符串输出到response里，ext也就可以获得这些数据了。</li>
</ol>
</div>
<p>结果经过了一番折腾，我们的jsp已经确定可以返回我们所需要的数据了。现在我们可以忘掉后台是用什么语言写的了，直接切入ext代码，看看它是怎么样才能跑去后台获得这些数据呢？</p>
<p>因为引入了json作为数据传输格式，这次我们要对ext代码进行一次大换血了，请做好思想准备。</p>
<div class="orderedlist">
<ol type="1">
<li>换掉proxy，别在内存里找了，让我们通过http获得我们想要的。
<pre class="programlisting">proxy: new Ext.data.HttpProxy({url:'grid.jsp'}),</pre>
<p>创建HttpProxy的同时，用url这个参数指定咱们去哪里取数据，我们这里设置成grid.jsp，就是我们刚才讨论的jsp脚本啦。</li>
<li>已经不是数组了，现在要用json咯。
<pre class="programlisting">reader: new Ext.data.JsonReader({
    totalProperty: 'totalProperty',
    root: 'root'
}, [
    {name: 'id'},
    {name: 'name'},
    {name: 'descn'}
])</pre>
<p>看比ArrayReader多了什么？totalProperty对应咱们jsp返回的totalProperty，也就是数据的总数。root对应咱们jsp返回的root，就是一个包含返回数据的数组。</li>
<li>好了，最后在初始化的时候，告诉我们希望获得哪部分的数据就可以了。
<pre class="programlisting">ds.load({params:{start:0,limit:10}});</pre>
<p>就在ds读取的时候添加两个参数，start和limit，告诉后台，我们从第一个数可以取起，最多要10个。</p>
<p>在 这里有一个小插曲，如果你按照我们以前的设置，grid是无法正常显示的，因为ds.load()无法在grid.render()前准备好所有 数组，所以它不知道自己应该实现多高。没法子，我们只好为它指定一个固定的高度了。像这样&lt;div id=&#8221;grid&#8221; style=&#8221;height:265px;&#8221;&gt;&lt;/div&gt;。</li>
</ol>
</div>
<p>最后，我们就可以使用分页条上那些按钮试试分页了。呵呵~就这么简单。</p>
<p>1.x的例子在lingo-sample/1.1.1/02-06.html，jsp文件在lingo-sample/1.1.1/grid.jsp，下面是它的截图：</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-20.png" alt="" align="middle" /></div>
<p>有趣的是，1.x中，不需要为div指定高度，它自己就知道如何显示，不晓得为什么2.0里不这样做呢。</p>
<p>2.0的例子在lingo-sample/2.0/02-06.html，jsp文件在lingo-sample/2.0/grid.jsp，下面是它的截图：</p>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-21.png" alt="" align="middle" /></div>
</div>
<div class="sect2">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="d0e702"></a>2.7.4. 其实分页不一定要踩在脚下，也可以顶在头上。</h3>
</div>
</div>
</div>
<p>我的意思是，grid除了FootPanel以外，还有HeaderPanel，意思就是头顶上的面板。我们把分页条放在上面也不会有任何问题。1.x中的代码仅仅是将getFooterPanel改成getHeaderPanel，这样分页条就跑到上头去了。</p>
<pre class="programlisting">var gridHead = grid.getView().getHeaderPanel(true);

var paging = new Ext.PagingToolbar(gridHead, ds, {
    pageSize: 10,
    displayInfo: true,
    displayMsg: '显示第 {0} 条到 {1} 条记录，一共 {2} 条',
    emptyMsg: '没有记录'
});</pre>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-22.png" alt="" align="middle" /></div>
<p>1.x的例子可以在lingo-sample/1.1.1/02-07.html找到。</p>
<p>2.0就更简单了，只需要改一个字母，b -&gt; t，呵呵~，让原来的bbar（bottom bar）变成tbar（top bar）就可以让我们的工具条登天了。</p>
<pre class="programlisting">var grid = new Ext.grid.GridPanel({
    el: 'grid',
    ds: ds,
    cm: cm,
    tbar: new Ext.PagingToolbar({
        pageSize: 10,
        store: ds,
        displayInfo: true,
        displayMsg: '显示第 {0} 条到 {1} 条记录，一共 {2} 条',
        emptyMsg: "没有记录"
    })
});</pre>
<div class="mediaobject"><img src="file:///I:/note_from_web/data/20080617204227/02-23.png" alt="" align="middle" /></div>
<p>2.0的例子可以在lingo-sample/2.0/02-07.html找到。</p>
<p>呃，当然你可以让上下都加上分页条，反正它们最后都是共享一个ds，功能不会有任何问题哈。吼吼。</p></div>
</div>
<div class="sect1">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both;"><a name="d0e729"></a>2.8. 可编辑表格，改变大小，表格间拖拽，树与表格间拖拽。</h2>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.result-search.com/sty/2009/04/23/ext20-getting-start-the-ext-table-widget.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
