现在的位置: 首页 > 综合 > 正文

Flex闲话其它

2013年08月30日 ⁄ 综合 ⁄ 共 15116字 ⁄ 字号 评论关闭

一个内部网站,要求10月前完成,我成功的拖到了12月……网站视觉样式是要求最多的,其实这个不用关心,东西像人脸,再漂亮连看三天也腻了,再难看看三天也习惯了。

整个网站比较繁琐(就我一个人完成,繁琐变成烦死)。包括文字信息和数据库查询两个部分组成。文字信息类似新闻,不是很困难,一个月里就做好大概,剩下就是照着意见修改。剩下数据库部分就是很麻烦了。因为查询的数据需要选取的条件十分多。查询出来的数据包括 时间 地区 指标名 3个属性,这也就意味着,结果表里会有维度选择。其次,对结果表还要作图(曲线图和直方图),导出excel,打印,计算小工具。开始准备使用js做,网上找到ext2,无奈调试困难(当时IE8没出来,firebug调试好的程序到了IE下又会出问题),IE下运行速度太慢(当chrome出来的时候,确实感到了JS的速度可以令人赏心悦目)。无奈只好选择了别的编程手段了。任何一个网页编程论坛都会在讨论JS的时候外加附带讨论Flash,讨论flash就会连带讨论Flex。

Flex

[flex builder 3] 3月发布 为了和 微软的银光对抗,玩家可以google到序列号。安装完后记得去adobe主站看看有没有新出补丁。Fb3 使用了Eclipse 所以java玩家可以光速上手,而且帮助文件模式基本一致。

学习flex现在已经有很多资源了,不像3月份的时候市面图书就一本flex第一步 ,基础学习只能看help。在这里可以下载到 中文视频教程 的确是十分不错的基础教程。Flex使用的as3.0语言对于学过任何一门面向对象语言,都可以很快熟悉。而对于界面编程的mxml 和 html 差不多,现在几乎小学就开始教如何制作做网页了。

Flex里面需要三个重点学习的 1、数据绑定 2、xml操作 3、mvc 

这三个很普通,每种编程方式都会涉及(其中mvc只是中编程思想,连编程都算不上),但这团子三兄弟在flex里面可谓是大放异彩。我从我上面说的做的项目里介绍。

因为是个web工程,所以会分为浏览器端和服务端,使用flex后会感觉到这个两个东西会如此分开,因为后台还是使用asp 所以无法使用flash特有remote的数据流格式。只能通过httpservice,传输 xml格式数据。简单分割如下:

[取得参数->数据数组->生成xml]服务端->[获得数据->数据绑定->对xml操作->发送参数]客户端

流程很简单,然后继续分化:

服务端:数据库操作类 ,xml生成类,事物处理类,每件事物都有自己独立的处理asp文件。

客户端:公共httpservice对象,作图类,做表类,界面操作,xml数据处理。

分成那么多就可以每个单独完成了。服务端不用费心,几年经验自然顺风顺水,开始准备xml生成类 后来直接写成页面了,代码少了很多,出来的东西也能随意修改(这是缺点)。

生成xml以后就可以开始专心写前台flex里的代码了。

前台 用ViewStack分为两页 一页可以输入查询条件,另页显示结果,页面一的选择条件包括数据库(Tree)、地区(CheckTree)、指标大类(Tree)、具体指标(CheckList)、和被选择的地区(List)与指标列表(List)。页面二 ApplicationControlBar里面的一堆 维度、指标选择(combo)、小工具、作图(TitleWindow)、转置、打印、导出(button)、 数据表(Adatagrid)

CheckTree 从 Tree 继承来的,CheckList 也是从List里itemrender 。除了button外 每个控件都使用了数据绑定(我使用了XML格式),一切对控件的操作都通过被绑定的数据反应出来,同样一切对数据的操作控件也会反应出来。所以在我面前的不是一个个控件,而是一个个XML。

CheckTree 的xml是这样的:

  1. <folder label="地区">
  2.  <folder label="全国">
  3.   <node label="北京" dqbm="100000" state="unchecked" />
  4.   <node label="上海" dqbm="200000" state="unchecked" /> 
  5.  </folder>
  6. </folder>

很简单吧,只要将这个XML其绑定在CheckTree上就会出现很熟悉的带选择的树控件,将某个节点打上钩,那么XML里该节点state属性就变为了checked , 而他的父节点state属性就变为了schrodinger(猫猫,表示节点不完全选择,如果都选上了也是checked),选择好以后我只要把那些最子节点里state属性为checked的node 拿出来放到 被选择的地区(List)所绑定的XML里就行了,选择的地区控件就立即呈现我选择的内容。

这就显示出了数据绑定的伟大,以至于我在以后写一个vb的程序的时候,也十分热爱使用控件直接渲染一个数组,只不过每次操作玩数组还得再次渲染一下,没有flex里绑定那样得心应手。

Flex里的控件已经十分强大了,但是有些需要自己来做比如上面那个checktree 尽管看上去是 checkbox+tree 但直接用itemrender无法满足要求,tree里的getState updateDisplayList 等等都要override ,累述无益,代码如下:

  1. package
  2. {
  3.     import mx.controls.Image;
  4.     import mx.controls.Tree;
  5.     import mx.controls.treeClasses.*;
  6.     import mx.collections.*;
  7.     import mx.controls.CheckBox;
  8.     import mx.controls.listClasses.*;
  9.     import flash.events.Event;
  10.     import flash.events.MouseEvent;
  11.     import mx.events.FlexEvent;
  12.     import flash.display.DisplayObject;
  13.     import flash.xml.*;
  14.     
  15.     import mx.core.IDataRenderer;
  16.     
  17.     public class CheckTreeRenderer extends TreeItemRenderer
  18.     {
  19.         protected var myImage:Image;
  20.         
  21.         // set image properties
  22.         private var imageWidth:Number   = 10;
  23.         private var imageHeight:Number  = 10;
  24.         private var inner:String    = "inner.png";
  25.         protected var myCheckBox:CheckBox;
  26.         static private var STATE_SCHRODINGER:String = "schrodinger";
  27.         static private var STATE_CHECKED:String = "checked";
  28.         static private var STATE_UNCHECKED:String = "unchecked";
  29.         
  30.         public function CheckTreeRenderer () 
  31.         {
  32.             super();
  33.             mouseEnabled = false;
  34.         }
  35.         private function toggleParents (item:Object, tree:Tree, state:String):void
  36.         {
  37.             if (item == null)
  38.             {
  39.                 return;
  40.             }
  41.             else
  42.             {
  43.                 item.@state = state;
  44.                 toggleParents(tree.getParentItem(item), tree, getState (tree, tree.getParentItem(item)));
  45.             }
  46.         }
  47.         
  48.         private function toggleChildren (item:Object, tree:Tree, state:String):void
  49.         {
  50.             if (item == null)
  51.             {
  52.                 return;
  53.             }
  54.             else
  55.             {
  56.                 item.@state = state;
  57.                 var treeData:ITreeDataDescriptor = tree.dataDescriptor;
  58.                 if (treeData.hasChildren(item))
  59.                 {
  60.                     var children:ICollectionView = treeData.getChildren (item);
  61.                     var cursor:IViewCursor = children.createCursor();
  62.                     while (!cursor.afterLast)
  63.                     {
  64.                         toggleChildren(cursor.current, tree, state);
  65.                         cursor.moveNext();
  66.                     }
  67.                 }
  68.             }
  69.         }
  70.         
  71.         private function getState(tree:Tree, parent:Object):String
  72.         {
  73.             var noChecks:int = 0;
  74.             var noCats:int = 0;
  75.             var noUnChecks:int = 0;
  76.             if (parent != null)
  77.             {
  78.                 var treeData:ITreeDataDescriptor = tree.dataDescriptor;
  79.                 var cursor:IViewCursor = treeData.getChildren(parent).createCursor();
  80.                 while (!cursor.afterLast)
  81.                 {
  82.                     if (cursor.current.@state == STATE_CHECKED)
  83.                     {
  84.                         noChecks++;
  85.                     }
  86.                     else if (cursor.current.@state == STATE_UNCHECKED)
  87.                     {
  88.                         noUnChecks++
  89.                     }
  90.                     else
  91.                     {
  92.                         noCats++;
  93.                     }
  94.                     cursor.moveNext();
  95.                 }
  96.             }
  97.             if ((noChecks > 0 && noUnChecks > 0) || (noCats > 0))
  98.             {
  99.                 return STATE_SCHRODINGER;
  100.             }
  101.             else if (noChecks > 0)
  102.             {
  103.                 return STATE_CHECKED;
  104.             }
  105.             else
  106.             {
  107.                 return STATE_UNCHECKED;
  108.             }
  109.         }
  110.         private function imageToggleHandler(event:MouseEvent):void
  111.         {
  112.             //event.stopImmediatePropagation();
  113.             myCheckBox.selected = !myCheckBox.selected;
  114.             checkBoxToggleHandler(event);
  115.         }
  116.         private function checkBoxToggleHandler(event:MouseEvent):void{
  117.             
  118.             //event.stopImmediatePropagation();
  119.             if (data)
  120.             {
  121.                 var myListData:TreeListData = TreeListData(this.listData);
  122.                 var selectedNode:Object = myListData.item;
  123.                 var tree:Tree = Tree(myListData.owner);
  124.                 var toggle:Boolean = myCheckBox.selected;
  125.                 if (toggle)
  126.                 {
  127.                     toggleChildren(data, tree, STATE_CHECKED);
  128.                 }
  129.                 else
  130.                 {
  131.                     toggleChildren(data, tree, STATE_UNCHECKED);
  132.                 }
  133.                 var parent:Object = tree.getParentItem (data);
  134.                 toggleParents (parent, tree, getState (tree, parent));
  135.             }
  136.         }
  137.         
  138.         override protected function createChildren():void
  139.         {
  140.             super.createChildren();
  141.             myCheckBox = new CheckBox();
  142.             myCheckBox.setStyle( "verticalAlign""middle" );
  143.             myCheckBox.addEventListener( MouseEvent.CLICK, checkBoxToggleHandler );
  144.             addChild(myCheckBox);
  145.             myImage = new Image();
  146.             myImage.source = inner;
  147.             myImage.addEventListener( MouseEvent.CLICK, imageToggleHandler );
  148.             myImage.setStyle( "verticalAlign""middle" );
  149.             addChild(myImage);
  150.             
  151.         }   
  152.         private function setCheckState (checkBox:CheckBox, value:Object, state:String):void
  153.         {
  154.             if (checkBox == null){
  155.                 return;
  156.             }
  157.             if (state == STATE_CHECKED)
  158.             {
  159.                 checkBox.selected = true;
  160.             }
  161.             else if (state == STATE_UNCHECKED)
  162.             {
  163.                 checkBox.selected = false;
  164.             }
  165.             else if (state == STATE_SCHRODINGER)
  166.             {
  167.                 checkBox.selected = false;
  168.             }
  169.             else
  170.             {
  171.                 checkBox.selected = false;
  172.             }
  173.         }       
  174.         override public function set data(value:Object):void
  175.         {           
  176.             if (value == nullreturn;
  177.             super.data = value;
  178.             setCheckState (myCheckBox, value, value.@state);
  179.             if(TreeListData(super.listData).item.@type == 'dimension')
  180.             {
  181.                 setStyle("fontStyle"'italic');
  182.             }
  183.             else
  184.             {
  185.                 if (this.parent != null)
  186.                 {
  187.                     var _tree:Tree = Tree(this.parent.parent);
  188.                     _tree.setStyle("defaultLeafIcon"null);
  189.                 }
  190.                 setStyle("fontStyle"'normal');
  191.             }
  192.         }
  193.        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
  194.        {
  195.             super.updateDisplayList(unscaledWidth, unscaledHeight);
  196.             if(super.data)
  197.             {
  198.                 if (super.icon != null)
  199.                 {
  200.                     myCheckBox.x = super.icon.x;
  201.                     myCheckBox.y = getStyle("fontSize")-2;
  202.                     super.icon.x = myCheckBox.x + myCheckBox.width + 17;
  203.                     super.label.x = super.icon.x + super.icon.width + 3;
  204.                 }
  205.                 else
  206.                 {
  207.                     myCheckBox.x = super.label.x;
  208.                     myCheckBox.y = getStyle("fontSize")-2;
  209.                     super.label.x = myCheckBox.x + myCheckBox.width + 17;
  210.                 }
  211.                 if (data.@state == STATE_SCHRODINGER)
  212.                 {
  213.                     myImage.x = myCheckBox.x+2;
  214.                     myImage.y = myCheckBox.y-5;
  215.                     myImage.width = imageWidth;
  216.                     myImage.height = imageHeight;
  217.                 }
  218.                 else
  219.                 {
  220.                     myImage.x = 0;
  221.                     myImage.y = 0;
  222.                     myImage.width = 0;
  223.                     myImage.height = 0;
  224.                 }
  225.             }
  226.         }
  227.     }
  228. }
最后需要吧所选取的东西提交给服务器去查询数据,提交的数据可以使XML,也可以是将准备提交的XML进行整理,生成字符串(这样节省带宽)。提交的内容 httpsrvice 使用post协议 因为是UTF-8编码,如果提交条件里有中文,还得URIencode来编码,后台还需要URIdecode
Asp里decodeURI 很简单的不必自己做
  1. <script language="javascript" runat="server" type="text/javascript"
  2.     function decodeURI(furl){ 
  3.     var a=furl; 
  4.     try{return decodeURIComponent(a)}catch(e){return 'undefined'}; 
  5.     return ''
  6.     } 
  7. </script>
好了返回来的数据生成的表格XML格式是这样的:
  1. <dataSet>
  2.     <colSet freeze="1">
  3.         <colObj columnName="@col1" headerText="指标/单位" width="120" tu="0" />
  4.         <colGroup headerText="2008年一季度">
  5.             <colObj columnName="@col2" headerText="绝对值" unit="亿元" zbname="2008年一季度绝对值" width="100" tu="1" />
  6.             <colObj columnName="@col3" headerText="增长" unit="%" zbname="2008年一季度增长" width="100" tu="1" />
  7.         </colGroup>
  8.         <colGroup headerText="2008年上半年">
  9.             <colObj columnName="@col4" headerText="绝对值" unit="亿元" zbname="2008年一季度绝对值" width="100" tu="1" />
  10.             <colObj columnName="@col5" headerText="增长" unit="%" zbname="2008年一季度增长" width="100" tu="1" />
  11.         </colGroup>
  12.         <colGroup headerText="2008年全年">
  13.             <colObj columnName="@col6" headerText="绝对值" unit="亿元" zbname="2008年一季度绝对值" width="100" tu="1" />
  14.             <colObj columnName="@col7" headerText="增长" unit="%" zbname="2008年一季度增长" width="100" tu="1" />
  15.         </colGroup>
  16.     </colSet>
  17.     <colData>
  18.         <dataObj col1 = "GDP" col2 = "1725.10" col3 = "13.50" col4 = "4180.70" col5 = "14.20" col6 = "8990.80" col7 = "13.90"/>
  19.         <dataObj col1 = "其中:一产" col2 = "196.40" col3 = "3.10" col4 = "565.80" col5 = "4.50" col6 = "1385.80" col7 = "4.30"/>
  20.         <dataObj col1 = "二产" col2 = "819.20" col3 = "17.90" col4 = "2097.30" col5 = "18.80" col6 = "4194.60" col7 = "18.50"/>
  21.         <dataObj col1 = "三产" col2 = "709.50" col3 = "11.80" col4 = "1517.60" col5 = "11.90" col6 = "3410.30" col7 = "11.90"/>
  22.         <dataObj col1 = "规模以上工业" col2 = "648.70" col3 = "22.20" col4 = "1535.30" col5 = "24.90" col6 = "3071" col7 = "23"/>
  23.     </colData>
  24. </dataSet>
这样分出
freeze 冷冻前X列 
headerText datagrid标题 
unit 也在标题上
zbname 作图的时候需要的名字,开始做的单独表是多表头的,不能直接用 headerText
tu 标记是否做图
这是个多个表头的xml数据,用html完成一个多表头的datagrid相当简单的,但是要完成这个XML的flash渲染的确还是比较讨厌的,因为我是初学者……
渲染XML类代码:
  1. package
  2. {
  3.     import mx.controls.AdvancedDataGrid;
  4.     import mx.controls.advancedDataGridClasses.*;
  5.     import mx.core.ClassFactory;
  6.     import mx.utils.ObjectUtil;
  7.     public class XmlToGrid
  8.     {
  9.         public function XmlToGrid():void{
  10.          }
  11.         public static function XmlGrid(adgrid:AdvancedDataGrid,InXml:XML):void{
  12.              adgrid.visible=false;
  13.              adgrid.groupedColumns=XmltoGCol(InXml.colSet);
  14.              adgrid.lockedColumnCount=InXml.colSet.@freeze;
  15.              adgrid.dataProvider=InXml.colData.dataObj;
  16.              adgrid.visible=true;
  17.          }
  18.         private static function sortFunc(field:String):Function{
  19.             return function(obj1:Object, obj2:Object):int{
  20.                 return ObjectUtil.numericCompare(obj1[field],obj2[field]);
  21.             }
  22.         }
  23.         private  static function XmltoColumns(InXml:XML):AdvancedDataGridColumn{
  24.             var columns:Array=new Array();
  25.             var item:Object=InXml
  26.             var dgColumn:AdvancedDataGridColumn=new AdvancedDataGridColumn();
  27.                //一个列头的内容
  28.                dgColumn.dataField=item.@columnName;
  29.                if (item.@unit!=undefined && item.@unit!=""){
  30.                 dgColumn.headerText=item.@headerText+"/n["+item.@unit+"]";
  31.                 //dgColumn.headerText=item.@headerText;
  32.                }
  33.                else{
  34.                 dgColumn.headerText=item.@headerText;
  35.                }
  36.                dgColumn.minWidth=item.@width;
  37.                //var tempstr:String=item.@headerText.toString();
  38.                //dgColumn.width=tempstr.length*10;
  39.                dgColumn.headerWordWrap=true;
  40.                dgColumn.wordWrap=true;
  41.                dgColumn.sortCompareFunction=sortFunc(item.@columnName);
  42.                dgColumn.itemRenderer=new ClassFactory(GridRenderer);
  43.                return(dgColumn);
  44.          }
  45.          private  static function XmltoGCol(InXml:XMLList):Array{
  46.             var columns:Array=new Array();
  47.             var item:Object=InXml
  48.                //递归遍历
  49.                     for each(var sonXml:XML in InXml.children()){
  50.                     if (sonXml.children().length()!=0){
  51.                         var groupedColumns:AdvancedDataGridColumnGroup=new AdvancedDataGridColumnGroup();
  52.                         groupedColumns.headerText=sonXml.@headerText;
  53.                         groupedColumns.children=(XmltoGCol(XMLList(sonXml)));
  54.                         columns.push(groupedColumns);
  55.                     }
  56.                     else{
  57.                         columns.push(XmltoColumns(sonXml));
  58.                    }
  59.                 }
  60.                 return(columns);
  61.          }
  62.     }
  63. }
对Flex 很大的优势在于对XML操作十分简单,取属性直接@,比起在javascript里受用的多。
因为是单向的,所以非常简单,否则还得override好多东西……
直接使用 XmlToGrid.XmlGrid(view_dg,TempXml);
一张表就生成了。
图的数据源也直接透过这个XML生成。单独一个类传递所需要的参数,因为图比较简单,网上有很多例子了,不在累述。工具也是类似……
这样一个程序就算完成了。多看看flex自带的help,会对写程序帮助很大,比较现在写程序,设计上动的脑子要多得多……
补充下,本程序里没有使用的一样东西。我在表里取得数据的时候会一般从datagrid的DataProvider取得
比如某行某列:
testDG.dataProvider[i][testDG.columns[0].dataField]
datagrid.getItemAt(i).列名
这就是一个单元格的数据了,注意列名大写。
行可以根据DataProvider的Index来取,例如DataGrid.dataProvider[index]取到该行的数据,列可以根据列名来取,例如DataGrid.dataProvider[index].dataField。如果是选中行的某列数据就更直接些了DataGrid.selectedItem.dataField 
this.grid.columns[event.columnIndex].dataField 
Alert.show(dg2.columns[0].headerText);

抱歉!评论已关闭.