flex与excel相互复制,导入,导出,另存为等通信问题

 

flex与excel相互复制

在Excel(OpenOffice Calc)中,当多个单元格被复制时,这些单元格的数据是以tab键分隔一行行数据(tab-separated values (TSV))存放在剪贴板中的,当这些数据被粘贴到Google Spreadsheets中时,这些TSV格式的数据被解析并被相应插入到Google Spreadssheets中了。 

既然知道其中的奥妙,那么剩下的就是在Flex中实现同样的效果了。以下是我们的实现思路,可以在Excel和Flex相互直接复制粘贴数据。

我们的思路的精妙所在是隐藏文本(TextField)组件的使用:
在DataGrid中,当按下Ctrl键时,我们创建一个隐藏的文本(TextField)组件,并将焦点定位给它,这样,我们就可以接受任何通过Ctrl+V粘贴过来的数据。相应的我们也将DataGrid选择行数据以TSV格式拷贝到TextField组件中,并且将所有的文本选择,这样我们使用Ctrl+C操作就可以复制当前行所有数据了。 
监听隐藏文件组件的textInput事件。如果有任何数据被粘贴的话,那么在这里数据将被解析,并插入到DataGrid中。 
当Ctrl键释放后,移除隐藏的文本组件。
以下是完整实现示例代码:

  1. <?xml version="1.0"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  3.    <mx:Script>
  4.        <![CDATA[
  5.    import flash.events.KeyboardEvent;
  6.  
  7.    private function dataGridKeyDownHandler(event:KeyboardEvent):void
  8.    {
  9.      if (event.ctrlKey && !dataGrid.getChildByName("clipboardProxy"))
  10.      {
  11.        // Add an invisible TextField object to the DataGrid
  12.        var textField:TextField = new TextField();
  13.        textField.name = "clipboardProxy";
  14.        dataGrid.addChild(textField);
  15.        textField.visible = false;
  16.  
  17.        textField.type = TextFieldType.INPUT;
  18.        textField.multiline = true;
  19.  
  20.        // Populate the TextField with selected data in TSV format
  21.  
  22.        textField.text = getTextFromItems(dataGrid.selectedItems);
  23.        textField.setSelection(0, textField.text.length - 1);
  24.  
  25.        // Listen for textInput event
  26.  
  27.        textField.addEventListener(TextEvent.TEXT_INPUT,
  28.            clipboardProxyPasteHandler);
  29.  
  30.        // Set player-level focus to the TextField
  31.  
  32.        systemManager.stage.focus = textField;
  33.      }
  34.    }
  35.  
  36.  
  37.    private function dataGridKeyUpHandler(event:KeyboardEvent):void
  38.    {
  39.      if (!event.ctrlKey)
  40.      {
  41.        var textField:TextField = TextField(dataGrid
  42.            .getChildByName("clipboardProxy"));
  43.        if (textField)
  44.          dataGrid.removeChild(textField);
  45.      }
  46.    }
  47.  
  48.    private function clipboardProxyPasteHandler(event:TextEvent):void
  49.    {
  50.      // Extract values from TSV format and populate the DataGrid
  51.  
  52.      var items:Array = getItemsFromText(event.text);
  53.      for each (var item:Object in items)
  54.        dataGrid.dataProvider.addItem(item);
  55.    }
  56.  
  57.    private function getItemsFromText(text:String):Array
  58.    {
  59.      var rows:Array = text.split("\n");
  60.      if (!rows[rows.length - 1])
  61.        rows.pop();
  62.  
  63.      var columns:Array = dataGrid.columns;
  64.      var itemsFromText:Array = [];
  65.  
  66.      for each (var rw:String in rows)
  67.      {
  68.        var fields:Array = rw.split("\t");
  69.  
  70.        var n:int = Math.min(columns.length, fields.length);
  71.        var item:Object = {};
  72.        for (var i:int = 0; i < n; i++)
  73.          item[columns[i].dataField] = fields[i];
  74.        itemsFromText.push(item);
  75.      }
  76.  
  77.      return itemsFromText; 
  78.    }
  79.  
  80.    private function getTextFromItems(items:Array):String
  81.    {
  82.      var columns:Array = dataGrid.columns;
  83.      var textFromItems:String = "";
  84.  
  85.      for each (var it:Object in items)
  86.      {
  87.        for each (var c:DataGridColumn in columns)
  88.          textFromItems += it[c.dataField] + "\t";
  89.        textFromItems += "\n";
  90.      }
  91.  
  92.      return textFromItems;
  93.    }
  94.    ]]>
  95.    </mx:Script>
  96.   
  97.    <mx:DataGrid id="dataGrid" editable="true"
  98.        keyDown="dataGridKeyDownHandler(event)"
  99.        keyUp="dataGridKeyUpHandler(event)">
  100.        <mx:columns>
  101.            <mx:DataGridColumn headerText="Scheduled Date"
  102.                dataField="scheduledDate" />
  103.            <mx:DataGridColumn headerText="Home Team"
  104.                dataField="homeTeam" />
  105.            <mx:DataGridColumn headerText="Away Team"
  106.                dataField="awayTeam" />
  107.            <mx:DataGridColumn headerText="Field"
  108.                dataField="field" />
  109.        </mx:columns>
  110.        <mx:dataProvider>
  111.            <mx:Object scheduledDate="4/1/2006" homeTeam="Chester Bucks"
  112.                awayTeam="Long Valley Hitters" field="Dawn Field" />
  113.        </mx:dataProvider>
  114.    </mx:DataGrid>
  115. </mx:Application>

这样我们可以写一个自定义组件继承自Datagrid组件来支持行级数据的复制粘贴:

  1. package com.yyhy.flex.util
  2. {
  3. import flash.events.KeyboardEvent;
  4. import flash.events.TextEvent;
  5. import flash.text.TextField;
  6. import flash.text.TextFieldType;
  7. import mx.controls.*;
  8. import mx.controls.dataGridClasses.DataGridColumn;
  9.     //import mx.events.
  10. public class EIDataGrid extends DataGrid
  11. {
  12. public function EIDataGrid()
  13. {
  14. super();
  15. this.addEventListener(KeyboardEvent.KEY_DOWN,KeyDownHandler);
  16. this.addEventListener(KeyboardEvent.KEY_UP,KeyUpHandler);
  17. }
  18. private function KeyDownHandler(event:KeyboardEvent):void
  19.    {
  20.       if (event.ctrlKey && !this.getChildByName("clipboardProxy"))
  21.       {
  22.         // Add an invisible TextField object to the DataGrid
  23.         var textField:TextField = new TextField();
  24.         textField.name = "clipboardProxy";
  25.         this.addChild(textField);
  26.         textField.visible = false;
  27.         textField.type = TextFieldType.INPUT;
  28.         textField.multiline = true;
  29.         // Populate the TextField with selected data in TSV format
  30.         textField.text = getTextFromItems(this.selectedItems);
  31.         //textField.text = getTextFromItems(dataGrid.dataProvider.source);
  32.         textField.setSelection(0, textField.text.length – 1);
  33.         // Listen for textInput event
  34.         textField.addEventListener(TextEvent.TEXT_INPUT,
  35.             clipboardProxyPasteHandler);
  36.         // Set player-level focus to the TextField
  37.         systemManager.stage.focus = textField;
  38.       }//end if
  39.     }//end function
  40.  
  41.  
  42.     private function KeyUpHandler(event:KeyboardEvent):void
  43.     {
  44.       if (!event.ctrlKey)
  45.       {
  46.         var textField:TextField = TextField(this.getChildByName("clipboardProxy"));
  47.         if (textField)
  48.         {
  49.           this.removeChild(textField);
  50.           }//end if
  51.       }//end if
  52.     }//end function
  53.  
  54.     private function clipboardProxyPasteHandler(event:TextEvent):void
  55.     {
  56.       // Extract values from TSV format and populate the DataGrid
  57.       var items:Array = getItemsFromText(event.text);
  58.       for each (var item:Object in items)
  59.         this.dataProvider.addItem(item);
  60.     }//end function
  61.  
  62.     private function getItemsFromText(text:String):Array
  63.     {
  64.       var rows:Array = text.split("\n");
  65.       if (!rows[rows.length - 1])
  66.         rows.pop();
  67.       var columns:Array = this.columns;
  68.       var itemsFromText:Array = [];
  69.       for each (var rw:String in rows)
  70.       {
  71.         var fields:Array = rw.split("\t");
  72.         var n:int = Math.min(columns.length, fields.length);
  73.         var item:Object = {};
  74.         for (var i:int = 0; i < n; i++)
  75.           item[columns[i].dataField] = fields[i];
  76.         itemsFromText.push(item);
  77.     }
  78.       return itemsFromText; 
  79.     }//end function
  80. private function getTextFromItems(items:Array):String
  81.     {
  82.       var columns:Array = this.columns;
  83.       var textFromItems:String = "";
  84.     //add datagrid headtext
  85.     for each (var i: DataGridColumn in columns)
  86.       {
  87.           textFromItems += i.headerText + "\t";
  88.           }
  89.         textFromItems += "\n";
  90.        
  91.       for each (var it:Object in items)
  92.       {
  93.      
  94.         for each (var c: DataGridColumn in columns)
  95.           textFromItems += it[c.dataField] + "\t";
  96.         textFromItems += "\n";
  97.       }
  98.       return textFromItems;
  99.     }//end function
  100. }
  101. }

在AIR环境下,可以使用as3xls-1.0.swc库来导出excel:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
  3.       <mx:Script>
  4.          <![CDATA[
  5.             import mx.controls.CheckBox;
  6.             import mx.controls.Alert;         
  7.             import com.as3xls.xls.ExcelFile;
  8.     import com.as3xls.xls.Sheet;
  9.       import flash.filesystem.*;
  10.        [Bindable]
  11.          private var dp:Array = [
  12.         {idx:1, names: "test1", sex: "b" },
  13.         {idx:2, names: "test2", sex: "g" }
  14.         
  15.         ];
  16.         public function doSelect(o:Object):void
  17.         {
  18.             Alert.show("行的数据分别是:"+o.idx+"/"+o.names+"/"+o.sex);
  19.             
  20.         }
  21.     
  22.  
  23.   
  24.     private var sheet:Sheet;
  25.     private function onCreate():void {
  26.  
  27.      var excelFile:ExcelFile = new ExcelFile();
  28.      sheet = new Sheet();
  29.      sheet.resize(10, 10);
  30.      sheet.setCell(0, 0, "Today’s date:");
  31.      sheet.setCell(0, 1, new Date());
  32.      excelFile.sheets.addItem(sheet);
  33.      var mbytes:ByteArray = excelFile.saveToByteArray();
  34.     
  35.     
  36.                                 var stream:FileStream = new FileStream();               
  37.                                 var docsDir:File = File.documentsDirectory.resolvePath("abc.xls"); // 定死文件名
  38.  
  39.                                 try
  40.                                 {
  41.                                     docsDir.browseForSave("Save As");
  42.                                     docsDir.addEventListener(Event.SELECT, saveData);
  43.                                 }
  44.                                 catch (error:Error)
  45.                                 {
  46.                                     trace("Failed:", error.message)
  47.                                 }
  48.                                 
  49.                                 
  50.                                 function saveData(event:Event):void
  51.                                 {
  52.                                     var newFile:File = event.target as File;
  53.  
  54.                                     if (!newFile.exists)
  55.                                     {
  56.                                         var stream:FileStream = new FileStream();
  57.                                         stream.open(newFile, FileMode.WRITE);
  58.                                         stream.writeBytes(mbytes);
  59.                                         // 写文件流
  60.                                         stream.close();
  61.                                     }
  62.                                 }
  63.  
  64.  
  65.     
  66.     }
  67.         
  68.     ]]>
  69.      </mx:Script>
  70.     
  71.      <mx:Panel>
  72.     
  73.  
  74.      <mx:Button   label="导出" click="onCreate()"/>
  75.     <mx:DataGrid id="dg1" dataProvider ="{dp}">
  76.         
  77.         <mx:columns>
  78.         <mx:DataGridColumn width="20" headerText="" >
  79.              <mx:itemRenderer>
  80.                         <mx:Component>
  81.                         <mx:CheckBox change=" {outerDocument.doSelect(data as Object)} "    />
  82.                         </mx:Component>
  83.                     </mx:itemRenderer>
  84.                     </mx:DataGridColumn>
  85.             <mx:DataGridColumn headerText="names" dataField="names" width="200" />
  86.                <mx:DataGridColumn headerText="sex" dataField="sex" width="300" />
  87.         
  88.         </mx:columns>
  89.     </mx:DataGrid>
  90.        </mx:Panel>
  91. </mx:WindowedApplication>

如果是flex web怎么办?flash.filesystem.File (AIR Only)在flex是实现不了的。这样就需要后台来完成。以Java为示例:
例如 flex中一个导出按钮,可以直接 flash.net.navigateToURL(new URLRequest(url),”_blank”); url 可以是一个jsp页面 或者 一个servet。也就是你说第二种方式 收到客户端数据。然后直接设置下
Response.Buffer = TRUE
Response.AddHeader “Content-Disposition”, “attachment”
Response.contentType=”application/vnd.ms-excel”
Response.Buffer 是设置缓存区的。
url当然指jsp或者servlet的访问 路径了。 Response.Buffer = TRUE
Response.AddHeader “Content-Disposition”, “attachment”
Response.contentType=”application/vnd.ms-exce 这个就是在生成jsp或者servlet的页面中设置的
例如

  1. <%@ page contentType="application/msexcel" %>
  2. <!–
  3. 以上这行设定本网页为excel格式的网页 –>
  4. <%
  5. response.setHeader("Content-disposition","inline; filename=test1.xls");
  6.   
  7. //以上这行设定传送到前端浏览器时的档名为test1.xls
  8.    //就是靠这一行,让前端浏览器以为接收到一个excel档
  9.  
  10. %>
  11. <html>
  12. <head>
  13. <title>Excel档案呈现方式</title>
  14. </head>
  15. <body>
  16.  
  17. <table border="1" width="100%">
  18.     <tr>
  19.       
  20. <td>姓名</td><td>身份证字号</td><td>生日</td>
  21.     
  22. </tr>
  23.     <tr>
  24.       
  25. <td>李玟</td><td>N111111111</td><td>1900/11/12</td>
  26.     
  27. </tr>
  28.     <tr>
  29.       
  30. <td>梁静如</td><td>N222222222</td><td>1923/10/1</td>
  31.     
  32. </tr>
  33.     <tr>
  34.       
  35. <td>张惠妹</td><td>N333333333</td><td>1934/12/18</td>
  36.     
  37. </tr>
  38.   </table>
  39. </body>
  40. </html>

也可以使用servlet将流直接输出到客户端。这里推荐Java Excel API开源类库,操作Excel非常简单。
Flex图片另存为的解决方法-类似可以解决另存为excel:
我们知道Flex对于本地的限制比AIR要大,当我们想保存一个由Flex生成的文件必须借由服务器来完成,现在有一个需求就是,用户想保存Flex生成的图片在本地,我们要完成这个过程,必须先将Flex生成的图片转换为通用的数据格式,即ByteArray,然后由后台程序帮助写文件,形式上类似先上传,再下载,只不过中间不用保存实际的物理文件。

Flex端

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
  3. <mx:Script>
  4. <![CDATA[
  5. import mx.graphics.codec.JPEGEncoder;
  6. import mx.graphics.ImageSnapshot;
  7. private function saveAs(){
  8. var en:JPEGEncoder = new JPEGEncoder(100); //压缩图片,100是指质量
  9. var ba:ByteArray=en.encode(ImageSnapshot.captureBitmapData(img));//将控件转为BitmapData后再转为ByteArray
  10. var request:URLRequest = new URLRequest("/TestForLCDS/servlet/UploadServlet");
  11. request.method="POST";
  12. request.data=ba;
  13. request.contentType = "application/octet-stream"; //这个很重要,设置成流数据
  14. navigateToURL(request,"_blank"); //因为要浏览器触发下载事件,所以就不用异步方式打开连接了
  15. }
  16. ]]>
  17. </mx:Script>
  18. <mx:Button x="228" y="10" label="另存为本地图片" click="saveAs()"/>
  19. <mx:Image id="img" x="10" y="10" source="img.jpg" width="200" height="200" scaleContent="false"/>
  20. </mx:Application>

后台Java servlet

  1. public void doPost(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3.  
  4. response.setContentType("application/x-download"); //内容是下载
  5. response.setHeader("Content-Disposition","attachment;filename=" + "test.jpg");//文件名,可以进一步处理
  6. //读数据
  7. BufferedInputStream inputStream = new BufferedInputStream(request.getInputStream());
  8. OutputStream outputStream = response.getOutputStream();
  9. byte [] bytes = new byte[1024];
  10. int v;
  11. //写数据
  12. while((v=inputStream.read(bytes))>0){
  13. outputStream.write(bytes,0,v);
  14. }
  15. outputStream.flush();
  16. outputStream.close();
  17. inputStream.close();
  18. }
  19.  
  20. }

摘自:http://www.flexer.cn/blog/?p=605

posted @ 2009-08-28 09:28  伊莱克斯  阅读(2291)  评论(1编辑  收藏  举报