随笔-9  评论-15  文章-0  trackbacks-0
  2009年1月17日

Sean Moore Bio 说道:秋天又一次来临了,是时候回顾一下2008年最热门的Flex和ActionScript 3.0 APIs,技巧和工具了,下面是我的总结,收集的比较全,Flex开发必备,欢迎补充。

 

介绍 Flex SDK 3.1 和 Flex Builder 3.0.1

Flex SDK 3.1 是一个Flex SDK里程碑式的版本,推荐开发者使用。
http://www.adobe.com/devnet/flex/articles/sdk3_fb301.html

Cairngorm 迁移进入Adobe开源网站(Cairngorm是Adobe 实验室中的Flex MVC框架)
http://weblogs.macromedia.com/amcleod/archives/2008/08/cairngorm_moved.html


Flex 架构基础 - 模块和数据转换对象

展示一个简单的方式使用模块和数据转换对象来设置简单Flex应用
http://nwebb.co.uk/blog/?p=228


教程: ActionScript 3 拖动函数

这个教程介绍ActionScript 3在布景中的拖动函数。
http://flashmymind.com/Tutorials/Actionscript/Advanced/actionscript-dragging.php


Flex 分页组件

一个小的Flex分页组件
http://www.darklump.co.uk/blog/?p=112


ModuleManager 和 IModuleInfo - 自动加载Flex模块

http://lowpitch.com/blog/2008/08/17/modulemanager-and-imoduleinfo-loading-flex-modules-dynamically/


Degrafa初学教程

Degrafa是一个Flex扩展,在FLEX中增加了对矢量数据的动态处理,包括动态添加,删除和修改,并支持SVG的路径格式数据。Mike Huntington一篇优秀文章。
http://www.mikehuntington.com/?p=22


同时使用Degrafa
高级CSS技巧
依然是Mike Huntington的文章。质量很高,推荐。
http://www.mikehuntington.com/?p=31


Alcon 3

为Adobe AIR重写过,一个简单好用的调试/日志工具。很酷。
http://blog.hexagonstar.com/alcon/


在Flex Builder中删除
css type selector 警告
在Flex Builder中删除 css type selector 警告的快速技巧
http://www.nutrixinteractive.com/blog/?p=135


在倾斜背景中的VBox, HBox Flex箱式模型
http://www.igorcosta.org/?p=160


Flex 设计/开发工作流程视频教程

http://www.ashorten.com/2008/08/11/flex-designerdeveloper-workflow-video-tutorials/


6个使用 ActionScript 3.0 的理由 - 作者Lee Brimelow

http://www.adobe.com/devnet/actionscript/articles/six_reasons_as3.html


定制 flex 皮肤

http://the.fontvir.us/b10g/?id=111


编写Flex组件, part 1

http://labs.flexperiments.nl/writing-components-in-flex-part-1/


编写Flex组件, part 2
http://labs.flexperiments.nl/writing-components-in-flex-part-2/


Actionscript 3 API 收集

http://flashenabledblog.com/2008/08/26/as3-actionscript-3-classes/


为展示对象创建 bitmap 数据对象

http://www.flexer.info/2008/08/20/how-to-make-a-bitmapdata-from-a-displayobjectuicomponent/


FCG 1.0 (Flex 代码生成器)

开源工具
http://www.dehats.com/drupal/?q=node/45


新的ActionScript 3 Singleton 函数

http://www.daniellove.net/blog/?p=81


CSKDebugger

Mac AIR 调试器
http://ultra-web.co.uk/?p=178


Fill Colors

Fill Colors 是一个分离Flex风格和布局工具,预览Flex应用外观皮肤。
http://www.fillcolors.com/


gTween

动画库 by Grant Skinner
http://www.gskinner.com/blog/archives/2008/08/gtween_a_new_tw.html


使用
Selenium来对AIR AJAX 应用做功能测试的框架
http://corlan.org/2008/08/15/functional-testing-framework-for-air-ajax-apps-based-on-selenium


Yahoo! Music API

The Yahoo! 音乐API给开发者权限来使用Yahoo! Music 目录。提供了多种方式浏览。
http://developer.yahoo.com/music/


ActionScript 3 灵活的布局类

The NpFlexLayout 类是设计用来简化DisplayObjects的布局。
http://www.blog.noponies.com/archives/109


mediacorelib -
ActionScript 3.0 核心媒体库
http://code.google.com/p/mediacorelib/


Servebox ActionScript Foundry

 ActionScript 3 / Java 框架为 Flex 2 应用设计,基于多个设计模式。
http://www.servebox.com/foundry/doku.php?id=


Flest Framework

Flest 是一个 ActionScript3 / Flex 应用框架,用来创建企业级别RIA应用。
http://code.google.com/p/flest/


Guasax Flex/AIR MVC - The MVC Flex/AIR Framework

Guasax是一个简单的框架提供可扩展的Flex应用。
http://www.guasax.com/guasax/web/en/index.php


Flex Mojos - HelloWorldTutorial

最简单的教程,创建一个HellowWorldFlex程序
http://code.google.com/p/flex-mojos/wiki/HelloWorldTutorial


Scott Evans - 对于新的 FlexBuilder 4 IDE 功能的公开讨论

Scott Evans, FlexBulder 团队的主导开发工程师,开始了一系列的新博客,讨论FlexBuilder 4 IDE 新功能,值得一看.
http://gettingandsetting.com/


dpHibernate - Hibernate lazy loading with Adobe BlazeDS

dpHibernate是一个定制的Flex库,和 custom BlazeDS Hibernate 一起使用提供对Flex应用内部的Hibernate对象 lazy loading(延迟加载)的支持。
http://blog.mikenimer.com/index.cfm/2008/5/21/dpHibernate–Hibernate-lazy-loading-with-Adobe-BlazeDS

http://code.google.com/p/dphibernate


Alternativa3D — browser 3D-engine based on Adobe Flash

Create 3D- 基于Flash场景 3D引擎。
http://alternativaplatform.com/en/alternativa3d/


KwikUML - build UML models of ActionScript and PHP classes

快速创建 ActionScript和PHP类,接口的 UML模型 的工具,以及提供SQL Entity关系设计 (ERDs).
http://labs.otuome.com/kwikuml


KitchenSync

KitchenSync 是一个 ActionScript 3.0 库,用来对动画排序以及其他基于时间的动作。
http://code.google.com/p/kitchensynclib/


as3xls - read and write Excel files in Flex

Flex读写excel文件工具

http://code.google.com/p/as3xls/


ASDebugger - A run-time debugger for AS3 Projects

AS 3项目的运行调试工具

http://labs.flexperiments.nl/asdebugger/


as3corelib update

这是一个ActionScript 3 库,包含很多有用的能使用在AS3中的 APIs 。
http://code.google.com/p/as3corelib/


swix framework - Flex development framework

Swiz 是一个简化RIA开发的Flex框架。
http://code.google.com/p/swizframework/


Gaia - open-source front-end Flash Framework for AS3 and AS2

Gaia 是一个开源的前台Flash框架,支持AS3和AS2,能够大量节省开发时间。
http://www.gaiaflashframework.com/


Penne Framework - lightweight framework for developing in Flex and Air

version 1.0 of The Penne Framework, 一个简单的 Flex and Air 框架, 是 Cairngorm 框架的备选方案.
http://www.flexpasta.com/index.php/2008/04/19/introducing-the-penne-framework-for-flex-3/


An ActionScript Compiler Written In ActionScript

一个用ActionScript写的ActionScript编译器
http://www.brooksandrus.com/blog/2008/08/27/an-actionscript-compiler-written-in-actionscript/

posted @ 2009-01-17 17:28 LaoH 阅读(2651) | 评论 (15)编辑 收藏
  2009年1月10日

<转>http://www.flexcoders.cn/ActionScript/thread-2769-1-1.aspx
AS3实例: LRC 歌词同步

一、准备工作
  既然要制作歌词同步程序,首先要准备一首歌,我们就以“周杰伦-青花瓷”为例。首先要下载这首“青花瓷.mp3”,保存为“C:\My Player\Music\青花瓷.mp3”。还要下载青花瓷的 LRC 文件,大家可以到网上下载(地址见附录),将文本内容保存为“C:\My Player\LRC\青花瓷.lrc”。我们的程序(类和FLA)则保存在“C:\My Player\”文件夹下。
青花瓷.lrc 文件:
[ti:青花瓷]
[ar:周杰伦]
[al:我很忙]
[by:张琪]
[00:00.00]发送短信18到291199下载该歌曲到手机
[00:01.11]青花瓷
[03:36.49]
[00:21.39]素眉勾勒秋千话北风龙转丹 
[00:26.08]屏层鸟绘的牡丹一如你梳妆
[00:30.46]黯然腾香透过窗心事我了然 
[00:34.93]宣纸上皱边直尺各一半
[00:39.49]油色渲染侍女图因为被失藏 
[00:43.83]而你嫣然的一笑如含苞待放
[00:48.30]你的美一缕飘散 
[00:50.77]去到我去不了的地方
[02:23.97][00:55.77]
[03:01.92][02:25.63][00:56.90]天正在等烟雨 
[03:03.57][02:27.91][00:58.99]而我在等你 
[03:05.92][02:30.44][01:00.93]炊烟袅袅升起 
[03:07.76][02:32.25][01:03.49]隔江千万里
[03:10.36][02:34.85][01:05.84]在平地书刻你房间上的飘影 
[03:14.67][02:38.73][01:09.87]就当我为遇见你伏笔
[03:18.83][02:43.35][01:14.34]天正在等烟雨 
[03:21.20][02:45.60][01:16.68]而我在等你 
[03:23.71][02:48.01][01:18.99]月色被打捞起 
[03:25.74][02:50.10][01:21.18]掩盖了结局
[03:28.33][02:52.54][01:23.72]如传世的青花瓷在独自美丽 
[03:32.30][02:56.67][01:27.65]你眼的笑意
[01:50.25]色白花青的景已跃然于碗底 
[01:54.69]临摹宋体落款时却惦记着你
[01:59.22]你隐藏在药效里一千年的秘密 
[02:03.75]急溪里犹如羞花沾落地
[02:08.32]林外芭蕉 惹咒语 
[02:10.57]梦幻的铜绿
[02:12.84]而我路过那江南小镇的等你
[02:17.19]在泼墨山水画里 
[02:19.75]你从墨色深处被隐去
  大家也可以把这个文本内容复制下来,然后在“C:\My Player\LRC\”下创建一个文本文档,将内容粘贴上去,再将文档保存为“青花瓷.lrc”,注意扩展名是“.lrc”。



二、LRC 内容分析
  准备工作完成了,下面分析一下这个 LRC 文件。之所以叫 LRC ,是因为它是 Lyric (歌词) 的缩写。这种格式真是一目了然,前面“[ ]”中的数字表示其后歌词的开始时间。例如,“[01:50.25]色白花青的景已跃然于碗底”表示在1分50.25秒时,歌词内容是“色白花青的景已跃然于碗底”。
  还有一种形式是“[03:01.92][02:25.63][00:56.90]天正在等烟雨”这种形式常用于赋格部分(俗称:歌曲的高潮部分),它表示在 03:01.92, 02:25.63, 00:56.90 时的歌词都是“天正在等烟雨”。由于这种形式的存在,使后面的编程稍显复杂,不过没关系,凭借各位的聪明智慧一定没问题。




三、预备知识
1. ActionScript 3 中默认使用 Unicode 来解码外部文件,如果读取的文本不是 Unicode 编码,而是按照操作系统代码页编写的,比如 GB2312,那么需要先导入 flash.system.System 类,并在加载外部文本的语句前将 System.useCodePage 设为 true,默认情况下为 false,即默认不使用操作系统页解码。
  如果 System.useCodePage = false 且外部 LRC 文件编码格式是 ANSI 的话,那么显示的中文歌词会是乱码。解决办法有两个:一是,将外部 LRC 文件编码格式改为 Unicode;二是,不改变外部文件编码格式,只在文档类中加入一句 System.useCodePage=true 即可。由于后一种方法使用简便,我们就采用第二种方法。




2.读取声音:
var sound:Sound=new Sound();
sound.load(new URLRequest("Music/青花瓷.mp3"));




3.播放声音及获取当前播放时间(毫秒):
var sc:SoundChannel;
var sound:Sound=new Sound();
sound.load(new URLRequest("Music/青花瓷.mp3"));
sc=sound.play();
stage.addEventListener(Event.ENTER_FRAME,EnterFrame);

function EnterFrame(evt:Event):void {
trace(sc.position);
}
这里将 sc 声明为全局变量(或类变量),因为在多个方法中都要使用它。




4.读取外部文件:
var loader:URLLoader=new URLLoader();
loader.load(new URLRequest("LRC/青花瓷.lrc"));
loader.addEventListener(Event.COMPLETE,LoadFinish);
function LoadFinish(evt:Event):void {
 trace(evt.target.data);
}




5.将字符串按分隔符分隔为数组(String.split):
var str:String="FL Basic Theory Master";
var array:Array=str.split(" ");
trace(array);
//输出数组:[[FL],[Basic],[Theory],[Master]]
str=" http://blog.sina.com.cn/yyy98";
array=str.split(".");
trace(array);
//输出数组:[[http://blog],[sina,com],[cn/yyy98]]




6.简单的正则表达式应用:
1>获取匹配次数:
var Pattern:RegExp=/Window/g;
//意思是所有名为“Window”的字符串
var str:String="Windows seems like a Window, so called Windows OS! ";
trace(str.match(Pattern).length)
//结果:3
2>获取正确匹配:
var foo:RegExp=/[0-3][0-9]\/[0-1][0-9]\/[0-2][0-9][0-9][0-9]/g;
//意思是所有格式为“日/月/年”的字符串
var str:String="Date Format: 2006/12/25 2006-12-25 12/25/2007 25/12/2007"
trace(str.match(foo))
//结果:25/12/2007




7.字符串取子串操作(String.substr):
var str:String="[03:01.92][02:25.63][00:56.90]天正在等烟雨";
trace(str.substr(0,30));
//从0号索引开始,取30个字符
//结果:[03:01.92][02:25.63][00:56.90]
trace(str.substr(30));
//只写一个参数,表示从该索引处到字符串结束位置
//结果:天正在等烟雨




8.数组排序中比较函数的应用:
var a:Object={price:20,number:3};
var b:Object={price:10,number:7};
var c:Object={price:50,number:1};
var amountAry:Array=[a,b,c];
function compare(paraA:Object,paraB:Object):int {
 var resultA =paraA.price*paraA.number;
 var resultB =paraB.price*paraB.number;
 if (resultA > resultB) return 1;  
 if (resultA < resultB) return -1;
 return 0;
}
amountAry.sort(compare);
trace(amountAry[0].price);  //输出:50
trace(amountAry[1].price);  //输出:20
trace(amountAry[2].price);  //输出:10






四、LRC 的读取与存储转换(使用文档类设计)
1.读取 LRC 文件,这一步非常简单与读取普通的文本文件是一样的;
public function LRCPlayer() {
 var loader:URLLoader=new URLLoader();
 loader.load(new URLRequest("LRC/青花瓷.lrc"));
 loader.addEventListener(Event.COMPLETE,LoadFinish);

}
function LoadFinish(evt:Event):void {
 trace(evt.target.data);
}
2.将读取的 LRC 数据按行分割( "\n" 为换行符),数组的每一个元素代表 LRC 的一行内容;
function LoadFinish(evt:Event):void {
 var list:String=evt.target.data;
var listarray:Array=list.split("\n");
 trace(listarray);
}
3.在数组中提取每一行的时间及歌词,解决单时间序列的问题;

(注意!此段代码只作讲解,不以应用)
LRC 内容如下:
[00:43.83]而你嫣然的一笑如含苞待放
[00:48.30]你的美一缕飘散 
[00:50.77]去到我去不了的地方
[03:01.92]天正在等烟雨 
[03:03.57]而我在等你 
[03:05.92]炊烟袅袅升起 
[03:07.76]隔江千万里
代码如下:
function LoadFinish(evt:Event):void {
 var list:String=evt.target.data;
 var listarray:Array=list.split("\n");
 for (var i=0; i < listarray.length; i++) {
  var info:String=listarray[i];
  //提取每行内容,用变量 info 保存
  var lyric:String=info.substr(10);
  //将歌词内容提取到 lyric 变量中
  var ctime:String =info.substr(0,10);
  //提取时间序列字串
  var ntime:Number=Number(ctime.substr(1,2))*60+Number(ctime.substr(4,5));
  //将时间字串转换为计算机可读取的时间
  var obj:Object=new Object();
  obj.timer=ntime*1000;
  obj.lyric=lyric;
  LRCarray.push(obj);
  //将时间与歌词保存到一个 Object 中,并压入LRCarray 数组
  trace(obj.timer,obj.lyric);
 }
}
输出结果:
43830 而你嫣然的一笑如含苞待放
48300 你的美一缕飘散
50770 去到我去不了的地方
181920 天正在等烟雨
183570 而我在等你
185920 炊烟袅袅升起
187760 隔江千万里
4.在LRC文件,还有多时间序列的存在,所以单时间序列算法不能满足实际需要,下面就来解决多时间序列问题;
LRC 内容如下:
[00:43.83]而你嫣然的一笑如含苞待放
[00:48.30]你的美一缕飘散 
[00:50.77]去到我去不了的地方
[03:01.92][02:25.63][00:56.90]天正在等烟雨 
[03:03.57][02:27.91][00:58.99]而我在等你 
[03:05.92][02:30.44][01:00.93]炊烟袅袅升起 
[03:07.76][02:32.25][01:03.49]隔江千万里
代码如下:
function LoadFinish(evt:Event):void {
 var list:String=evt.target.data;
 var listarray:Array=list.split("\n");
 var reg:RegExp=/\[[0-5][0-9]:[0-5][0-9].[0-9][0-9]\]/g;
 //建立正则表达式,范围:[00:00.00]~[59:59.99]
 for (var i=0; i < listarray.length; i++) {
  var info:String=listarray[i];
  //提取每行内容,用变量 info 保存
  var len:int=info.match(reg).length;
  //该行拥有时间序列的个数
  var timeAry:Array=info.match(reg);
  //将匹配的时间序列保存到 timeAry 数组中
  var lyric:String=info.substr(len*10);
  //根据每个时间序列占10个字符,找出歌词内容的起点


  //将歌词提取到 lyric 变量中
  for (var k:int=0; k < timeAry.length; k++) {
  var obj:Object=new Object();
   var ctime:String=timeAry[k];
   var ntime:Number=Number(ctime.substr(1,2))*60+Number(ctime.substr(4,5));
   obj.timer=ntime*1000;
   obj.lyric=lyric;
   LRCarray.push(obj);
   trace(obj.timer,obj.lyric);

  }
  //将时间序列转换为毫秒并与歌词一起保存为一个数组元素
 }
}
输出结果:
43830 而你嫣然的一笑如含苞待放
48300 你的美一缕飘散 
50770 去到我去不了的地方
181920 天正在等烟雨 
145630 天正在等烟雨 
56900 天正在等烟雨 
183570 而我在等你 
147910 而我在等你 
58990 而我在等你 
185920 炊烟袅袅升起 
150440 炊烟袅袅升起 
60930 炊烟袅袅升起 
187760 隔江千万里
152250 隔江千万里
63490 隔江千万里
5.将获得的 LRCarray 数组按起始时间排序,这对于按序读取歌词有重要意义;
LRCarray.sort(compare);
private function compare(paraA:Object,paraB:Object):int{
 if (paraA.timer > paraB.timer) {
  return 1;
 }
 if (paraA.timer < paraB.timer) {
  return -1;
 }
 return 0;
}
结果如下:
43830 而你嫣然的一笑如含苞待放
48300 你的美一缕飘散
50770 去到我去不了的地方
56900 天正在等烟雨
58990 而我在等你
60930 炊烟袅袅升起
63490 隔江千万里
145630 天正在等烟雨
147910 而我在等你
150440 炊烟袅袅升起
152250 隔江千万里
181920 天正在等烟雨
183570 而我在等你
185920 炊烟袅袅升起
187760 隔江千万里
6.最后,随着音乐的播放,读取播放时间段内的歌词。用当前播放时间与 LRCarray 中的时间相比较,如果当前时间小于 LRCarray[i].timer 的时间,那么就显示 LRCarray[i-1].lyric 的歌词。为什么要显示 [i-1] 的歌词呢?比如说当前播放到第 500 秒,读取的 LRCarray[20].timer 时间是 400 秒,那么 i++ 。下一次读取的 LRCarray[21].timer 时间是 700 秒,这时当前播放时间小于读取的这个时间,就说明当前的第 500 秒仍处于 LRCarray[20].timer 的时间范围内。
var lrc_txt:TextField=new TextField();
var LRCarray:Array=new Array();
var sc:SoundChannel;
public function LRCPlayer() {
 lrc_txt.width=500;
 lrc_txt.selectable=false;
 addChild(lrc_txt);
 //歌词在文本 lrc_txt 中显示
 var loader:URLLoader=new URLLoader();
 loader.load(new URLRequest("LRC/青花瓷.lrc"));
 loader.addEventListener(Event.COMPLETE,LoadFinish);
 var sound:Sound=new Sound();
 sound.load(new URLRequest("Music/青花瓷.mp3"));
 sc=sound.play();
 //播放声音,并生成 sc 变量,SoundChannel 类的实例
 stage.addEventListener(Event.ENTER_FRAME,SoundPlaying);
 //实时刷新歌词
}
function SoundPlaying(evt:Event):void {
 for (var i=1; i < LRCarray.length; i++) {
  if (sc.position < LRCarray[i].timer) {
   lrc_txt.text=LRCarray[i-1].lyric;
   break;
 
//找到歌词,跳出循环体
  }
  lrc_txt.text=LRCarray[LRCarray.length-1].lyric;
  //找不到歌词,说明已超出了最后一句的时间,因此显示最后一句歌词
 }
}




五、全部代码(文档类 LRCPlayer.as):
package {
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.events.Event;
import flash.text.TextField;
import flash.system.System;
public class LRCPlayer extends Sprite {
var lrc_txt:TextField=new TextField();
var LRCarray:Array=new Array();
var sc:SoundChannel;
public function LRCPlayer() {
 System.useCodePage=true;
 lrc_txt.width=500;
 lrc_txt.selectable=false;
 addChild(lrc_txt);
 var loader:URLLoader=new URLLoader();
 loader.load(new URLRequest("LRC/青花瓷.lrc"));
 loader.addEventListener(Event.COMPLETE,LoadFinish);
 var sound:Sound=new Sound();
 sound.load(new URLRequest("Music/青花瓷.mp3"));
 sc=sound.play();
 stage.addEventListener(Event.ENTER_FRAME,SoundPlaying);
}
function SoundPlaying(evt:Event):void {
 for (var i=1; i < LRCarray.length; i++) {
  if (sc.position < LRCarray[i].timer) {
   lrc_txt.text=LRCarray[i-1].lyric;
   break;
  }
  lrc_txt.text=LRCarray[LRCarray.length-1].lyric;
 }
}
function LoadFinish(evt:Event):void {
 var list:String=evt.target.data;
 var listarray:Array=list.split("\n");
 var reg:RegExp=/\[[0-5][0-9]:[0-5][0-9].[0-9][0-9]\]/g;
 for (var i=0; i < listarray.length; i++) {
  var info:String=listarray[i];
  var len:int=info.match(reg).length;
  var timeAry:Array=info.match(reg);
  var lyric:String=info.substr(len*10);
  for (var k:int=0; k < timeAry.length; k++) {
   var obj:Object=new Object();
   var ctime:String=timeAry[k];
   var ntime:Number=Number(ctime.substr(1,2))*60+Number(ctime.substr(4,5));
   obj.timer=ntime*1000;
   obj.lyric=lyric;
   LRCarray.push(obj);
  }
 }
 LRCarray.sort(compare);
}
private function compare(paraA:Object,paraB:Object):int {
 if (paraA.timer > paraB.timer) {
  return 1;
 }
 if (paraA.timer < paraB.timer) {
  return -1;
 }
 return 0;
}
}
}




六、*无处不在的优化
  至此,该程序已经可以顺利执行了,此处只讨论一下优化问题,看不懂可以跳过。
以这段代码为例:
function SoundPlaying(evt:Event):void {
for (var i=1; i < LRCarray.length; i++) {
 if (sc.position < LRCarray[i].timer) {
  lrc_txt.text=LRCarray[i-1].lyric;
  break;
 }
 lrc_txt.text=LRCarray[LRCarray.length-1].lyric;
}
}
如果要进行优化,那么这个 for 循环,应该写成:
for (var i=1,j=LRCarray.length; i < j; i++) {… …}
这样在执行判断时,不必每次都进行 LRCarray.length 操作,该操用于读取数组长度,执行 Array 类的 length 方法,属于高级操作,花费的时间要比低级操作多。其实,只要读取一次长度,然后将结果保存在变量 j 中,每次判断时读取 j 的值即可。取值与赋值都属于低级别的操作,速度较快。同样的道理,在 if (sc.position < LRCarray[i].timer) {… …} 中的 sc.position 在每次判断时都要读取一遍,这时就应将它在循环之前保存到一个变量里,这段代码优化后应是这样:
function SoundPlaying(evt:Event):void {
var now:Number=sc.position;
for (var i=1,j=LRCarray.length; i < j; i++) {
 if (now < LRCarray[i].timer) {
  lrc_txt.text=LRCarray[i-1].lyric;
  break;
 }
 lrc_txt.text=LRCarray[j-1].lyric;
}
}
  在我们的文档类中还有几个地方用到了 for 循环,请大家按照上述方法自行优化。
  其实,代码优化无处不在,其中的学问不胜枚举,有兴趣的朋友可以到我的博客中看一下关于代码优化的总结贴,见附录。



七、附录
LRC 文件下载地址:
http://lrc.bzmtv.com/

http://www.5ilrc.com/


至于 MP3 的下载,我想大家比我在行,用百度或酷狗都可以。

整个文件包括(歌曲、歌词、LRCPlayer.as 、FLA 文件)本帖附件中下载
下载附件:My Player.part1.rar

下载附件:My Player.part2.rar

下载附件:My Player.part3.rar

下载附件:My Player.part4.rar


八、结束语
  恭喜您坚持到了现在,确实内容比较长,同时也涉及了一些知识点。其实做法肯定不只这一种,所以希望大家多多发挥主观能动性,结合上述内容继续将这个播放程序做大做强。好了,就到这里,再次感谢。
posted @ 2009-01-10 11:11 LaoH 阅读(2154) | 评论 (1)编辑 收藏
  2008年12月22日
     摘要: SqlMapClient对象 这个对象是iBatis操作数据库的接口(执行CRUD等操作),它也可以执行事务管理等操作。这个类是我们使用iBATIS的最主要的类。它是线程安全的。通常,将它定义为单例。(与hibernate中sessionFactory的定义类似)。如: import java.io.Rea...  阅读全文
posted @ 2008-12-22 10:42 LaoH 阅读(15690) | 评论 (0)编辑 收藏
  2008年12月17日
给出整数,返回对应的字符;
SQL> select chr(54740) zhao,chr(65) chr65 from dual; ZH C
-- -
赵 A 3.CONCAT
连接两个字符串;
SQL> select concat('010-','88888888')'转23'  高乾竞电话 from dual; 高乾竞电话
----------------
010-88888888转23 4.INITCAP
返回字符串并将字符串的第一个字母变为大写;
SQL> select initcap('smith') upp from dual; UPP
-----
Smith
5.INSTR(C1,C2,I,J)
在一个字符串中搜索指定的字符,返回发现指定的字符的位置;
C1    被搜索的字符串
C2    希望搜索的字符串
I     搜索的开始位置,默认为1
J     出现的位置,默认为1
SQL> select instr('Oracle traning','ra',1,2) instring from dual;  INSTRING
---------
        9
6.LENGTH
返回字符串的长度;
SQL> select name,length(name),addr,length(addr),sal,length(to_char(sal)) from gao.nchar_tst; NAME   LENGTH(NAME) ADDR             LENGTH(ADDR)       SAL LENGTH(TO_CHAR(SAL))
------ ------------ ---------------- ------------ --------- --------------------
高乾竞            3 北京市海锭区                6   9999.99                    7 7.LOWER
返回字符串,并将所有的字符小写
SQL> select lower('AaBbCcDd')AaBbCcDd from dual; AABBCCDD
--------
aabbccdd
8.UPPER
返回字符串,并将所有的字符大写
SQL> select upper('AaBbCcDd') upper from dual; UPPER
--------
AABBCCDD 9.RPAD和LPAD(粘贴字符)
RPAD  在列的右边粘贴字符
LPAD  在列的左边粘贴字符
SQL> select lpad(rpad('gao',10,'*'),17,'*')from dual; LPAD(RPAD('GAO',1
-----------------
*******gao*******
不够字符则用*来填满
10.LTRIM和RTRIM
LTRIM  删除左边出现的字符串
RTRIM  删除右边出现的字符串
SQL> select ltrim(rtrim('   gao qian jing   ',' '),' ') from dual;
LTRIM(RTRIM('
-------------
gao qian jing
11.SUBSTR(string,start,count)
取子字符串,从start开始,取count个
SQL> select substr('13088888888',3,8) from dual; SUBSTR('
--------
08888888
12.REPLACE('string','s1','s2')
string   希望被替换的字符或变量
s1       被替换的字符串
s2       要替换的字符串
SQL> select replace('he love you','he','i') from dual; REPLACE('H
----------
i love you
13.SOUNDEX
返回一个与给定的字符串读音相同的字符串
SQL> create table table1(xm varchar(8));
SQL> insert into table1 values('weather');
SQL> insert into table1 values('wether');
SQL> insert into table1 values('gao'); SQL> select xm from table1 where soundex(xm)=soundex('weather'); XM
--------
weather
wether
14.TRIM('s' from 'string')
LEADING   剪掉前面的字符
TRAILING  剪掉后面的字符
假如不指定,默认为空格符 15.ABS
返回指定值的绝对值
SQL> select abs(100),abs(-100) from dual;  ABS(100) ABS(-100)
--------- ---------
      100       100
16.ACOS
给出反余弦的值
SQL> select acos(-1) from dual;  ACOS(-1)
---------
3.1415927
17.ASIN
给出反正弦的值
SQL> select asin(0.5) from dual; ASIN(0.5)
---------
.52359878
18.ATAN
返回一个数字的反正切值
SQL> select atan(1) from dual;   ATAN(1)
---------
.78539816
19.CEIL
返回大于或等于给出数字的最小整数
SQL> select ceil(3.1415927) from dual; CEIL(3.1415927)
---------------
              4
20.COS
返回一个给定数字的余弦
SQL> select cos(-3.1415927) from dual; COS(-3.1415927)
---------------
             -1
21.COSH
返回一个数字反余弦值
SQL> select cosh(20) from dual;  COSH(20)
---------
242582598
22.EXP
返回一个数字e的n次方根
SQL> select exp(2),exp(1) from dual;    EXP(2)    EXP(1)
--------- ---------
7.3890561 2.7182818
23.FLOOR
对给定的数字取整数
SQL> select floor(2345.67) from dual; FLOOR(2345.67)
--------------
          2345
24.LN
返回一个数字的对数值
SQL> select ln(1),ln(2),ln(2.7182818) from dual;
    LN(1)     LN(2) LN(2.7182818)
--------- --------- -------------
        0 .69314718     .99999999
25.LOG(n1,n2)
返回一个以n1为底n2的对数
SQL> select log(2,1),log(2,4) from dual;  LOG(2,1)  LOG(2,4)
--------- ---------
        0         2
26.MOD(n1,n2)
返回一个n1除以n2的余数
SQL> select mod(10,3),mod(3,3),mod(2,3) from dual; MOD(10,3)  MOD(3,3)  MOD(2,3)
--------- --------- ---------
        1         0         2
27.POWER
返回n1的n2次方根
SQL> select power(2,10),power(3,3) from dual; POWER(2,10) POWER(3,3)
----------- ----------
       1024         27
28.ROUND和TRUNC
按照指定的精度进行舍入
SQL> select round(55.5),round(-55.4),trunc(55.5),trunc(-55.5) from dual; ROUND(55.5) ROUND(-55.4) TRUNC(55.5) TRUNC(-55.5)
----------- ------------ ----------- ------------
         56          -55          55          -55
29.SIGN
取数字n的符号,大于0返回1,小于0返回-1,等于0返回0
SQL> select sign(123),sign(-100),sign(0) from dual; SIGN(123) SIGN(-100)   SIGN(0)
--------- ---------- ---------
        1         -1         0
30.SIN
返回一个数字的正弦值
SQL> select sin(1.57079) from dual; SIN(1.57079)
------------
           1
31.SIGH
返回双曲正弦的值
SQL> select sin(20),sinh(20) from dual;   SIN(20)  SINH(20)
--------- ---------
.91294525 242582598
32.SQRT
返回数字n的根
SQL> select sqrt(64),sqrt(10) from dual;  SQRT(64)  SQRT(10)
--------- ---------
        8 3.1622777
33.TAN
返回数字的正切值
SQL> select tan(20),tan(10) from dual;   TAN(20)   TAN(10)
--------- ---------
2.2371609 .64836083
34.TANH
返回数字n的双曲正切值
SQL> select tanh(20),tan(20) from dual;  TANH(20)   TAN(20)
--------- ---------
        1 2.2371609 35.TRUNC
按照指定的精度截取一个数
SQL> select trunc(124.1666,-2) trunc1,trunc(124.16666,2) from dual;
   TRUNC1 TRUNC(124.16666,2)
--------- ------------------
      100             124.16 36.ADD_MONTHS
增加或减去月份
SQL> select to_char(add_months(to_date('199912','yyyymm'),2),'yyyymm') from dual; TO_CHA
------
200002
SQL> select to_char(add_months(to_date('199912','yyyymm'),-2),'yyyymm') from dual; TO_CHA
------
199910
37.LAST_DAY
返回日期的最后一天
SQL> select to_char(sysdate,'yyyy.mm.dd'),to_char((sysdate)+1,'yyyy.mm.dd') from dual; TO_CHAR(SY TO_CHAR((S
---------- ----------
2004.05.09 2004.05.10
SQL> select last_day(sysdate) from dual; LAST_DAY(S
----------
31-5月 -04
38.MONTHS_BETWEEN(date2,date1)
给出date2-date1的月份
SQL> select months_between('19-12月-1999','19-3月-1999') mon_between from dual; MON_BETWEEN
-----------
          9
SQL>selectmonths_between(to_date('2000.05.20','yyyy.mm.dd'),to_date('2005.05.20','yyyy.mm.dd')) mon_betw from dual;  MON_BETW
---------
      -60
39.NEW_TIME(date,'this','that')
给出在this时区=other时区的日期和时间
SQL> select to_char(sysdate,'yyyy.mm.dd hh24:mi:ss') bj_time,to_char(new_time
  2  (sysdate,'PDT','GMT'),'yyyy.mm.dd hh24:mi:ss') los_angles from dual; BJ_TIME             LOS_ANGLES
------------------- -------------------
2004.05.09 11:05:32 2004.05.09 18:05:32
40.NEXT_DAY(date,'day')
给出日期date和星期x之后计算下一个星期的日期
SQL> select next_day('18-5月-2001','星期五') next_day from dual; NEXT_DAY
----------
25-5月 -01 41.SYSDATE
用来得到系统的当前日期
SQL> select to_char(sysdate,'dd-mm-yyyy day') from dual; TO_CHAR(SYSDATE,'
-----------------
09-05-2004 星期日
trunc(date,fmt)按照给出的要求将日期截断,假如fmt='mi'表示保留分,截断秒
SQL> select to_char(trunc(sysdate,'hh'),'yyyy.mm.dd hh24:mi:ss') hh,
  2  to_char(trunc(sysdate,'mi'),'yyyy.mm.dd hh24:mi:ss') hhmm from dual; HH                  HHMM
------------------- -------------------
2004.05.09 11:00:00 2004.05.09 11:17:00 42.CHARTOROWID
将字符数据类型转换为ROWID类型
SQL> select rowid,rowidtochar(rowid),ename from scott.emp; ROWID              ROWIDTOCHAR(ROWID) ENAME
------------------ ------------------ ----------
AAAAfKAACAAAAEqAAA AAAAfKAACAAAAEqAAA SMITH
AAAAfKAACAAAAEqAAB AAAAfKAACAAAAEqAAB ALLEN
AAAAfKAACAAAAEqAAC AAAAfKAACAAAAEqAAC WARD
AAAAfKAACAAAAEqAAD AAAAfKAACAAAAEqAAD JONES
43.CONVERT(c,dset,sset)
将源字符串 sset从一个语言字符集转换到另一个目的dset字符集
SQL> select convert('strutz','we8hp','f7dec') "conversion" from dual;
conver
------
strutz
44.HEXTORAW
将一个十六进制构成的字符串转换为二进制
45.RAWTOHEXT
将一个二进制构成的字符串转换为十六进制 46.ROWIDTOCHAR
将ROWID数据类型转换为字符类型 47.TO_CHAR(date,'format')
SQL> select to_char(sysdate,'yyyy/mm/dd hh24:mi:ss') from dual; TO_CHAR(SYSDATE,'YY
-------------------
2004/05/09 21:14:41 48.TO_DATE(string,'format')
将字符串转化为ORACLE中的一个日期
49.TO_MULTI_BYTE
将字符串中的单字节字符转化为多字节字符
SQL>  select to_multi_byte('高') from dual; TO
--

50.TO_NUMBER
将给出的字符转换为数字
SQL> select to_number('1999') year from dual;      YEAR
---------
     1999
51.BFILENAME(dir,file)
指定一个外部二进制文件
SQL>insert into file_tb1 values(bfilename('lob_dir1','image1.gif'));
52.CONVERT('x','desc','source')
将x字段或变量的源source转换为desc
SQL> select sid,serial#,username,decode(command,
  2  0,'none',
  3  2,'insert',
  4  3,
  5  'select',
  6  6,'update',
  7  7,'delete',
  8  8,'drop',
  9  'other') cmd  from v$session where type!='background';       SID   SERIAL# USERNAME                       CMD
--------- --------- ------------------------------ ------
        1         1                                none
        2         1                                none
        3         1                                none
        4         1                                none
        5         1                                none
        6         1                                none
        7      1275                                none
        8      1275                                none
        9        20 GAO                            select
       10        40 GAO                            none

53.DUMP(s,fmt,start,length)
DUMP函数以fmt指定的内部数字格式返回一个VARCHAR2类型的值
SQL> col global_name for a30
SQL> col dump_string for a50
SQL> set lin 200
SQL> select global_name,dump(global_name,1017,8,5) dump_string from global_name; GLOBAL_NAME                    DUMP_STRING
------------------------------ --------------------------------------------------
ORACLE.WORLD                   Typ=1 Len=12 CharacterSet=ZHS16GBK: W,O,R,L,D
54.EMPTY_BLOB()和EMPTY_CLOB()
这两个函数都是用来对大数据类型字段进行初始化操作的函数
55.GREATEST
返回一组表达式中的最大值,即比较字符的编码大小.
SQL> select greatest('AA','AB','AC') from dual; GR
--
AC
SQL> select greatest('啊','安','天') from dual; GR
--

56.LEAST
返回一组表达式中的最小值
SQL> select least('啊','安','天') from dual; LE
--

57.UID
返回标识当前用户的唯一整数
SQL> show user
USER 为"GAO"
SQL> select username,user_id from dba_users where user_id=uid; USERNAME                         USER_ID
------------------------------ ---------
GAO                                   25 58.USER
返回当前用户的名字
SQL> select user from  dual; USER
------------------------------
GAO
59.USEREVN
返回当前用户环境的信息,opt可以是:
ENTRYID,SESSIONID,TERMINAL,ISDBA,LABLE,LANGUAGE,CLIENT_INFO,LANG,VSIZE
ISDBA  查看当前用户是否是DBA假如是则返回true
SQL> select userenv('isdba') from dual; USEREN
------
FALSE
SQL> select userenv('isdba') from dual; USEREN
------
TRUE
SESSION
返回会话标志
SQL> select userenv('sessionid') from dual; USERENV('SESSIONID')
--------------------
                 152
ENTRYID
返回会话人口标志
SQL> select userenv('entryid') from dual; USERENV('ENTRYID')
------------------
                 0
INSTANCE
返回当前INSTANCE的标志
SQL> select userenv('instance') from dual; USERENV('INSTANCE')
-------------------
                  1
LANGUAGE
返回当前环境变量
SQL> select userenv('language') from dual;
USERENV('LANGUAGE')
----------------------------------------------------
SIMPLIFIED CHINESE_CHINA.ZHS16GBK
LANG
返回当前环境的语言的缩写
SQL> select userenv('lang') from dual; USERENV('LANG')
----------------------------------------------------
ZHS
TERMINAL
返回用户的终端或机器的标志
SQL> select userenv('terminal') from dual; USERENV('TERMINA
----------------
GAO
VSIZE(X)
返回X的大小(字节)数
SQL> select vsize(user),user from dual; VSIZE(USER) USER
----------- ------------------------------
          6 SYSTEM 60.AVG(DISTINCTALL)
all表示对所有的值求平均值,distinct只对不同的值求平均值
SQLWKS> create table table3(xm varchar(8),sal number(7,2));
语句已处理。
SQLWKS>  insert into table3 values('gao',1111.11);
SQLWKS>  insert into table3 values('gao',1111.11);
SQLWKS>  insert into table3 values('zhu',5555.55);
SQLWKS> commit; SQL> select avg(distinct sal) from gao.table3; AVG(DISTINCTSAL)
----------------
         3333.33 SQL> select avg(all sal) from gao.table3; AVG(ALLSAL)
-----------
    2592.59
61.MAX(DISTINCTALL)
求最大值,ALL表示对所有的值求最大值,DISTINCT表示对不同的值求最大值,相同的只取一次
  返回选择列表项目的最大值,假如x是字符串数据类型,他返回一个VARCHAR2数据类型,假如X是一个DATA数据类型,返回一个日期,假如X是numeric数据类型,返回一个数字。注重distinct和all不起作用,应为最大值与这两种设置是相同的。
SQL> select max(distinct sal) from scott.emp; MAX(DISTINCTSAL)
----------------
            5000
62.MIN(DISTINCTALL)
求最小值,ALL表示对所有的值求最小值,DISTINCT表示对不同的值求最小值,相同的只取一次
SQL> select min(all sal) from gao.table3; MIN(ALLSAL)
-----------
    1111.11
63.STDDEV(distinctall)
求标准差,ALL表示对所有的值求标准差,DISTINCT表示只对不同的值求标准差
SQL> select stddev(sal) from scott.emp; STDDEV(SAL)
-----------
  1182.5032 SQL> select stddev(distinct sal) from scott.emp; STDDEV(DISTINCTSAL)
-------------------
           1229.951 64.VARIANCE(DISTINCTALL)
求协方差 SQL> select variance(sal) from scott.emp; VARIANCE(SAL)
-------------
    1398313.9
65.GROUP BY
主要用来对一组数进行统计
SQL> select deptno,count(*),sum(sal) from scott.emp group by deptno;    DEPTNO  COUNT(*)  SUM(SAL)
--------- --------- ---------
       10         3      8750
       20         5     10875
       30         6      9400
66.HAVING
对分组统计再加限制条件
SQL> select deptno,count(*),sum(sal) from scott.emp group by deptno having count(*)>=5;    DEPTNO  COUNT(*)  SUM(SAL)
--------- --------- ---------
       20         5     10875
       30         6      9400
SQL> select deptno,count(*),sum(sal) from scott.emp having count(*)>=5 group by deptno ;    DEPTNO  COUNT(*)  SUM(SAL)
--------- --------- ---------
       20         5     10875
       30         6      9400
67.ORDER BY
用于对查询到的结果进行排序输出
SQL> select deptno,ename,sal from scott.emp order by deptno,sal desc;    DEPTNO ENAME            SAL
--------- ---------- ---------
       10 KING            5000
       10 CLARK           2450
       10 MILLER          1300
       20 SCOTT           3000
       20 FORD            3000
       20 JONES           2975
       20 ADAMS           1100
       20 SMITH            800
       30 BLAKE           2850
       30 ALLEN           1600
       30 TURNER          1500
       30 WARD            1250
       30 MARTIN          1250
       30 JAMES            950 
 
posted @ 2008-12-17 13:20 LaoH 阅读(380) | 评论 (0)编辑 收藏
  2008年12月16日

文章来源(IBM中国)

1、介绍

在这一节中,我们将分析两个进行点对点消息接发的程序—— QSender.java 和 QReceiver.java。

我们将在一些小节中分析代码并描述每一小节的功能。

2、QSender:提示输入 JNDI 名称~

这两个示例程序都是命令行程序, 用 System.in 输入、用 System.out 输出。 QSender 类有两个方法:main(String[]) 和 send()。main(String[]) 方法只举例说明了 QSender ,并调用了它的 send() 方法。send() 方法的第一部分提示输入用来发送消息受管理对象的 JNDI 的名称。

  1. import java.io.*;   
  2. import javax.jms.*;   
  3. import javax.naming.*;   
  4.   
  5. public class QSender {   
  6.   
  7.     public static void main(String[] args) {   
  8.   
  9.         new QSender().send();   
  10.     }   
  11.   
  12.     public void send() {   
  13.   
  14.         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));   
  15.   
  16.         try {   
  17.             //Prompt for JNDI names   
  18.             System.out.println("Enter QueueConnectionFactory name:");   
  19.             String factoryName = reader.readLine();   
  20.             System.out.println("Enter Queue name:");   
  21.             String queueName = reader.readLine();   
  22.     . . .  

3、QSender查找管理对象 

send() 方法的第二部分用前面输入的名字在 JNDI 中查找受管理的对象。通过举例说明 InitialContext 对象访问 JNDI,通过调用lookup(String) 方法并传递要获取的对象的名字来检索受管理的对象。注意, lookup(String) 方法返回的是 Object,所以必须对返回的对象进行类型强制转换。


 

  1. . . .   
  2.         //Look up administered objects   
  3.         InitialContext initContext = new InitialContext();   
  4.         QueueConnectionFactory factory =   
  5.             (QueueConnectionFactory) initContext.lookup(factoryName);   
  6.         Queue queue = (Queue) initContext.lookup(queueName);   
  7.         initContext.close();   
  8.         . . .   

4、QSender:创建 JMS 对象

现在,我们已创建了发送消息所需要的 JMS 对象。注意,我们没有用 new 直接举例说明这些对象。所有对象都是通过调用另一个对象的方法创建的。
首先,用 QueueConnectionFactory 创建 QueueConnection。然后用 QueueConnection 创建一个 QueueSession。
QueueSession 不是经过处理的(false),并且它将使用自动确认 (Session.AUTO_ACKNOWLEDGE)。
最后,创建 QueueSender 将信息发送到从 JNDI 中检索的 Queue 发送消息。

  1. . . .   
  2.         //Create JMS objects   
  3.         QueueConnection connection = factory.createQueueConnection();   
  4.         QueueSession session =   
  5.             connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);   
  6.         QueueSender sender = session.createSender(queue);   
  7.         . . .  

5、QSender:发送消息

现在就可以发送消息了。在这一部分中,我们进入一个循环,该循环提示我们要发送的消息的文本。如果用户输入 quit,则退出循环。

否则要在输入的文本中建立一个 TextMessage ,并用 QueueSender 发送消息,然后返回循环的开始部分。

  1. . . .   
  2.         //Send messages   
  3.         String messageText = null;   
  4.         while (true) {   
  5.             System.out.println("Enter message to send or 'quit':");   
  6.             messageText = reader.readLine();   
  7.             if ("quit".equals(messageText))   
  8.                 break;   
  9.             TextMessage message = session.createTextMessage(messageText);   
  10.             sender.send(message);   
  11.         }   
  12.         . . .   

 6、QSender:退出

退出循环后,关闭 QueueConnection。关闭 QueueConnection 会自动关闭 QueueSession 和 QueueSender。

java 代码
  1. . . .   
  2.         //Exit   
  3.         System.out.println("Exiting...");   
  4.         reader.close();   
  5.         connection.close();   
  6.         System.out.println("Goodbye!");   
  7.   
  8.     } catch (Exception e) {   
  9.         e.printStackTrace();   
  10.         System.exit(1);   
  11.     }   
  12. }   

7、QReceiver提示输入 JNDI 名称并查找受管理的对象

QReceiver 类与 QSender 类非常类似,都有一个 main(String[]) 方法,它只举例说明 QReceiver 并调用了它的主要方法 receive()。

提示输入 JNDI 名字并查找受管理对象的代码与 QSender 中的代码完全一样。
不过,在这个类中有两处不一样的地方:
boolean stop 实例变量被用来指出程序应该退出。
QReceiver 可以实现 MessageListener 接口来异步接收消息。

  1. import java.io.*;   
  2. import javax.jms.*;   
  3. import javax.naming.*;   
  4.   
  5. public class QReceiver implements MessageListener {   
  6.   
  7.     private boolean stop = false;   
  8.   
  9.     public static void main(String[] args) {   
  10.   
  11.         new QReceiver().receive();   
  12.     }   
  13.   
  14.     public void receive() {   
  15.   
  16.         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));   
  17.   
  18.         try {   
  19.             //Prompt for JNDI names   
  20.             System.out.println("Enter QueueConnectionFactory name:");   
  21.             String factoryName = reader.readLine();   
  22.             System.out.println("Enter Queue name:");   
  23.             String queueName = reader.readLine();   
  24.             reader.close();   
  25.   
  26.             //Look up administered objects   
  27.             InitialContext initContext = new InitialContext();   
  28.             QueueConnectionFactory factory =   
  29.                 (QueueConnectionFactory) initContext.lookup(factoryName);   
  30.             Queue queue = (Queue) initContext.lookup(queueName);   
  31.             initContext.close();   
  32.             . . .  

 

8、QReceiver:创建 JMS 对象

像在 QSender 中那样创建 QueueConnection 和 QueueSession,然后创建一个 QueueReceiver。

接着,调用 setMessageListener(),传递 QReceiver 的本地实例 this,我们将重调它来实现 MessageListener 接口。

最后,启动 QueueConnection 来接收消息。

  1. . . .   
  2.         //Create JMS objects   
  3.         QueueConnection connection = factory.createQueueConnection();   
  4.         QueueSession session =   
  5.             connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);   
  6.         QueueReceiver receiver = session.createReceiver(queue);   
  7.         receiver.setMessageListener(this);   
  8.         connection.start();   
  9.         . . .   

9、QReceiver:等待 stop 并退出

接着,程序进入一个循环,它会在 stop 变量变为 true 时退出循环。在循环中,线程睡眠一秒钟。一旦退出循环, QueueConnection 就会退出,并且程序也会终止

  1. . . .   
  2.         //Wait for stop   
  3.         while (!stop) {   
  4.             Thread.sleep(1000);   
  5.         }   
  6.   
  7.         //Exit   
  8.         System.out.println("Exiting...");   
  9.         connection.close();   
  10.         System.out.println("Goodbye!");   
  11.   
  12.     } catch (Exception e) {   
  13.         e.printStackTrace();   
  14.         System.exit(1);   
  15.     }   
  16. }   
  17. . . .  

10、QReceiver:onMessage(Message) 方法

需要包含 QReceiver 类的 onMessage(Message) 方法,因为 QReceiver 可以实现 MessageListener 接口。

接收消息时,就调用这个方法,并将 Message 作为参数传递。

在这个实现中,我们获得了消息的文本内容,并将它打印到 System.out。然后,检查消息是否等于 stop,如果是,则将 stop 变量设置为 true,这会使 receive() 方法中的循环终止。

 

  1.     . . .   
  2.     public void onMessage(Message message) {   
  3.   
  4.         try {   
  5.             String msgText = ((TextMessage) message).getText();   
  6.             System.out.println(msgText);   
  7.             if ("stop".equals(msgText))   
  8.                 stop = true;   
  9.         } catch (JMSException e) {   
  10.             e.printStackTrace();   
  11.             stop = true;   
  12.         }   
  13.     }   
  14. }   


11、源码QSender.java 的代码清单

java 代码
  1. import java.io.*;   
  2. import javax.jms.*;   
  3. import javax.naming.*;   
  4.   
  5. public class QSender {   
  6.   
  7.     public static void main(String[] args) {   
  8.   
  9.         new QSender().send();   
  10.     }   
  11.   
  12.     public void send() {   
  13.   
  14.         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));   
  15.   
  16.         try {   
  17.             //Prompt for JNDI names   
  18.             System.out.println("Enter QueueConnectionFactory name:");   
  19.             String factoryName = reader.readLine();   
  20.             System.out.println("Enter Queue name:");   
  21.             String queueName = reader.readLine();   
  22.   
  23.             //Look up administered objects   
  24.             InitialContext initContext = new InitialContext();   
  25.             QueueConnectionFactory factory =   
  26.                 (QueueConnectionFactory) initContext.lookup(factoryName);   
  27.             Queue queue = (Queue) initContext.lookup(queueName);   
  28.             initContext.close();   
  29.   
  30.             //Create JMS objects   
  31.             QueueConnection connection = factory.createQueueConnection();   
  32.             QueueSession session =   
  33.                 connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);   
  34.             QueueSender sender = session.createSender(queue);   
  35.   
  36.             //Send messages   
  37.             String messageText = null;   
  38.             while (true) {   
  39.                 System.out.println("Enter message to send or 'quit':");   
  40.                 messageText = reader.readLine();   
  41.                 if ("quit".equals(messageText))   
  42.                     break;   
  43.                 TextMessage message = session.createTextMessage(messageText);   
  44.                 sender.send(message);   
  45.             }   
  46.   
  47.             //Exit   
  48.             System.out.println("Exiting...");   
  49.             reader.close();   
  50.             connection.close();   
  51.             System.out.println("Goodbye!");   
  52.   
  53.         } catch (Exception e) {   
  54.             e.printStackTrace();   
  55.             System.exit(1);   
  56.         }   
  57.     }   
  58. }   

 

12、源码QReceiver .java 的代码清单

java 代码
  1. import java.io.*;   
  2. import javax.jms.*;   
  3. import javax.naming.*;   
  4.   
  5. public class QReceiver implements MessageListener {   
  6.   
  7.     private boolean stop = false;   
  8.   
  9.     public static void main(String[] args) {   
  10.   
  11.         new QReceiver().receive();   
  12.     }   
  13.   
  14.     public void receive() {   
  15.   
  16.         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));   
  17.   
  18.         try {   
  19.             //Prompt for JNDI names   
  20.             System.out.println("Enter QueueConnectionFactory name:");   
  21.             String factoryName = reader.readLine();   
  22.             System.out.println("Enter Queue name:");   
  23.             String queueName = reader.readLine();   
  24.             reader.close();   
  25.   
  26.             //Look up administered objects   
  27.             InitialContext initContext = new InitialContext();   
  28.             QueueConnectionFactory factory =   
  29.                 (QueueConnectionFactory) initContext.lookup(factoryName);   
  30.             Queue queue = (Queue) initContext.lookup(queueName);   
  31.             initContext.close();   
  32.   
  33.             //Create JMS objects   
  34.             QueueConnection connection = factory.createQueueConnection();   
  35.             QueueSession session =   
  36.                 connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);   
  37.             QueueReceiver receiver = session.createReceiver(queue);   
  38.             receiver.setMessageListener(this);   
  39.             connection.start();   
  40.   
  41.             //Wait for stop   
  42.             while (!stop) {   
  43.                 Thread.sleep(1000);   
  44.             }   
  45.   
  46.             //Exit   
  47.             System.out.println("Exiting...");   
  48.             connection.close();   
  49.             System.out.println("Goodbye!");   
  50.   
  51.         } catch (Exception e) {   
  52.             e.printStackTrace();   
  53.             System.exit(1);   
  54.         }   
  55.     }   
  56.   
  57.     public void onMessage(Message message) {   
  58.   
  59.         try {   
  60.             String msgText = ((TextMessage) message).getText();   
  61.             System.out.println(msgText);   
  62.             if ("stop".equals(msgText))   
  63.                 stop = true;   
  64.         } catch (JMSException e) {   
  65.             e.printStackTrace();   
  66.             stop = true;   
  67.         }   
  68.     }   
  69. }  
posted @ 2008-12-16 17:37 LaoH 阅读(418) | 评论 (0)编辑 收藏
  2008年11月24日
ActiveMQ 是一个实现了 JMS 1.1 规范的开源的 JMS Server,HermesJMS 则是一个开源的 GUI 工具,可以连接许多种 JMS Server。

然而,HermesJMS 的官方网站上提供的配置方法语焉不详,常常使初次使用者陷入困境。本文给出详细的操作步骤,并给出了一段视频。

一、安装 ActiveMQ

1、下载 ActiveMQ,网址是:http://www.activemq.com,目前的最新版本是 ActiveMQ 4.0 M4;

2、把下载到的 activemq-4.0-M4.zip 解压,假设解压后的目录为 E:\activemq;

3、运行 E:\activemq\bin 目录下的 activemq.bat (在 UNIX/LINUX 下运行 activemq 脚本)

默认情况下,ActiveMQ 运行在 61616 端口,连接串是 tcp://hostname:61616。

另:ActiveMQ 也可以通过 JMX Remote 来连接并进行管理,例如:用 MC4J Console 1.2b9。

用 JMX Remote 工具时,连接串是:service:jmx:rmi://hostname/jndi/rmi://hostname:1099/jmxrmi

二、安装 HermesJMS

1、下载 HermesJMS,网址是:http://www.hermesjms.com,当前最新版本是 hermes-v1.10_221005;

2、把下载到的 hermes-v1.10_221005.zip 解压,假设目录为 E:\hermes;

3、运行 E:\hermes\bin\hermes.bat,启动 HermesJMS 的主界面;

三、配置 HermesJMS

1、单击主界面上的“Options -> Configuration...”;

2、在窗口底部,选择“Provider”;

3、在窗口的空白处单击鼠标右键,选择“Add Group”;

4、在 Classpath group name 中随便输入一个名字,例如 ActiveMQ 4.0 Group;

5、展开刚添加的“ActiveMQ 4.0”节点,在“Library”上单击右键,选择“Add JAR(s)”;

6、把连接 ActiveMQ 所需要的 JAR 文件添加进来,共需要下列文件:

  activeio-2.1.jar
  activemq-core-4.0-M4.jar
  backport-util-concurrent-2.0_01_pd.jar
  geronimo-spec-jms-1.1-rc4.jar


7、当弹出窗口问是否自动“Scan”时,选择“Yes”;

8、单击“OK”按钮,关闭当前窗口;

9、在主界面左边树上的“sessions”节点上单击右键,“New -> New session...”;

10、在“Session:”后边,随意输入一个 Session 的名称,例如 “ActiveMQ4.0”;

11、在“Connection Factory”下面,“Loader”右边的下拉框中选择刚才添加的 ActiveMQ 4.0 Group;

12、在“Class”右边的下拉框中,选择“org.apache.activemq.ActiveMQConnectionFactory”;

13、在“Class”和“Loader”下方的表格内,单击右键,“Add property”;

14、在表格的第一列的下拉框中选择“brokerURL”,在右边输入“tcp://localhost:61616”;

15、单击“OK”按钮,关闭当前窗口;

四、往队列中发消息

用 ActiveMQ 自带的例子,往队列中发消息。为了运行例子,需要有 Ant。

1、下载 Ant,地址是:http://ant.apache.org

2、把下载后的文件解压到某个目录下,例如:E:\Ant1.6.5;

3、在系统的环境变量中设置“JAVA_HOME”和“ANT_HOME”(设置方法是:在“我的电脑”上单击右键,“属性”->“高级”->“环境变量”),例如 JAVA_HOME 设置为 E:\JDK1.4.2,ANT_HOME 设置为 E:\Ant1.6.5;

4、把“%JAVA_HOME%\bin”和“%ANT_HOME%\bin”目录添加到系统的环境变量“PATH”中;

5、打开一个“命令提示符”窗口,进入 ActiveMQ 的 examples 目录:E:\activemq\examples;

6、输入“ant producer”,回车,待程序运行完毕,将往 ActiveMQ 的 QUEUE 中发送了一条消息,QUEUE 的名称是 TEST.FOO;

五、在 HermesJMS 中查看刚才发送的消息

1、在 HermesJMS 主界面左边的树中,在“sessions”下面刚才添加的“ActiveMQ4.0”节点上单击右键,“New -> Add queue...”;

2、在 Name 和 ShortName 里面都输入“TEST.FOO”;

3、在主界面左边的树上,可以看出,在“ActiveMQ4.0”节点下面,添加了一个“TEST.FOO”节点;

4、在“TEST.FOO”上单击右键,“Browse...”;

5、在主界面右边的表格中,就可以看到刚才由 example 程序发到 TEST.FOO 队列的 10 条消息;

六、取走队列中的消息

1、另开一个“命令提示符”窗口,进入 E:\activemq\examples 目录;

2、输入“ant consumer”,回车,待程序运行完毕,将从 ActiveMQ 的 QUEUE TEST.FOO 中取走所有消息;

3、回到 HermesJMS 的主界面上去,在工具栏上单击“Refresh now.”按钮,刷新;

4、可以看到主界面右边的表格中是空的,刚才显示的 10 条消息已经被取走。

本文提供了视频剪辑,可从此处下载。因为有最大文件尺寸限制,所以分成两个卷压缩。下载后把两个文件放在一个目录下,然后解压第一个文件即可(第二个文件会自动被解压)。

解压后的文件名为:HermesJmsDemo.exe,MD5 摘要是:A74CF06E27FD19D91F678E85E7B4C0C5

绝非病毒,请放心地双击播放。


转自http://wakan.blog.51cto.com/59583/7217
posted @ 2008-11-24 10:46 LaoH 阅读(1453) | 评论 (0)编辑 收藏
  2008年11月21日

20.Working with Tree Controls使用Tree控件
初次翻译,错误之处必然不少,敬请见谅。
翻译日期:2008-03-01
译者:ShiLiangShuai(http://hi.baidu.com/shiliangshuai)
Flex版本:3
原文地址:http://www.adobe.com/devnet/flex/quickstart/working_with_tree/
所处章节:Flex Developer Center -> Flex Quick Starts -> Working with Tree controls
要看程序运行效果请查看原文,或自己手工编译程序。

Tree控件是一个枝和叶节点分层次的机构。树中没每一个条目叫做节点,节点既可以作为枝也可以作为叶。枝节点可以包含叶或枝节点,或者为空。一个叶节点就是一个树的末梢。本快速指南包含一些开发者在使用Treecontrols经常会遇到的一些挑战。
使用XMLLISTCOLLECTION 和ARRAYCOLLECTION对象的对比。
你也许想知道,在运行时从远程或本地得来的数据被动态修改的时候,应该使用XMLListCollection对象还是ArrayCollection对象作为Tree空间的数据提供者。
如果你使用的数据源提供成形的XML,并且,你想在Tree控件中操作 XML数据。你应该使用XMLListCollection对象作为数据提供者。当使用MXML标记时,如果数据源是XMLList对象,你应该把它绑定到XMLLsitCollection对象的source属性上,然后把 XMLListCollection对象绑定到Tree控件的dataProvider属性上。当你想要动态改变对象值时,不要使用XMLList或XML对象直接绑定到Tree控件的dataProvider属性上。
当数据源是RPC(远程过程调用)服务的lastResult属性,并且你想使用XML数据,确保RPC组件的resultFormat属性被设置成e4x,当你使用e4x结果格式,最总结果就是XMLList,可以绑定在XMLListCollection对象上。这里 有一个例子。
为例数据被动态改变,使用ArrayCollection对象作为Tree控件的数据提供器。当使用MXML标记时,如果你期望动态的改变Arrayl,你不应该把Array对象直接绑定到Tree控件的dataProvider属性上。作为代替,你应该绑定Array到一个ArrayCollection对象的source属性上,然后再把ArrayCollection对象绑定到Tree控件的dataProvider属性上。
当数据源是RPC(远程过程调用)服务的lastResult对象,并且RPC组件的resultFormat属性被成object,你应该使用ArrayUtil.toArray()方法来确保对象是一个Array。然后绑定到ArrayCollection对象上,就像下边的例子所示:
<mx:ArrayCollection
    id="employeeAC"
    source= "{ArrayUtil.toArray(employeeSrv.lastResult.employees.employee)}"/>
在运行时增加和删除叶子节点
你可以在运行时为Tree控件增加或删除叶子节点。下边的例子包含的代码来实现这种改变。这个程序使用预定义的枝和叶来初始化,表现公司部门和员工。你可以向任意枝节点增加叶节点在运行时。你也可以删除预定义的叶节点和你在运行时增加的节点。
在这个例子中的XML包含两种不同的元素名字,department和employee。Tree控件的label函数,决定根据元素的类型应该显示那些文本。它使用了E4X语法来返回department的title,或者employee的name。然后,这些语法在addEmployee()和removeEmployee()中会用到。
为了增加员工到业务部门,addEmployee()方法使用E4X语法,通过title属性的值获得业务部门的节点,并把它保存到XMLList类型的变量dept中。然后,通过调用dept.appendChild()方法向操作节点添加子结点。
remove方法保存当前被选择的元素到变量node中,node的类型是XML。调用node.localName()方法确定被选择的元素是否是employee节点。如果是employee节点,删除它。
Example
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">
  
    <mx:Script>
        <![CDATA[            import mx.collections.XMLListCollection;
          
            [Bindable]
            private var company:XML =
              <list>
                <department title="Finance" code="200">
                    <employee name="John H"/>
                    <employee name="Sam K"/>
                </department>
                <department title="Operations" code="400">
                    <employee name="Bill C"/>
                    <employee name="Jill W"/>
                </department>                  
                <department title="Engineering" code="300">
                    <employee name="Erin M"/>
                    <employee name="Ann B"/>
                </department>                              
              </list>;
          
            [Bindable]
            private var companyData:XMLListCollection = new XMLListCollection(company.department);
          
            private function treeLabel(item:Object):String
            {
                var node:XML = XML(item);
                if( node.localName() == "department" )
                    return node.@title;
                else
                    return node.@name;
            }
            private function addEmployee():void
            {
                var newNode:XML = <employee/>;
                newNode.@name = empName.text;
                var dept:XMLList =company.department.(@title == "Operations");
                if( dept.length() > 0 ) {
                    dept[0].appendChild(newNode);
                    empName.text = "";
                }
            }
            private function removeEmployee():void
            {
                var node:XML = XML(tree.selectedItem);
                if( node == null ) return;
                if( node.localName() != "employee" ) return;
          
                var children:XMLList = XMLList(node.parent()).children();
                for(var i:Number=0; i < children.length(); i++) {
                    if( children[i].@name == node.@name ) {
                        delete children[i];
                    }
                }
            }
        ]]>
    </mx:Script>
  
    <mx:Tree id="tree" top="72" left="50" dataProvider="{companyData}"
        labelFunction="treeLabel"
         height="224" width="179"/>
    <mx:HBox>      
        <mx:Button label="Add Operations Employee" click="addEmployee()"/><mx:TextInput id="empName"/>
    </mx:HBox>
    <mx:Button label="Remove Selected Employee" click="removeEmployee()"/>  
</mx:Application>
在运行时添加一个空的枝节点
可以在运行时向Tree控件添加空的枝节点。下边的例子展示了通过数据提供器(data provider)API和数据描述器(data descriptor )API添加枝节点。通常,添加枝节点的首选途径是通过数据提供器(data provider)API。
addEmptyBranthDP()方法通过数据提供器API向使用XML数据提供器的Tree组件增加一个空节点,这个方法为新节点创建一个XML类型的变量,并且设置这个节点的isBranch属性为true来创建一个枝节点。然后这个方法调用Tree控件的dataProvider.addItemAt()方法来向Tree控件的数据提供器增加新的元素。
addEmptyBranchDP2()方法通过数据提供器API向使用对象数据提供器的Tree组件增加一个空节点,这个方法使用children属性创建一个新的对象,使用children属性能够确保isBranch()方法返回true。然后,这个方法调用Tree控件的dataProvider.addItemAt()方法来向Tree控件的数据提供器增加新的对象。
addEmptyBranchDD()方法通过数据描述器(data descripter)API。这个方法创建一个XML类型的变量,并且设置isBranch属性为true来创建一个枝节点。然后,这个方法调用Tree控件的dataDescriptor.addChildAt()方法来向Tree控件的数据描述器添加一个新的子节点。
Example
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">    <mx:Script>
        <![CDATA[
            [Bindable]
            private var dataX:XML =
                <item label="Top">
                <item label="Child One"/>
                <item label="Child Two" />
            </item>;
      
            [Bindable]
            private var dataObj:Object =
                [{label:"Top", children:
                [
                {label:"Child One"}, {label: "Child Two"}
                ]
                }];
      
            // Adding a branch by going through the Tree control's dataProvider. This is
            // the preferred method.
            // Toggling the isBranch attribute to true causes DefaultDataDescriptor.isBranch()
            // to return true and the Tree treats the node as a branch.
            private function addEmptyBranchDP():void
            {
                var newNode:XML = <item label='Middle' isBranch="true"></item>;
                xmlBound2Tree.dataProvider.addItemAt(newNode, 1);
            }
      
            // For an object graph, the key point is that the children property needs to be defined,
            // even if it is empty.
            // This causes isBranch() to return true and the Tree treats the new node as a branch.
            private function addEmptyBranchDP2():void
            {
                var newObj:Object = {label:"Middle", children:[]};
                objGraphBound2Tree.dataProvider.addItemAt(newObj, 1);
            }
      
            // Adding a branch by going through the Tree control's dataDescriptor.
            private function addEmptyBranchDD():void
            {
                var newNode:XML = <item label='Child 4' isBranch="true"></item>;
                xmlBound2Tree.dataDescriptor.addChildAt(dataX, newNode, 2, dataX);
            }
          ]]>
    </mx:Script>
    <mx:Label text="Tree with XML data"/>
    <mx:Tree id="xmlBound2Tree" dataProvider="{dataX}" labelField="@label" showRoot="true" width="200"/>
    <mx:Button label="Add Empty Branch through the dataProvider" click="addEmptyBranchDP();"/>
    <mx:Button label="Add Empty Branch through the dataDescriptor" click="addEmptyBranchDD();"/>
    <mx:Spacer height="10"/>
    <mx:Label text="Tree with object data"/>
    <mx:Tree id="objGraphBound2Tree" dataProvider="{dataObj}" width="200"/>
    <mx:Button label="Add Empty Branch through the dataProvider" click="addEmptyBranchDP2();"/>  
</mx:Application>
打开树到指定的节点
默认的,Tree控件在初始化后是收缩的,你也许不确定如何初始化控件时展开数,并且选定指定的节点。下边的例子,展示了如何实现它。在这个程序中,initTree()方法,在Tree控件被创建后调用。这个方法展开Tree控件的根节点,并且设置selectedIndex属性为指定节点的索引号。
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">    <mx:Script>
        <![CDATA[
            import flash.events.*;
            import mx.events.*;
            import mx.controls.*;
            private function initTree():void {
                XMLTree1.expandItem(MailBox.getItemAt(0), true);
                XMLTree1.selectedIndex = 2;
            }
        ]]>
    </mx:Script>
    <mx:Tree id="XMLTree1" width="150" height="170"
             labelField="@label" creationComplete="initTree();">
        <mx:XMLListCollection id="MailBox">
            <mx:XMLList>
                <node label="Mail" data="100">
                    <node label="Inbox" data="70"/>
                    <node label="Personal Folder" data="10">
                        <node label="Business" data="2"/>
                        <node label="Demo" data="3"/>
                        <node label="Saved Mail" data="5" />
                    </node>
                    <node label="Sent" data="15"/>
                    <node label="Trash" data="5"/>
                 </node>
            </mx:XMLList>
        </mx:XMLListCollection>
</mx:Tree>
</mx:Application>
读取多节点名XML文档
你可以从具有多个节点名字的XML文档中组装Tree 控件。下边的例子实现了这个功能。Tree控件的数据提供者是一个XMLListCollection,它组装自一个包含folder和Pfolder元素的XMLList。Tree控件的labelField属性被设置为label属性,不管元素叫什么名字,这个属性对XMLList中的所有属性都是公共的。
Example
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">
    <mx:Tree id="tree1" dataProvider="{MailBox}" labelField="@label" showRoot="true" width="160"/>
    <mx:XMLListCollection id="MailBox" source="{Folders}"/>
     <mx:XMLList id="Folders">
        <folder label="Mail">
            <folder label="INBOX"/>
            <folder label="Personal Folder">
                <Pfolder label="Business" />
                <Pfolder label="Demo" />
                <Pfolder label="Saved Mail" />
            </folder>

            <folder label="Sent" />
            <folder label="Trash" />
        </folder>
    </mx:XMLList>   
</mx:Application>
当数据提供器更新时保持Tree控件打开
默认地,当数据提供器更新数据时Tree控件收缩。下边的例子展示了当数据提供器更新时保持Tree控件打开的方法。
在这个应用程序中,当一个用户单击Button控件时changeProvider()方法更新数据提供器。通常,这会导致Tree控件收缩。然而,Tree控件的渲染事件处理器,renderTree()方法,放置收缩的发生。当changerProvider()方法被调用,当前状态是打开的元素被保存到对象open变量中。当数据被刷新时,被命名为refreshData的Boolean类型的变量被置为true。renderTree()方法调用Tree控件的invalidateList()方法来刷新树的行。然后置refreshDate属性为false,并且重置Tree控件的打开元素属性为open对象变量,这个变量在刷新前就包含了状态是打开的元素。
Example
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" initialize="initTree()" viewSourceURL="srcview/index.html">

    <mx:Script>
        <![CDATA[
            [Bindable]
            public var open:Object = new Object();
            [Bindable]

            public var refreshData:Boolean = false;
            [Bindable]
            public var switchObj:Object = new Object();
            [Bindable]

            public var firstObj:Object = new Object();
            [Bindable]

            public var firstObj1:Object = new Object();
            [Bindable]

            public var firstObj2:Object = new Object();
            [Bindable]

            public var provider:String = "firstObj";

            private function initTree():void

            {

                firstObj = new Object();
                firstObj.label = "Foods";
                firstObj.children = new Array();
                firstObj1.label = "Fruits";
                firstObj1.children = new Array();
                firstObj2.label = "Oranges";
                firstObj1.children[0] = firstObj2;
                firstObj.children[0] = firstObj1;
                switchObj = firstObj;
            }

            public function changeProvider():void
            {
                open = SampleTree.openItems;
                refreshData = true;
                if (provider == "firstObj")

                {
                    provider = "switchObj";
                    SampleTree.dataProvider = switchObj;
                }
                else

                {
                    provider = "firstObj";
                    SampleTree.dataProvider = firstObj;
                }
            }

            public function renderTree():void{
                if(refreshData){

                    // Refresh all rows on next update.
                    SampleTree.invalidateList();
                    refreshData = false;
                    SampleTree.openItems = open;
                    // Validate and update the properties and layout
                    // of this object and redraw it, if necessary.
                    SampleTree.validateNow();
                }

            }
        ]]>
    </mx:Script>
    <mx:Tree id="SampleTree" render="renderTree()" width="250" dataProvider="{firstObj}" labelField="label" />

    <mx:Button label="Change Data Provider" click="changeProvider()"/>
</mx:Application>

posted @ 2008-11-21 09:57 LaoH 阅读(1298) | 评论 (0)编辑 收藏
  2008年11月19日
     摘要: 什么是反射 反射 (Reflection) 是指在程序在运行时 (run-time) 获取类信息的方式. 诸如实现动态创建类实例, 方法等. 在很语言中都有相关的的实现, 如 Java 和 c# 等 反射有什么用 在 as3 与 as2 不同, 类实例中任何元素, 如变量 (variable), 访问器 (accessor, 即 getter / setter), 方法 (method) 都...  阅读全文
posted @ 2008-11-19 10:30 LaoH 阅读(1526) | 评论 (0)编辑 收藏
  2008年10月13日
在看JPetStore的代码时,发现它的分页处理主要是通过返回PaginatedList对象来完成的。如:在CatalogService类中


public PaginatedList getProductListByCategory(String categoryId) {
    return productDao.getProductListByCategory(categoryId);
  }
分页是操作数据库型系统常遇到的问题。分页实现方法很多,但效率的差异就很大了。iBatis是通过什么方式来实现这个分页的了。查看它的实现部分:
 
返回的PaginatedList实际上是个接口,实现这个接口的是PaginatedDataList类的对象,查看PaginatedDataList类发现,每次翻页的时候最后都会调用下面这段函数
private List getList(int idx, int localPageSize) throws SQLException {
    return sqlMapExecutor.queryForList(statementName, parameterObject, (idx) * pageSize, localPageSize);
  }
由于
public interface SqlMapClient extends SqlMapExecutor, SqlMapTransactionManager {……}
所以实际的调用次序如下:
SqlMapClientImpl.queryForPaginatedList->SqlMapSessionImpl.queryForPaginatedList
->SqlMapExecutorDelegate.queryForPaginatedList->GeneralStatement.executeQueryForList
->GeneralStatment.executeQueryWithCallback->GeneralStatment.executeQueryWithCallback
->SqlExecutor.executeQuery->SqlExecutor.handleMultipleResults()->SqlExecutor.executeQuery-> handleResults
分页处理的函数如下
private void handleResults(RequestScope request, ResultSet rs, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
    try {
      request.setResultSet(rs);
      ResultMap resultMap = request.getResultMap();
      if (resultMap != null) {
        // Skip Results
        if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
          if (skipResults > 0) {
            rs.absolute(skipResults);
          }
        } else {
          for (int i = 0; i < skipResults; i++) {
            if (!rs.next()) {
              return;
            }
          }
        }
 
        // Get Results
        int resultsFetched = 0;
        while ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults) && rs.next()) {
          Object[] columnValues = resultMap.resolveSubMap(request, rs).getResults(request, rs);
          callback.handleResultObject(request, columnValues, rs);
          resultsFetched++;
        }
      }
    } finally {
      request.setResultSet(null);
    }
  }
由此可见,iBatis的分页主要依赖于jdbcdriver的如何实现以及是否支持rs.absolute(skipResults)。它并不是一个好的分页方式。它先要取出所有的符合条件的记录存入ResultSet对象,然后用absolute方法进行定位,来实现分页。当记录数较大(比如十万条)时,整体的查询速度将会变得很慢。
所以分页还是要考虑采用直接操作sql语句来完成。当然小批量的可以采用iBatis的分页模式。一般分页的sql语句与数据库的具体实现有关
mysql:
select * from A limit startRow,endRow
oracle:
select b.* from (select a.*,rownum as linenum from (select * from A) a where rownum <= endRow) b where linenum >= startRow
Hibernate的Oracle分页采用的就是是拼凑RowNum的Sql语句来完成的。参考代码如下:
 
        public String createOraclePagingSql(String sql, int pageIndex, int pageSize){
            int m = pageIndex * pageSize;
            int n = m + pageSize;
            return "select * from ( select row_.*, rownum rownum_ from ( " + sql
                    + " ) row_ where rownum <= " + n 
                    + ") where rownum_ > " + m;
        } 综上,小批量(<2w)可以采用ibatis自带的分页类,大批量的还是直接操纵sql,当然也可以将这些sql自己进行封装,或在包中封装都可以。包封装的示例代码如下:
一个封装了分页功能的Oracle Package
create or replace package body FMW_FY_HELPER is
PROCEDURE GET_DATA(pi_sql in varchar,pi_whichpage in integer,pi_rownum in integer,
po_cur_data out cur_DATA,po_allrownum out integer,pio_succeed in out integer)
as
v_cur_data cur_DATA;
v_cur_temp cur_TEMP;
v_temp integer;
v_sql varchar(5000);
v_temp1 integer;
v_temp2 integer;
begin
pio_succeed := 1;
v_sql := 'select count(''a'') from ( ' || pi_sql || ')';
execute immediate v_sql into v_temp;

po_allrownum:=ceil(v_temp/pi_rownum);

v_sql := '';
v_temp :=pi_whichpage*pi_rownum + 1;
v_temp1:=(pi_whichpage-1)*pi_rownum + 1;
v_temp2:=pi_whichpage*pi_rownum;
v_sql:= 'select * from (select rownum as rn,t.* from (' || pi_sql ||') t where rownum<' || to_char(v_temp) || ')  where rn between ' || to_char(v_temp1) || ' and ' || to_char(v_temp2);
open v_cur_data for v_sql;
if v_cur_data %notfound
then
pio_succeed:=-1;
return;
end if;
po_cur_DATA := v_cur_data;
end;
posted @ 2008-10-13 14:02 LaoH 阅读(3232) | 评论 (1)编辑 收藏
仅列出标题