参看了一些网上的最小化窗口,发现大多都是添加在容器中的面板,所以利用popupmanager写了个组件,需要用到flexlib.swc的ButtonScrollingCanvas和自己写的PopUp组件(已贴出)。skin是自动生成的,稍作修改。
工具代码:
package pizazz.flex4.utility{ import flash.display.Stage; import flash.events.MouseEvent; import flash.geom.Point; import mx.core.IUIComponent; import spark.components.Button; public class UIUtil{ public static function buttonFactory(label:String, onClick:Function = null, width:Number = NaN, icon:Class = null, target:Button = null):Button{ if(!target){ target = new Button(); } if(onClick != null){ target.addEventListener(MouseEvent.CLICK, onClick); } if(icon != null){ target.setStyle("icon", icon); } target.setStyle("cornerRadius", 0); ParamUtil.setParam(target, { "width": width, "label": label }); return target; } public static function includeContainer(target:IUIComponent, stage:Stage):Point{ var _x:Number = target.x; var _y:Number = target.y; if(_x > stage.stageWidth){ target.x = stage.stageWidth > target.width ? stage.stageWidth - target.width : 0; }else if(_x < 0){ target.x = 0; } if(_y > stage.stageHeight){ target.y = stage.stageHeight > target.height ? stage.stageHeight - target.height : 0; }else if(_y < 0){ target.y = 0; } return new Point(target.x, target.y); } } }
组件代码:
pizazz\flex4\container\skin\MinimizeButtonSkin.mxml
<?xml version="1.0" encoding="utf-8"?> <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled="0.5"> <fx:Metadata> <![CDATA[ [HostComponent("spark.components.Button")] ]]> </fx:Metadata> <fx:Script fb:purpose="styling"> private static const exclusions:Array = ["xSymbol"]; private static const symbols:Array = ["xFill1", "xFill2"]; override public function get colorizeExclusions():Array{ return exclusions; } override public function get symbolItems():Array{ return symbols } </fx:Script> <s:states> <s:State name="up" /> <s:State name="over"/> <s:State name="down" /> <s:State name="disabled" /> </s:states> <s:RectangularDropShadow id="dropShadow" blurX="0" blurY="0" alpha="0" alpha.over="0.85" alpha.down=".85" distance="1" angle="90" color="0xFFFFFF" left="0" top="0" right="0" bottom="0"/> <s:Rect left="0" top="0" right="0" bottom="0"> <s:stroke> <s:SolidColorStroke color="0x000000" alpha="0.0" alpha.over="0.7" alpha.down="0.7" weight="1"/> </s:stroke> <s:fill> <s:SolidColor color="0xCCCCCC" alpha="0" alpha.down="0.7" /> </s:fill> </s:Rect> <s:Rect id="cbshad" left="1" right="1" top="1" height="1" > <s:fill> <s:SolidColor color="0x000000" color.over="0xFFFFFF" alpha="0" alpha.over=".85" alpha.down="0.22" /> </s:fill> </s:Rect> <s:Group top="1" left="1" id="xSymbol"> <s:Path blendMode="normal" alpha=".85" data="M 3 10 L 3 9 L 4 9 L 4 8 L 9 8 L 9 9 L 10 9 L 10 10 Z"> <s:fill> <s:SolidColor id="xFill1" color="0x000000" /> </s:fill> </s:Path> <s:Path blendMode="normal" alpha=".75" data="M 3 9 L 3 8 L 4 8 L 4 9 L 3 9 M 10 9 L 10 8 L 9 8 L 9 9 Z"> <s:fill> <s:SolidColor id="xFill2" color="0x000000" /> </s:fill> </s:Path> <s:Path blendMode="normal" alpha=".85" data="M 3 10 L 3 11 L 10 11 L 10 10 L 3 10 Z"> <s:fill> <s:SolidColor color="0xFFFFFF" /> </s:fill> </s:Path> </s:Group> </s:SparkSkin>
pizazz\flex4\container\skin\WindowTemplateSkin.mxml
<?xml version="1.0" encoding="utf-8"?> <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled="0.5" alpha.disabledWithControlBar="0.5" blendMode="normal" mouseEnabled="false"> <fx:Metadata> <![CDATA[ [HostComponent("pizazz.flex4.container.WindowTemplate")] ]]> </fx:Metadata> <fx:Script> static private const exclusions:Array = ["background", "titleDisplay", "contentGroup"]; override public function get colorizeExclusions():Array { return exclusions; } override protected function initializationComplete():void{ useChromeColor = true; super.initializationComplete(); } override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{ if (getStyle("borderVisible") == true){ border.visible = true; background.left = background.top = background.right = background.bottom = 1; contents.left = contents.top = contents.right = contents.bottom = 1; }else{ border.visible = false; background.left = background.top = background.right = background.bottom = 0; contents.left = contents.top = contents.right = contents.bottom = 0; } dropShadow.visible = getStyle("dropShadowVisible"); var cr:Number = getStyle("cornerRadius"); var withControls:Boolean = (currentState == "disabledWithControlBar" || currentState == "normalWithControlBar" || currentState == "inactiveWithControlBar"); if (cornerRadius != cr){ cornerRadius = cr; dropShadow.tlRadius = cornerRadius; dropShadow.trRadius = cornerRadius; dropShadow.blRadius = withControls ? cornerRadius : 0; dropShadow.brRadius = withControls ? cornerRadius : 0; setPartCornerRadii(topMaskRect, withControls); setPartCornerRadii(border, withControls); setPartCornerRadii(background, withControls); } if (bottomMaskRect){ setPartCornerRadii(bottomMaskRect, withControls); } borderStroke.color = getStyle("borderColor"); borderStroke.alpha = getStyle("borderAlpha"); backgroundFill.color = getStyle("backgroundColor"); backgroundFill.alpha = getStyle("backgroundAlpha"); super.updateDisplayList(unscaledWidth, unscaledHeight); } private function setPartCornerRadii(target:Rect, includeBottom:Boolean):void{ target.topLeftRadiusX = cornerRadius; target.topRightRadiusX = cornerRadius; target.bottomLeftRadiusX = includeBottom ? cornerRadius : 0; target.bottomRightRadiusX = includeBottom ? cornerRadius : 0; } private var cornerRadius:Number; </fx:Script> <s:states> <s:State name="normal" /> <s:State name="inactive" stateGroups="inactiveGroup" /> <s:State name="disabled" /> <s:State name="minimize" /> <s:State name="normalWithControlBar" stateGroups="withControls" /> <s:State name="inactiveWithControlBar" stateGroups="withControls, inactiveGroup" /> <s:State name="disabledWithControlBar" stateGroups="withControls" /> </s:states> <s:RectangularDropShadow id="dropShadow" blurX="20" blurY="20" alpha="0.32" alpha.inactiveGroup="0.22" distance="11" distance.inactiveGroup="7" angle="90" color="0x000000" left="0" top="0" right="0" bottom="0"/> <s:Group left="0" right="0" top="0" bottom="0"> <s:Group left="1" top="1" right="1" bottom="1" id="topGroupMask"> <s:Rect id="topMaskRect" left="0" top="0" right="0" bottom="0"> <s:fill> <s:SolidColor alpha="0"/> </s:fill> </s:Rect> </s:Group> <s:Group left="1" top="1" right="1" bottom="1" id="bottomGroupMask" includeIn="withControls"> <s:Rect id="bottomMaskRect" left="0" top="0" right="0" bottom="0"> <s:fill> <s:SolidColor alpha="0"/> </s:fill> </s:Rect> </s:Group> <s:Rect id="border" left="0" right="0" top="0" bottom="0" > <s:stroke> <s:SolidColorStroke id="borderStroke" weight="1" /> </s:stroke> </s:Rect> <s:Rect id="background" left="1" top="1" right="1" bottom="1"> <s:fill> <s:SolidColor id="backgroundFill" color="#FFFFFF"/> </s:fill> </s:Rect> <s:Group left="1" right="1" top="1" bottom="1" id="contents"> <s:layout> <s:VerticalLayout gap="0" horizontalAlign="justify" /> </s:layout> <s:Group id="topGroup" mask="{topGroupMask}"> <s:Rect id="tbFill" left="0" right="0" top="0" bottom="1"> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="0xD2D2D2" color.inactiveGroup="0xEAEAEA"/> <s:GradientEntry color="0x9A9A9A" color.inactiveGroup="0xCECECE"/> </s:LinearGradient> </s:fill> </s:Rect> <s:Rect id="tbHilite" left="0" right="0" top="0" bottom="0"> <s:stroke> <s:LinearGradientStroke rotation="90" weight="1"> <s:GradientEntry color="0xE6E6E6" /> <s:GradientEntry color="0xFFFFFF" alpha="0.22"/> </s:LinearGradientStroke> </s:stroke> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="0xFFFFFF" alpha="0.15" /> <s:GradientEntry color="0xFFFFFF" alpha="0.15" ratio="0.44"/> <s:GradientEntry color="0xFFFFFF" alpha="0" ratio="0.4401"/> </s:LinearGradient> </s:fill> </s:Rect> <s:Rect id="tbDiv" left="0" right="0" height="1" bottom="0"> <s:fill> <s:SolidColor color="0x000000" alpha="0.75" /> </s:fill> </s:Rect> <s:Label id="titleDisplay" maxDisplayedLines="1" left="9" right="36" top="1" bottom="0" minHeight="24" verticalAlign="middle" fontWeight="bold" /> <s:Group id="moveArea" left="0" right="0" top="0" bottom="0" /> <s:Button id="minimizeButton" toolTip="最小化" width="15" excludeFrom="minimize" right="26" top="7" height="15" skinClass="pizazz.flex4.container.skin.MinimizeButtonSkin" /> <s:Button id="closeButton" toolTip="关闭" width="15" height="15" skinClass="spark.skins.spark.TitleWindowCloseButtonSkin" right="7" top="7" /> </s:Group> <s:Group id="contentGroup" excludeFrom="minimize" width="100%" height="100%" minWidth="0" minHeight="0"> </s:Group> <s:Group id="bottomGroup" minWidth="0" minHeight="0" includeIn="withControls"> <s:Group left="0" right="0" top="0" bottom="0" mask="{bottomGroupMask}"> <s:Rect left="0" right="0" top="0" height="1" alpha="0.22"> <s:fill> <s:SolidColor color="0x000000" /> </s:fill> </s:Rect> <s:Rect left="0" right="0" top="1" bottom="0"> <s:stroke> <s:LinearGradientStroke rotation="90" weight="1"> <s:GradientEntry color="0xFFFFFF" /> <s:GradientEntry color="0xD8D8D8" /> </s:LinearGradientStroke> </s:stroke> </s:Rect> <s:Rect left="1" right="1" top="2" bottom="1"> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="0xEDEDED"/> <s:GradientEntry color="0xCDCDCD"/> </s:LinearGradient> </s:fill> </s:Rect> </s:Group> <s:Group id="controlBarGroup" left="0" right="0" top="1" bottom="1" minWidth="0" minHeight="0"> <s:layout> <s:HorizontalLayout paddingLeft="10" paddingRight="10" paddingTop="7" paddingBottom="7" gap="10" /> </s:layout> </s:Group> </s:Group> </s:Group> </s:Group> </s:SparkSkin>
package pizazz.flex4.container{ import flash.utils.Dictionary; import flexlib.containers.ButtonScrollingCanvas; import pizazz.flex4.container.component.WindowItem; import spark.components.HGroup; public class WindowBar extends ButtonScrollingCanvas{ private const _container:HGroup = new HGroup(); private const _items:Dictionary = new Dictionary(); private var _size:int = 0; private var _index:int = 0; public function get size():int{ return _size; } public function WindowBar(){ super(); WindowTemplate.init(this); _container.percentWidth = 100; height = 24; buttonWidth = 20; } override protected function createChildren():void{ super.createChildren(); addElement(_container); } public function addData(item:WindowTemplate):void{ if(!_items[item]){ _items[item] = new WindowItem(item, _size); _size++; } } public function removeData(item:WindowTemplate):void{ var _target:WindowItem = _items[item]; if(_target){ delete _items[item]; if(_target.index != _size - 1){ for each(var _item:WindowItem in _items){ if(_item.index > _target.index){ _item.index--; } } } _size--; } } public function getIndex(item:WindowTemplate):int{ for each(var _item:WindowItem in _items){ if(_item.item == item){ return _item.index; } } return -1; } public function getItem(index:int):WindowTemplate{ if(index >= 0){ for each(var _item:WindowItem in _items){ if(_item.index == index){ return _item.item; } } } return null; } public function addToBar(item:WindowTemplate):void{ _container.addElement(item); } public function removeFromBar(item:WindowTemplate):void{ if(_container.getElementIndex(item) != -1){ _container.removeElement(item); } } } }
package pizazz.flex4.container{ import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import pizazz.flex4.container.skin.WindowTemplateSkin; import pizazz.flex4.manager.PopUp; import pizazz.flex4.utility.UIUtil; import spark.components.Button; import spark.components.TitleWindow; [Event(name="minimize", type="flash.events.Event")] [SkinState("normal")] [SkinState("minimize")] public class WindowTemplate extends TitleWindow{ [SkinPart(required="true")] public var minimizeButton:Button; public var sign:String = ""; private var _closeable:Boolean = true; private var _minimizable:Boolean = true; private var _mask:Boolean = false; private var _isPanel:Boolean = false; private var _addrPoint:Point = new Point(); private var _areaPoint:Point = new Point(); private var _state:String = STATE_NORMAL; private static var _bar:WindowBar; public static const STATE_MINIMIZE:String = "minimize"; public static const STATE_NORMAL:String = "normal"; /** * 是否为面板模式 */ public function set isPanel(value:Boolean):void{ _isPanel = value; } /** * 是否显示最小化按钮 */ public function set minimizable(value:Boolean):void{ _minimizable = value; } /** * 是否显示关闭按钮 */ public function set closeable(value:Boolean):void{ _closeable = value; } /** * 获取最小化停靠栏 * @return 最小化停靠栏 */ public function get bar():WindowBar{ return _bar; } public function WindowTemplate(){ super(); minWidth = 160; setStyle("skinClass", WindowTemplateSkin); } /** * 弹出面板 * @param mask 是否为模态窗口 * @param sign 窗口弹出唯一标志 */ public function open(mask:Boolean = false, sign:String = ""):Boolean{ return PopUp.openWindow(this, (_mask = mask), sign); } /** * 关闭面板 */ public function shut():void{ if(_state == STATE_MINIMIZE && _bar != null){ _bar.removeFromBar(this); } if(_bar != null){ _bar.removeData(this); } PopUp.closeWindow(this); } override protected function partAdded(partName:String, instance:Object):void{ super.partAdded(partName, instance); if(instance == closeButton){ if(!_closeable || _isPanel){ closeButton.visible = false; closeButton.includeInLayout = false; } closeButton.addEventListener(MouseEvent.CLICK, buttonClickHandler); }else if(instance == minimizeButton){ if(!_minimizable || _isPanel){ minimizeButton.visible = false; minimizeButton.includeInLayout = false; }else if(!_closeable){ minimizeButton.right = 7; } minimizeButton.owner = this; minimizeButton.addEventListener(MouseEvent.CLICK, buttonClickHandler); } } override protected function moveArea_mouseDownHandler( event:MouseEvent):void{ super.moveArea_mouseDownHandler(event); if(_state == STATE_MINIMIZE && !isPopUp && !_isPanel){ toNormal(); } } override protected function getCurrentSkinState():String{ return _state; } override protected function createChildren():void{ super.createChildren(); if(_bar != null && !_isPanel){ _bar.addData(this); }else if(_bar == null){ _minimizable = false; } } private function buttonClickHandler(event:MouseEvent):void{ if(event.currentTarget == minimizeButton){ toMinimize(); dispatchEvent(new Event("minimize")); }else if(event.currentTarget == closeButton){ shut(); } event.preventDefault(); } /** * 窗口标准状态 */ public function toNormal():void{ if(_bar != null){ _bar.removeFromBar(this); } PopUp.updateState(this); open(_mask, sign); updateState(STATE_NORMAL, _addrPoint.x, _addrPoint.y, _areaPoint.x, _areaPoint.y); } /** * 窗口最小化状态 */ public function toMinimize():void{ _addrPoint = new Point(x, y); _areaPoint = new Point(width, height); updateState(STATE_MINIMIZE, x, y, 200, 24); PopUp.updateState(this, STATE_MINIMIZE); if(_bar != null){ _bar.addToBar(this); } } public static function init(bar:WindowBar):void{ _bar = bar; } private function updateState(state:String, addrX:int, addrY:int, areaWidth:uint, areaHeight:uint):void{ _state = state; x = addrX; y = addrY; width = areaWidth; height = areaHeight; invalidateSkinState(); } override protected function moveArea_mouseUpHandler(event:Event):void{ super.moveArea_mouseUpHandler(event); UIUtil.includeContainer(this, stage); } } }
组件执行:
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:container="pizazz.flex4.container.*" minWidth="955" minHeight="600" creationComplete="init()" > <s:layout> <s:BasicLayout /> </s:layout> <fx:Script> <![CDATA[ import mx.controls.Alert; import pizazz.flex4.container.WindowTemplate; import pizazz.flex4.manager.PopUp; import pizazz.flex4.utility.UIUtil; private var num:int = 0; private function init():void{ PopUp.init(this); panelWindow(); } private function panelWindow():void{ const _panel:WindowTemplate = new WindowTemplate(); _panel.isPanel = true; _panel.x = 100; _panel.y = 30; _panel.width = 320; _panel.height = 240; _panel.title = "非弹出窗口"; addElement(_panel); } private function minimizeWindow():void{ var _window:WindowTemplate = windowFactory(); _window.closeable = false; _window.title = "无关闭按钮窗口"; _window.open(); _window.toMinimize(); } private function normalWindow():void{ var _window:WindowTemplate = windowFactory(); _window.title = "默认弹出窗口"; _window.minimizable = false; _window.open(false, "unique"); } private function openWindow():void{ var _window:WindowTemplate = windowFactory(); _window.title = "窗口" + num++; _window.open(); } private function windowFactory():WindowTemplate{ const _window:WindowTemplate = new WindowTemplate(); _window.width = 320; _window.height = 240; _window.addElement(UIUtil.buttonFactory("显示", function(event:MouseEvent):void{ var i:int = _window.bar.getIndex(_window); Alert.show("窗口总数:" + _window.bar.size + "\n当前序列:" + i); } , 100)); return _window; } ]]> </fx:Script> <s:HGroup> <s:Button width="100" label="打开窗口" click="openWindow()" /> <s:Button width="100" label="缩小窗口" click="minimizeWindow()" /> <s:Button width="100" label="普通窗口" click="normalWindow()" /> </s:HGroup> <container:WindowBar width="{width}" bottom="0" /> </s:Application>
视图:
当模态窗口和最小化按钮并存时,点击最小化不符合操作逻辑。
1 楼
exingzhe
2011-03-11
你好pizazz-ex:
我尝试运行你的代码可是发现缺少WindowItem类,您能贴出来吗?
我尝试运行你的代码可是发现缺少WindowItem类,您能贴出来吗?
2 楼
pizazz_ex
2011-07-13
包名可以在程序中找到
public class WindowItem{ private var _item:WindowTemplate; private var _index:int; public function WindowItem(value:WindowTemplate, index:int){ _item = value; _index = index; } public function get item():WindowTemplate{ return _item; } public function set index(value:int):void{ _index = value; } public function get index():int{ return _index; } }