Slider是常用控件。Adobe官方提供的控件中,fl库所带的控件不好用,便有兄弟《自制Flash Slider滚动条》。Flex库中也提供有Slider控件,但是Flex控件太重量级,动不动就是一二百K的尺寸,很多场合没法用。并且,Flex的Slider也不容易定制,比如,它的highlight track比track要低1像素,这在很多情况下是不合适的。
本文修改MinimalComps项目的Slider控件代码,提供一个小巧的Slider控件解决方案,本方案具有以下优势:
(1)小巧。不依赖于fl控件或Flex库,使用本控件不会让程序尺寸增加多少;
(2)容易定制。很容易定制 highlight track、track和thumb部分;
(3)可数据绑定。
MinimalComps项目提供了简单的Slider控件,该控件源代码为:

* Slider.as
* Keith Peters
* version 0.9.1
*
* Abstract base slider class for HSlider and VSlider.
*
* Copyright (c) 2010 Keith Peters
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.bit101.components
{
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
public class Slider extends Component
{
protected var _handle:Sprite;
private var _back:Sprite;
private var _backClick: Boolean = true;
protected var _value: Number = 0;
protected var _max: Number = 100;
protected var _min: Number = 0;
protected var _orientation: String;
protected var _tick: Number = 1;
public static const HORIZONTAL: String = "horizontal";
public static const VERTICAL: String = "vertical";
/* *
* Constructor
* @param orientation Whether the slider will be horizontal or vertical.
* @param parent The parent DisplayObjectContainer on which to add this Slider.
* @param xpos The x position to place this component.
* @param ypos The y position to place this component.
* @param defaultHandler The event handling function to handle the default event for this component (change in this case).
*/
public function Slider(orientation: String = Slider.HORIZONTAL, parent:DisplayObjectContainer = null, xpos: Number = 0, ypos: Number = 0, defaultHandler:Function = null)
{
_orientation = orientation;
super(parent, xpos, ypos);
if(defaultHandler != null)
{
addEventListener(Event.CHANGE, defaultHandler);
}
}
/* *
* Initializes the component.
*/
override protected function init():void
{
super.init();
if(_orientation == HORIZONTAL)
{
setSize(100, 10);
}
else
{
setSize(10, 100);
}
}
/* *
* Creates and adds the child display objects of this component.
*/
override protected function addChildren():void
{
_back = new Sprite();
_back.filters = [getShadow(2, true)];
addChild(_back);
_handle = new Sprite();
_handle.filters = [getShadow(1)];
_handle.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
_handle.buttonMode = true;
_handle.useHandCursor = true;
addChild(_handle);
}
/* *
* Draws the back of the slider.
*/
protected function drawBack():void
{
_back.graphics.clear();
_back.graphics.beginFill(Style.BACKGROUND);
_back.graphics.drawRect(0, 0, _width, _height);
_back.graphics.endFill();
if(_backClick)
{
_back.addEventListener(MouseEvent.MOUSE_DOWN, onBackClick);
}
else
{
_back.removeEventListener(MouseEvent.MOUSE_DOWN, onBackClick);
}
}
/* *
* Draws the handle of the slider.
*/
protected function drawHandle():void
{
_handle.graphics.clear();
_handle.graphics.beginFill(Style.BUTTON_FACE);
if(_orientation == HORIZONTAL)
{
_handle.graphics.drawRect(1, 1, _height - 2, _height - 2);
}
else
{
_handle.graphics.drawRect(1, 1, _width - 2, _width - 2);
}
_handle.graphics.endFill();
positionHandle();
}
/* *
* Adjusts value to be within minimum and maximum.
*/
protected function correctValue():void
{
if(_max > _min)
{
_value = Math.min(_value, _max);
_value = Math.max(_value, _min);
}
else
{
_value = Math.max(_value, _max);
_value = Math.min(_value, _min);
}
}
/* *
* Adjusts position of handle when value, maximum or minimum have changed.
* TODO: Should also be called when slider is resized.
*/
protected function positionHandle():void
{
var range: Number;
if(_orientation == HORIZONTAL)
{
range = _width - _height;
_handle.x = (_value - _min) / (_max - _min) * range;
}
else
{
range = _height - _width;
_handle.y = _height - _width - (_value - _min) / (_max - _min) * range;
}
}
// /////////////////////////////////
// public methods
// /////////////////////////////////
/* *
* Draws the visual ui of the component.
*/
override public function draw():void
{
super.draw();
drawBack();
drawHandle();
}
/* *
* Convenience method to set the three main parameters in one shot.
* @param min The minimum value of the slider.
* @param max The maximum value of the slider.
* @param value The value of the slider.
*/
public function setSliderParams(min: Number, max: Number, value: Number):void
{
this.minimum = min;
this.maximum = max;
this.value = value;
}
// /////////////////////////////////
// event handlers
// /////////////////////////////////
/* *
* Handler called when user clicks the background of the slider, causing the handle to move to that point. Only active if backClick is true.
* @param event The MouseEvent passed by the system.
*/
protected function onBackClick(event:MouseEvent):void
{
if(_orientation == HORIZONTAL)
{
_handle.x = mouseX - _height / 2;
_handle.x = Math.max(_handle.x, 0);
_handle.x = Math.min(_handle.x, _width - _height);
_value = _handle.x / (width - _height) * (_max - _min) + _min;
}
else
{
_handle.y = mouseY - _width / 2;
_handle.y = Math.max(_handle.y, 0);
_handle.y = Math.min(_handle.y, _height - _width);
_value = (_height - _width - _handle.y) / (height - _width) * (_max - _min) + _min;
}
dispatchEvent(new Event(Event.CHANGE));
}
/* *
* Internal mouseDown handler. Starts dragging the handle.
* @param event The MouseEvent passed by the system.
*/
protected function onDrag(event:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, onDrop);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onSlide);
if(_orientation == HORIZONTAL)
{
_handle.startDrag( false, new Rectangle(0, 0, _width - _height, 0));
}
else
{
_handle.startDrag( false, new Rectangle(0, 0, 0, _height - _width));
}
}
/* *
* Internal mouseUp handler. Stops dragging the handle.
* @param event The MouseEvent passed by the system.
*/
protected function onDrop(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, onDrop);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onSlide);
stopDrag();
}
/* *
* Internal mouseMove handler for when the handle is being moved.
* @param event The MouseEvent passed by the system.
*/
protected function onSlide(event:MouseEvent):void
{
var oldValue: Number = _value;
if(_orientation == HORIZONTAL)
{
_value = _handle.x / (width - _height) * (_max - _min) + _min;
}
else
{
_value = (_height - _width - _handle.y) / (height - _width) * (_max - _min) + _min;
}
if(_value != oldValue)
{
dispatchEvent(new Event(Event.CHANGE));
}
}
// /////////////////////////////////
// getter/setters
// /////////////////////////////////
/* *
* Sets / gets whether or not a click on the background of the slider will move the handler to that position.
*/
public function set backClick(b: Boolean):void
{
_backClick = b;
invalidate();
}
public function get backClick(): Boolean
{
return _backClick;
}
/* *
* Sets / gets the current value of this slider.
*/
public function set value(v: Number):void
{
_value = v;
correctValue();
positionHandle();
// This has the potential to set up an infinite loop if two sliders are listening to each other's change
// events to sync to each other. Tentitively trying it out...
dispatchEvent(new Event(Event.CHANGE));
}
public function get value(): Number
{
return Math.round(_value / _tick) * _tick;
}
/* *
* Gets / sets the maximum value of this slider.
*/
public function set maximum(m: Number):void
{
_max = m;
correctValue();
positionHandle();
}
public function get maximum(): Number
{
return _max;
}
/* *
* Gets / sets the minimum value of this slider.
*/
public function set minimum(m: Number):void
{
_min = m;
correctValue();
positionHandle();
}
public function get minimum(): Number
{
return _min;
}
/* *
* Gets / sets the tick value of this slider. This round the value to the nearest multiple of this number.
*/
public function set tick(t: Number):void
{
_tick = t;
}
public function get tick(): Number
{
return _tick;
}
}
}
然而,MinimalComps的Slider控件的外观(http://www.minimalcomps.com/?page_id=5)很简单,见下图。

由于外观直接写死了,没办法换皮肤,因此,难以用于生产环境。

* Slider.as
* Keith Peters
* version 0.9.10
*
* Abstract base slider class for HSlider and VSlider.
*
* Copyright (c) 2011 Keith Peters
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* version 1.0
* By. xiaotie@geblab.com
* Changes: [2012-02-11] make it skinable
*/
package geb.controls
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import geb.common.BaseComponent;
[Event(name="change", type="flash.events.Event")]
public class Slider extends BaseComponent
{
[Bindable]
public var thumb:Sprite;
[Bindable]
public var track:Sprite;
[Bindable]
public var trackHighlight:Sprite;
[Bindable]
public var orientation: String = "horizontal";
public var trackClickable: Boolean = true;
[Bindable]
public var ignoreThumbSize: Boolean = false;
protected var _value: Number = 0;
protected var _max: Number = 100;
protected var _min: Number = 0;
protected var _tick: Number = 0.01;
public static const HORIZONTAL: String = "horizontal";
public static const VERTICAL: String = "vertical";
/* *
* Initializes the component.
*/
override protected function init():void
{
super.init();
if(orientation == HORIZONTAL)
{
setSize(width, height);
}
else
{
setSize(width, height);
}
}
/* *
* Creates and adds the child display objects of this component.
*/
override protected function addChildren():void
{
super.addChildren();
}
/* *
* Adjusts value to be within minimum and maximum.
*/
protected function correctValue():void
{
if(_max > _min)
{
_value = Math.min(_value, _max);
_value = Math.max(_value, _min);
}
else
{
_value = Math.max(_value, _max);
_value = Math.min(_value, _min);
}
}
private function get thumbSize(): Number
{
if(thumb == null || ignoreThumbSize == true) return 0;
else if(orientation == HORIZONTAL)
{
return thumb.width;
}
else
{
return thumb.height;
}
}
/* *
* Adjusts position of handle when value, maximum or minimum have changed.
* TODO: Should also be called when slider is resized.
*/
protected function updateDislpay():void
{
var range: Number;
var highlightRange: Number;
var pos: Number;
var ts: Number = thumbSize;
if(orientation == HORIZONTAL)
{
range = _width - ts;
pos = (_value - _min) / (_max - _min) * range;
highlightRange = pos + ts * 0.5;
if(thumb!= null)
{
thumb.x = pos - (ignoreThumbSize ? thumb.width * 0.5 : 0);
thumb.y = 0.5 * (this.height - thumb.height);
}
if(trackHighlight != null)
{
trackHighlight.width = pos + 0.5 * ts;
trackHighlight.height = Math.min(height,trackHighlight.height);
trackHighlight.y = Math.max(0, 0.5 * (height - trackHighlight.height));
if(trackHighlight is BaseComponent)
{
BaseComponent(trackHighlight).invalidate( false);
}
}
if(track != null)
{
track.width = width;
track.height = Math.min(height,track.height);
track.y = Math.max(0, 0.5 * (height - track.height));
if(track is BaseComponent)
{
BaseComponent(track).invalidate( false);
}
}
}
else
{
range = _height - ts;
pos = height - ts - (_value - _min) / (_max - _min) * range;
highlightRange = pos + ts * 0.5;
if(thumb != null)
{
thumb.x = 0.5 * (this.width - thumb.width);
thumb.y = pos - (ignoreThumbSize ? thumb.height * 0.5 : 0);
}
if(trackHighlight != null)
{
trackHighlight.width = Math.min(width,trackHighlight.width);
trackHighlight.y = pos + 0.5 * ts;
trackHighlight.height = height - trackHighlight.y;
trackHighlight.x = Math.max(0, 0.5 * (width - trackHighlight.width));
if(trackHighlight is BaseComponent)
{
BaseComponent(trackHighlight).invalidate( false);
}
}
if(track != null)
{
track.height = height;
track.width = Math.min(width,track.width);
track.x = Math.max(0, 0.5 * (width - track.width));
if(track is BaseComponent)
{
BaseComponent(track).invalidate( false);
}
}
}
if(track != null && this.contains(track) == false)
{
addChild(track);
if(trackClickable)
{
track.useHandCursor = true;
track.buttonMode = true;
track.addEventListener(MouseEvent.MOUSE_DOWN, onBackClick);
}
else
{
track.removeEventListener(MouseEvent.MOUSE_DOWN, onBackClick);
}
}
if(trackHighlight != null && this.contains(trackHighlight) == false)
{
addChild(trackHighlight);
if(trackClickable)
{
trackHighlight.useHandCursor = true;
trackHighlight.buttonMode = true;
trackHighlight.addEventListener(MouseEvent.MOUSE_DOWN, onBackClick);
}
else
{
trackHighlight.removeEventListener(MouseEvent.MOUSE_DOWN, onBackClick);
}
}
if(thumb != null && this.contains(thumb) == false)
{
thumb.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
thumb.buttonMode = true;
thumb.useHandCursor = true;
addChild(thumb);
}
}
// /////////////////////////////////
// public methods
// /////////////////////////////////
/* *
* Draws the visual ui of the component.
*/
override public function draw():void
{
super.draw();
updateDislpay();
}
/* *
* Convenience method to set the three main parameters in one shot.
* @param min The minimum value of the slider.
* @param max The maximum value of the slider.
* @param value The value of the slider.
*/
public function setSliderParams(min: Number, max: Number, value: Number):void
{
this.minimum = min;
this.maximum = max;
this.value = value;
}
// /////////////////////////////////
// event handlers
// /////////////////////////////////
/* *
* Handler called when user clicks the background of the slider, causing the handle to move to that point. Only active if backClick is true.
* @param event The MouseEvent passed by the system.
*/
protected function onBackClick(event:MouseEvent):void
{
var ts: Number = thumbSize;
var pos: Number;
if(orientation == HORIZONTAL)
{
pos = mouseX - ( ignoreThumbSize ? 0 : thumb.width * 0.5);
pos = Math.max(pos, 0);
pos = Math.min(pos, _width - ts);
value = pos / (width - ts) * (_max - _min) + _min;
}
else
{
pos = mouseY - ( ignoreThumbSize ? 0 : thumb.height * 0.5);
pos = Math.max(pos, 0);
pos = Math.min(pos, _height - ts);
value = (_height - ts - pos) / (height - ts) * (_max - _min) + _min;
}
dispatchEvent(new Event(Event.CHANGE));
}
/* *
* Internal mouseDown handler. Starts dragging the handle.
* @param event The MouseEvent passed by the system.
*/
protected function onDrag(event:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, onDrop);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onSlide);
if(orientation == HORIZONTAL)
{
var xStart: Number = ignoreThumbSize? - thumb.width * 0.5 : 0;
thumb.startDrag( false, new Rectangle(xStart, thumb.y, _width - thumbSize, 0));
}
else
{
var yStart: Number = ignoreThumbSize? - thumb.height * 0.5 : 0;
thumb.startDrag( false, new Rectangle(thumb.x, yStart, 0, _height - thumbSize));
}
}
/* *
* Internal mouseUp handler. Stops dragging the handle.
* @param event The MouseEvent passed by the system.
*/
protected function onDrop(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, onDrop);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onSlide);
stopDrag();
}
/* *
* Internal mouseMove handler for when the handle is being moved.
* @param event The MouseEvent passed by the system.
*/
protected function onSlide(event:MouseEvent):void
{
var oldValue: Number = _value;
var pos: Number;
if(orientation == HORIZONTAL)
{
pos = ignoreThumbSize ? (thumb.x + thumb.width * 0.5) : thumb.x;
value = pos / (width - thumbSize) * (_max - _min) + _min;
}
else
{
pos = ignoreThumbSize ? (thumb.y + thumb.height * 0.5) : thumb.y;
value = (height - thumbSize - pos) / (height - thumbSize) * (_max - _min) + _min;
}
if(value != oldValue)
{
dispatchEvent(new Event(Event.CHANGE));
}
}
// /////////////////////////////////
// getter/setters
// /////////////////////////////////
/* *
* Sets / gets whether or not a click on the background of the slider will move the handler to that position.
*/
public function set backClick(b: Boolean):void
{
trackClickable = b;
invalidate();
}
public function get backClick(): Boolean
{
return trackClickable;
}
/* *
* Sets / gets the current value of this slider.
*/
[Bindable]
public function set value(v: Number):void
{
_value = v;
correctValue();
updateDislpay();
}
[Bindable]
public function get value(): Number
{
return Math.round(_value / _tick) * _tick;
}
/* *
* Gets the value of the slider without rounding it per the tick value.
*/
public function get rawValue(): Number
{
return _value;
}
[Bindable]
/* *
* Gets / sets the maximum value of this slider.
*/
public function set maximum(m: Number):void
{
_max = m;
correctValue();
updateDislpay();
}
public function get maximum(): Number
{
return _max;
}
[Bindable]
/* *
* Gets / sets the minimum value of this slider.
*/
public function set minimum(m: Number):void
{
_min = m;
correctValue();
updateDislpay();
}
public function get minimum(): Number
{
return _min;
}
/* *
* Gets / sets the tick value of this slider. This round the value to the nearest multiple of this number.
*/
public function set tick(t: Number):void
{
_tick = t;
}
public function get tick(): Number
{
return _tick;
}
}
}
BaseComponent类见我的其它博文:《只学一点点:我的技术学习策略 》(http://www.cnblogs.com/xiaotie/archive/2011/12/10/2283384.html)和《使用铁哥SmartFlash快速开发方案:66行代码搞定抽奖程序!》(http://www.cnblogs.com/xiaotie/archive/2011/06/15/2081386.html)。
下面演示Slider控件的使用:

< common:Application xmlns:fx ="http://ns.adobe.com/mxml/2009"
xmlns:local ="*"
xmlns:common ="geb.common.*"
xmlns:gc ="geb.controls.*"
xmlns:shapes ="geb.shapes.*"
xmlns:containers ="geb.containers.*"
fillMode ="false"
width ="300" height ="300"
>
< fx:Declarations >
<!-- 定义slider1外观的三个形状 -->
< shapes:Rectangle id ="trackHighlight" color ="0x125894" height ="5" />
< shapes:Rectangle id ="track" color ="0x343434" height ="5" />
< shapes:Ellipse id ="thumb" color ="0x999999" width ="10" height ="10" />
<!-- 定义slider3外观的三个形状 -->
< shapes:Rectangle id ="trackHighlight2" color ="0x125894" width ="5" />
< shapes:Rectangle id ="track2" color ="0x343434" width ="5" />
< shapes:Ellipse id ="thumb2" color ="0x999999" width ="10" height ="10" />
<!-- 定义slider2外观的三个图片 -->
< gc:Image id ="thumbImage" height ="10" width ="10" source ="@Embed(source='assets/sliderAssets/thumbSkin.png')" />
< gc:Image id ="trackHighlightImage" height ="4" width ="10" source ="@Embed(source='assets/sliderAssets/trackHighlightSkin.png')" />
< gc:Image id ="trackImage" height ="4" width ="10" source ="@Embed(source='assets/sliderAssets/trackSkin.png')" />
</ fx:Declarations >
< shapes:Rectangle width ="{width}" height ="{height}" color ="0xEEEEEE" />
< gc:Slider id ="slider1" x ="50" y ="50" width ="70" height ="20"
trackHighlight ="{trackHighlight}"
track ="{track}"
thumb ="{thumb}" ignoreThumbSize ="false" >
</ gc:Slider >
< gc:Label x ="130" y ="50" autoSize ="true" text ="{slider1.value}" />
< gc:Slider id ="slider2" x ="50" y ="100" width ="70" height ="20"
trackHighlight ="{trackHighlightImage}" value ="20" maximum ="50"
track ="{trackImage}"
thumb ="{thumbImage}" ignoreThumbSize ="true" >
</ gc:Slider >
< gc:Label x ="130" y ="100" autoSize ="true" text ="{slider2.value}" />
< gc:Slider id ="slider3" x ="50" y ="150" width ="10" height ="70"
trackHighlight ="{trackHighlight2}" orientation ="vertical"
track ="{track2}"
thumb ="{thumb2}" ignoreThumbSize ="true" >
</ gc:Slider >
</ common:Application >
在线演示:
从上到下,可以看到三个Slider:
第一个Slider的皮肤由三个形状组成,track是黑色矩形,highlightTrack是蓝色矩形,thumb是圆。highlightTrack和track都规定了高度,这个高度,就是显示出来的highlightTrack和track高度,如果想让highlightTrack和track变粗,改变它的高度即可。Thumb规定了长和宽,如果修改thumb的大小,改变它的长宽即可,当然,如果长宽不等,则就是椭圆而非圆形了。
第二个Slider是由三个图片组成的,以应对复杂精致的皮肤,所使用的三个图片如下:

使用不同的图片,便是不同的Slider外观。
第二个Slider和第一个Slider还有个不同,就是ignoreThumbSize属性为true。第一个Slider的thumb是圆形,把thumb拖到两端可以发现,thumb遮盖不住两端(如果是方形的thumb则没这个问题),因此,引入了ignoreThumbSize字段。ignoreThumbSize字段默认为false,当ignoreThumbSize为true时,以thumb的中线为定位基准,这样便可避免当thumb是圆形时移动到两端,盖不住track两端的情况。
第三个Slider的orientation设为vertical,因此,便是竖着的Slider。
Slider可供数据绑定,比如:
<gc:Label x="130" y="50" autoSize="true" text="{slider1.value}" />
通过这样简单的代码便可使slider1的值改变时,对应的Lable的文本也发生变化。
是不是既小巧、又易用又灵活呢?