Flex汉语本高亮显示

Flex中文本高亮显示

HighlightBlock .as:

package com.kingnare.regex
{
 import flash.display.Shape;
 import flash.geom.Point;
 import flash.geom.Rectangle;
 import flash.text.TextLineMetrics;
 
 import mx.core.IUITextField;
 import mx.flash.UIMovieClip;
 
 /**
  *
  * 根据IUITextField文本的起始和结束字符索引绘制图形并显示在文本选择区。
  * <br/><br/>
  * E-mail:auzn1982[at]gmail.com
  * @author auzn at Kingnare.com
  *
  */ 
 
 public class HighlightBlock extends UIMovieClip
 {
  /**
   * 目标文本
   */  
  private var _textField:IUITextField;
  /**
   * 偏移点,调整绘图Shape与目标文本的位置差距
   */  
  private var _offsetPoint:Point;
  
  
  /**
   *
   * HighlightBlock 构造方法
   * @param textField 目标文本
   *
   */  
  public function HighlightBlock(textField:IUITextField)
  {
   super();
   _offsetPoint = new Point(0, 0);
   _textField = textField;
  }
  
  /**
   *
   * 绘制高亮块
   * 根据起始字符索引及结束字符索引获得有效的绘制范围
   * 如果绘制范围合法,将绘制高亮块。
   *
   * @param beginIndex 目标文本中起始字符索引
   * @param endIndex 目标文本中结束字符索引
   *
   * @see #getValidBeginCharIndex()
   * @see #getValidEndCharIndex()
   */  
  public function highLightDraw(beginIndex:Number, endIndex:Number):void
  {
   var beginValidIndex:Number = getValidBeginCharIndex(beginIndex);
   var endValidIndex:Number = getValidEndCharIndex(endIndex);
   if(beginValidIndex == -1 || endValidIndex == -2)
   {
    //throw new Error("Invalid value");
    return;
   }
   if(beginValidIndex<=endValidIndex)
   {
    normalDraw(beginValidIndex, endValidIndex);
   }
  }
  
  /**
   *
   * 根据起始字符索引及结束字符索引绘制,单行/多行。
   *
   * @param beginIndex 目标文本中起始字符索引
   * @param endIndex 目标文本中结束字符索引
   *
   * @see #drawSingleLine()
   */  

  private function normalDraw(beginIndex:Number, endIndex:Number):void
  {
   //trace("Normal Draw");
   var beginLineIndex:Number = _textField.getLineIndexOfChar(beginIndex);
   var endLineIndex:Number = _textField.getLineIndexOfChar(endIndex);
   var disLineNum:Number = endLineIndex-beginLineIndex;
   //1行
   if(disLineNum<1)
   {
    drawSingleLine(beginIndex, endIndex);
    return;
   }
   //大于或等于一行
   //首行
   drawSingleLine(beginIndex, _textField.getLineOffset(beginLineIndex)+_textField.getLineLength(beginLineIndex)-1);
   //中间行
   for(var i:Number=beginLineIndex+1;i<endLineIndex;i++)
   {
    drawSingleLine(_textField.getLineOffset(i), _textField.getLineOffset(i)+_textField.getLineLength(i)-1);
   }
   //尾行
   drawSingleLine(_textField.getLineOffset(endLineIndex), endIndex);
  }
  
  /**
   *
   * 根据起始字符索引及结束字符索引绘制,单行。
   *
   * @param beginIndex 目标文本中起始字符索引
   * @param endIndex 目标文本中结束字符索引
   *
   * @throws Error  起始和结束索引跨多个行。
   */  
  private function drawSingleLine(beginIndex:Number, endIndex:Number):void
  {
   endIndex--;
   var beginLineIndex:Number = _textField.getLineIndexOfChar(beginIndex);
   var endLineIndex:Number = _textField.getLineIndexOfChar(endIndex);
   var disLineNum:Number = endLineIndex-beginLineIndex;
   //1行
   if(disLineNum<1)
   {
    var frame:Rectangle = _textField.getCharBoundaries(beginIndex);
    frame.y = getDisLineHeightByLine(beginLineIndex);
    frame.width = _textField.getCharBoundaries(endIndex).x - _textField.getCharBoundaries(beginIndex).x+_textField.getCharBoundaries(endIndex).width;
    showBlock(frame);
   }
   else
   {
    throw new Error("drawSingleLine:disLineNum >= 1.");
   }
  }
  
  /**
   *
   * 通过行索引查找相对显示行的总高度
   * @param lineIndex 行索引
   * @return 相对高度
   *
   */  
  public function getDisLineHeightByLine(lineIndex:Number):Number
  {
   
   var addHeight:Number = 2;
   for(var i:Number=_textField.scrollV-1;i<lineIndex;i++)
   {
    var showLine:TextLineMetrics = _textField.getLineMetrics(i);
    addHeight += showLine.height;
   }
   return addHeight;
  }
  
  /**
   *
   * 通过字符索引查找相对显示行的总高度
   * @param charIndex 字符索引
   * @return 相对高度
   *
   */  
  public function getDisLineHeightByChar(charIndex:Number):Number
  {
   var line:Number = _textField.getLineIndexOfChar(charIndex);
   return getDisLineHeightByLine(line);
  }
  
  /**
   *
   * 获取当前有效的起始字符索引
   * @param beginIndex 起始字符索引
   * @return 有效的索引值。若索引值超出文本范围,返回-1
   *
   */  
  public function getValidBeginCharIndex(beginIndex:Number):Number
  {
   var len:Number = _textField.text.length;
   if(beginIndex<0 || beginIndex>len-1)
   {
    return -1;
   }
   var line:Number = _textField.getLineIndexOfChar(beginIndex);
   
   if(line<_textField.scrollV-1)
   {
    line = _textField.scrollV-1;
    return _textField.getLineOffset(line);
   }
   return beginIndex;
  }
  
  
  /**
   *
   * 获取当前有效的结束字符索引
   * @param endIndex 结束字符索引
   * @return 有效的索引值。若索引值超出文本范围,返回-2
   *
   */  
  public function getValidEndCharIndex(endIndex:Number):Number
  {
   var len:Number = _textField.text.length;
   if(endIndex<0 || endIndex>len-1)
   {
    return -2;
   }
   var line:Number = _textField.getLineIndexOfChar(endIndex);
   if(line>_textField.bottomScrollV-1)
   {
    line = _textField.bottomScrollV-1;
    return _textField.getLineOffset(line)+_textField.getLineLength(line)-1;
   }
   return endIndex;
  }
  
  
  /**
   *
   * 绘制并加到显示容器中
   * @param pos
   *
   */  
  private function showBlock(pos:Rectangle):void
  {
   var rect:Rectangle = new Rectangle(_offsetPoint.x+pos.x, _offsetPoint.y+pos.y, pos.width, pos.height);
   this.addChild(drawBlock(rect));
  }
  
  
  /**
   *
   * 绘制
   * @param rect
   * @return 绘制图形
   *
   */  
  protected function drawBlock(rect:Rectangle):Shape
  {
   var block:Shape = new Shape();
   block.graphics.clear();
   block.graphics.beginFill(0x0099CC, .35);
   block.graphics.lineStyle(1, 0x0099CC, .65, true);
   block.graphics.drawRoundRectComplex(rect.x, rect.y, rect.width, rect.height, 0, 0, 0, 0);
   block.graphics.endFill();
   return block;
  }
  
  /**
   *
   * 目标文本组件
   * @param tf 目标文本
   *
   */  
  public function set textField(tf:IUITextField):void
  {
   _textField = tf;
  }
  
  /**
   *
   * @private
   * @return 目标文本
   *
   */  
  public function get textField():IUITextField
  {
   return _textField;
  }
  
  /**
   *
   * 偏移点
   * @param op 偏移点
   *
   */  
  public function set offsetPoint(op:Point):void
  {
   _offsetPoint = op;
  }
  
  /**
   *
   * @private
   * @return 偏移点
   *
   */  
  public function get offsetPoint():Point
  {
   return _offsetPoint;
  }
 }
}

BlockTextArea.as:

package com.components
{
 import com.kingnare.regex.HighlightBlock;
 
 import flash.display.DisplayObject;
 import flash.geom.Point;
 
 import mx.controls.TextArea;

 public class BlockTextArea extends TextArea
 {
  
  private var blockArray:Array;
  
  public function BlockTextArea()
  {
   super();
   blockArray = [];
  }
  
  public function showBlock(beginIndex:int, endIndex:int):void
  {
   var movieTip:HighlightBlock= new HighlightBlock(this.textField);
   movieTip.offsetPoint = new Point(0, 0);
   movieTip.highLightDraw(beginIndex, endIndex);
   movieTip.toolTip = "beginIndex: "+beginIndex+"\nendIndex: "+endIndex+"\nlength: "+(endIndex-beginIndex+1).toString()+"\ntext:\t"+this.textField.text.substring(beginIndex, endIndex+1);
   clearBlock();
   this.addChild(movieTip);
   blockArray.push(movieTip);
  }
  
  public function clearBlock():void
  {
   var len:uint = blockArray.length;
   for(var k:uint=0;k<len;k++)
   {
    var obj:DisplayObject = blockArray[k]
    this.removeChild(obj);
    obj = null;
   }
   blockArray = [];
  }
 }
}

Test.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:components="com.components.*"
     width="420" height="160" applicationComplete="initApp();">
 <mx:Script>
  <![CDATA[
  
   import mx.events.ScrollEvent;
   import mx.managers.ToolTipManager;
   
   private var updateTimer:Timer;
   
   private function initApp():void
   {
    ToolTipManager.showDelay = 0;
    //timer
    updateTimer = new Timer(5, 1);
             updateTimer.addEventListener(TimerEvent.TIMER, validate, false, 0, true);
             
    lightText.addEventListener(ScrollEvent.SCROLL, scrollEvent);
    lightText.htmlText = "Documentation for classes includes syntax, " +
      "<b><font size='18'>usage</font></b> information, and code samples for methods, " +
      "properties, " +
      "and event handlers and listeners for those APIs that belong to a specific class " +
      "in ActionScript (as opposed to global functions or properties). " +
      "The <font size='24'>classes</font> are listed alphabetically. " +
      "If you are not sure to which class a certain method or property belongs, " +
      "you can look it up in the Index.";
    beginIndexInput.text = "43";
    endIndexInput.text = "300";
   }
   
   private function showBlock():void
   {
    lightText.showBlock(parseInt(beginIndexInput.text), parseInt(endIndexInput.text));
   }
   
   //validate
   private function validate(event:TimerEvent):void
   {
    showBlock();
   }
   
   //scrollEvent
   private function scrollEvent(event:ScrollEvent):void
   {
    updateBlock();
   }
   
   //鏇存柊
   private function updateBlock():void
   {
    updateTimer.reset();
    updateTimer.start();
   }
  ]]>
 </mx:Script>
 <components:BlockTextArea id="lightText" width="400" height="100" y="10" x="10"/>
 <mx:Button y="118" label="Show Highlight" click="showBlock();" right="10"/>
 <mx:TextInput id="beginIndexInput" x="92" y="118" width="60"/>
 <mx:TextInput id="endIndexInput" x="232" y="118" width="60"/>
 <mx:Label x="10" y="121" text="beginIndex:"/>
 <mx:Label x="160" y="121" text="endIndex:"/>
</mx:Application>
下面是源码包!!!转自:http://blog.minidx.com/2008/07/28/1178.html