AS3 Windows 样式拖放
AS3 Windows style drag and drop
我正在制作一个 windows 风格的应用程序,其中包含不同的 windows 元素。我知道如何编写拖放功能代码来更改 windows 在舞台上的位置,但我想对所有 windows 使用单一代码而不重复无限功能。我的代码是:
public function fl_WindowDrag(event: MouseEvent): void {
instance.startDrag();
}
public function fl_WindowDrop(event: MouseEvent): void {
instance.stopDrag();
}
我希望从所选 window 中自动检索实例名称,这可能吗? 我希望你明白我的需要 任何帮助都会被接受 提前致谢
package {
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.Keyboard;
import flash.ui.Mouse;
import flash.display.MovieClip;
public class MainTimeline extends MovieClip {
//Variabili
public var VFullscreen: int = 1;
//Import var
public var VTerminal: Terminal = new Terminal();
public var nTerminal:String;
public function MainTimeline(): void {
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
//Import
//Terminal
VTerminal.x = 288;
VTerminal.y = 384;
stage.addChild(VTerminal);
//Event Listeners
//addEventListener(MouseEvent.CLICK, fl_BringToFront);
VTerminal.addEventListener(MouseEvent.MOUSE_DOWN, fl_WindowDrag);
VTerminal.addEventListener(MouseEvent.MOUSE_UP, fl_WindowDrop);
}
//public functions
//Gestione Fullscreen
public function fl_Fullscreen(event: MouseEvent): void {
switch (VFullscreen) {
case 0:
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
VFullscreen = 1;
break;
case 1:
stage.displayState = StageDisplayState.NORMAL;
VFullscreen = 0;
break;
}
}
public function fl_FSCheck(event: Event): void {
if (stage.displayState == StageDisplayState.NORMAL) {
VFullscreen = 0;
}
if (stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE) {
VFullscreen = 1;
}
}
//Primo Piano Finestre
public function fl_BringToFront(event: MouseEvent): void {
this.addChild(event.currentTarget as DisplayObject);
}
public function fl_WindowDrag(event: MouseEvent): void {
event.currentTarget.startDrag();
nTerminal = event.currentTarget.name.toString();
trace(nTerminal);
}
public function fl_WindowDrop(event: MouseEvent): void {
event.currentTarget.stopDrag();
}
//Chiusura
public function fl_Close(event: MouseEvent): void {
stage.nativeWindow.close();
}
//Apertura/Chiusura Terminal
public function fl_Terminal(event: MouseEvent): void {
if (contains(VTerminal)) {
removeChild(VTerminal);
} else {
VTerminal.x = 288;
VTerminal.y = 320;
addChild(VTerminal);
}
}
}
}
你可以使用鼠标事件的target
或currentTarget
属性来引用触发事件的实例,就像这样(我没有测试过这段代码):
public function fl_WindowDrag(event: MouseEvent): void {
event.currentTarget.startDrag();
}
通过这种方式,您可以将事件处理程序添加到多个实例。您可以阅读有关 events properties here
的更多信息有很多方法可以做到这一点。 您可以为所有 windows 准备基数 class,这将继承此行为,如果您计划设计超过一打 windows,这绝对是您应该考虑的事情。另一种方法是创建单独的 class 旨在仅执行此操作并注册您想要的所有 windows。 但是既然你问这是否可能,我建议你尝试一些第三方库。
GreenShock 有一个很好的工具,但我有一段时间没有使用他们的库,我不知道他们的许可程序是什么。
如果你不喜欢它,你可以使用我前段时间制作的代码。 它非常易于使用,但尚未完全实现(无法旋转等)并且文档非常薄弱,但如果您有兴趣,我可以帮助您。 您需要做的就是传递要移动的对象以及一些基本属性:
TransformTool.addClient(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Array = null, dragBounds:Array = null, grabRange:Number = 5):TransformData
terget
- 那就是你的 window.operations
- 表示变换类型(缩放、拖动、旋转)的位标志edgesMask
- 定义哪些边应该参与缩放操作的位标志(左、右、上、下)所有这些标志值以及操作标志都可以在TransformData
中找到class.sizeBounds
- 数组包含相应缩放对象的最小和最大尺寸以及高度。dragBounds
- 拖动对象的位置边界。基本上这些都是 flashRectangle
class. 的参数
grabRange
- 从鼠标到边缘的距离,您可以在其中抓取和边缘(或边角情况下的边缘)。您也可以在对象外部用鼠标抓取边缘并同时缩放两个单独的对象边缘。
因此假设 w
和 w2
是您的 windows,用法如下所示:
TransformTool.addClient(w, TransforData.SCALE|TransformData.DRAG, TransformData.BOTTOM_EDGE|TransformData.RIGHT_EDGE, null, null, 10);
TransformTool.addClient(w2, 3, 15, [20, 10, 350, 350], [100, 100, 600, 500], 10);
使用它只需要这一行。 如果你想改变光标,你也可以添加监听器。
TransformTool.eventDispatcher.addEventListener(TransformToolEvent.EDGES_HIT, transformTestHit);
private function transformTestHit(e:TransformToolEvent):void
{
trace(TransformData(e.data).hitEdges);
}
下面是所有涉及的代码。您可以随意使用它,但请注意 TransformTool 是静态的 class 并且仅使用一个阶段实例。 我想在 Air 中开发应用程序并使用原生 windows 您需要修改此代码,因为每个原生 window 实例都有其独特的阶段。
变形工具class:
package utils
{
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* @author Audionysos
*/
public class TransformTool
{
private static var clients:Vector.<TransformData> = new Vector.<TransformData>();
private static var transforming:Vector.<TransformData> = new Vector.<TransformData>();
private static var _stage:Stage;
public static var checkEdgesOnMMove:Boolean = true;
private static var _eventDispatcher:EventDispatcher = new EventDispatcher();
public static function addClient(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Array = null, dragBounds:Array = null, grabRange:Number = 5):TransformData {
var sBR:Rectangle;
var dBR:Rectangle;
if (sizeBounds) sBR = new Rectangle(sizeBounds[0], sizeBounds[1], sizeBounds[2], sizeBounds[3]);
if (dragBounds) dBR = new Rectangle(dragBounds[0], dragBounds[1], dragBounds[2], dragBounds[3]);
var td:TransformData = new TransformData(target, operations, edgesMask, sBR, dBR, grabRange);
if (operations & TransformData.SCALE) td.allowDrag = true;
clients.push(td);
if (stage) return td;
if (!target.stage) target.addEventListener(Event.ADDED_TO_STAGE, onStage);
else { stage = target.stage; addStageListeners(); }
return td;
}
/**
* Return TransformData object associated with given target.
* @param target object associated with searched TransformData.
* @return TransformData object associated with given target.
*/
static public function getTransformData(target:InteractiveObject):TransformData {
for (var i:int = 0; i < clients.length; i++){
if (clients[i].targetObject == target) return clients[i];
}return null;
}
/**
* Mouse position relative to specifed object.
* @param target InteractiveObject or TransformData object.
* @return Mouse position relative to specifed object.
*/
static public function getTargetMouse(target:*):Point
{
var t:InteractiveObject = target as InteractiveObject;
if (!t && target as TransformData) t = TransformData(target).targetObject;
else throw new Error ("property object must be of type InteractiveObject or TransformData");
return new Point(t.parent.mouseX, t.parent.mouseY);
}
/**
* Adds MOUSE_DOWN and MOUSE_UP listener for current stage;
*/
static private function addStageListeners():void
{
//trace("TT adding stage listeners");
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
static private function onStage(e:Event):void
{
//trace("TT client on stage");
InteractiveObject(e.target).removeEventListener(Event.ADDED_TO_STAGE, onStage);
stage = InteractiveObject(e.target).stage;
addStageListeners();
}
static private function onMUp(e:MouseEvent):void
{
for (var i:int = 0; i < transforming.length; i++){
transforming[i].isTransforming = false;
}
transforming = new Vector.<TransformData>();
}
static private function onMDown(e:MouseEvent):void
{
//trace("TT MousDown");
findAffectedObjects();
}
static private function findAffectedObjects():void
{
for (var i:int = 0; i < clients.length; i++) {
clients[i].hitEdges = findEdges(clients[i]);
if (!clients[i].hitEdges) continue;
//trace("TT got R", clients[i].hitEdges);
transforming.push(clients[i]);
clients[i].isTransforming = true;
clients[i].updateMouseVector();
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
}
static private function onMMove(e:MouseEvent):void
{
//trace("Transforming", transforming.length);
if (TransformTool.checkEdgesOnMMove) dispatchEdges();
//trace("TT Moving");
for (var i:int = 0; i < transforming.length; i++) {
if (transforming[i].operations & TransformData.ROTATE) rotateTarget();
//if (!checkEdgesOnMMove)
transforming[i].updateMouseVector();
scaleTarget(transforming[i]);
fixSize(transforming[i]);
fixPlacement(transforming[i]);
}
}
/**
* Performs fingEdges() operation on each client TransformData object and dispatches EDGES_HIT event if result is different form last hitEdges state;
*/
static private function dispatchEdges():void
{
for (var i:int = 0; i < clients.length; i++) {
if (clients[i].isTransforming) continue;
var r:uint = findEdges(clients[i]);
if (r != clients[i].hitEdges) {
clients[i].hitEdges = r;
_eventDispatcher.dispatchEvent(new TransformToolEvent(TransformToolEvent.EDGES_HIT, clients[i]));
}
}
}
static private function rotateTarget():void
{
}
/**
* If a part of an object is outside defined dragBounds rectangle area it will move this object to closest allowed position.
* @param td
*/
static public function fixPlacement(td:TransformData):void
{
if (!td.dragBounds) return;
td.targetObject.x = Math.max(td.targetObject.x, td.dragBounds.x);
td.targetObject.x = Math.min(td.dragBounds.right - td.targetObject.width, td.targetObject.x);
td.targetObject.y = Math.max(td.targetObject.y, td.dragBounds.y);
td.targetObject.y = Math.min(td.dragBounds.bottom-td.targetObject.height, td.targetObject.y);
}
/**
* Changes the object to fit min/max size defined in sizeBounds object of the transformation data.
* @param td
*/
static public function fixSize(td:TransformData):void
{
if (!td.sizeBounds) return;
td.targetObject.width = Math.min(td.targetObject.width, td.sizeBounds.width);
td.targetObject.width = Math.max(td.targetObject.width, td.sizeBounds.x);
td.targetObject.height = Math.min(td.targetObject.height, td.sizeBounds.height);
td.targetObject.height = Math.max(td.targetObject.height, td.sizeBounds.y);
}
/**
* Scales the object accordingly to grabed edges and move of the mouse.
* @param td
*/
static public function scaleTarget(td:TransformData):void
{
//trace("TT mouse vector", td.mouseVector);
var rD:Point = td.mouseVector//new Point(td.mouseVector.x * td.targetObject.parent.scaleX, td.mouseVector.y * td.targetObject.parent.scaleY); //relativeDisplacement
if (td.hitEdges & TransformData.LEFT_EDGE) { td.targetObject.width -= rD.x; td.targetObject.x += rD.x; }
if (td.hitEdges & TransformData.RIGHT_EDGE) { td.targetObject.width += rD.x; }
if (td.hitEdges & TransformData.TOP_EDGE) { td.targetObject.height -= rD.y; td.targetObject.y += rD.y; }
if (td.hitEdges & TransformData.BOTTOM_EDGE) { td.targetObject.height += rD.y; }
}
/**
* Check if mouse position is in grab range to any of specified object edge.
* @param target examined object
* @param grabRange minimal distance from mouse position to edge of the object.
* @return resul of the inspection.
*/
static public function findEdges(td:TransformData):uint
{
if (!isMouseNearTarget(td)) return 0;
var t:InteractiveObject = td.targetObject;
var gR:Number = td.grabRange;
var r:uint;
if (Math.abs(t.x - t.parent.mouseX) < gR && t.parent.mouseX) r |= TransformData.LEFT_EDGE;
if (Math.abs(t.x + t.width- t.parent.mouseX) < gR) r |= TransformData.RIGHT_EDGE;
if (Math.abs(t.y - t.parent.mouseY) < gR) r |= TransformData.TOP_EDGE;
if (Math.abs(t.y + t.height - t.parent.mouseY) < gR) r |= TransformData.BOTTOM_EDGE;
return r;
}
/**
* Check if mouse relative position is cantained within target rectangle + grabRange;
* @param td object to examine.
* @return true if mouse is near object (edges can be grabbed);
*/
static public function isMouseNearTarget(td:TransformData):Boolean
{
td.updateMouseVector();
var exRect:Rectangle = td.targetObject.getRect(td.targetObject.parent).clone();
exRect.inflate(td.grabRange, td.grabRange);
return exRect.containsPoint(td.mouseStart);
}
/**
* Dispatches events associated with transformed client objects.
* TransformToolEvent contains reference to interested TransformData object.
* @eventType TransformToolEvent.EDGE_HIT dispatched when mouse cursor is close enought client object edges to let it to be scaled.
* You can for example use it's hitEdges property to change cursor icon accordingly.
*/
static public function get eventDispatcher():EventDispatcher
{
return _eventDispatcher;
}
/**
* Stage property on which mouse events will be proceded.
* This will be set automaticly from client object (it it was null before).
*/
static public function get stage():Stage
{
return _stage;
}
static public function set stage(value:Stage):void
{
if (_stage) {
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMUp);
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMDown);
}
_stage = value;
addStageListeners();
if(checkEdgesOnMMove) value.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
}
}
转换数据class:
package utils
{
import flash.display.InteractiveObject;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* @author Audionysos
*/
public class TransformData
{
public static const SCALE:uint = 1;
public static const DRAG:uint = 2;
public static const ROTATE:uint = 4;
public static const TOP_EDGE:uint = 1;
public static const RIGHT_EDGE:uint = 2;
public static const BOTTOM_EDGE:uint = 4;
public static const LEFT_EDGE:uint = 8;
public var targetObject:InteractiveObject;
public var grabRange:Number;
public var sizeBounds:Rectangle;
public var dragBounds:Rectangle;
public var mouseStart:Point;
public var mouseVector:Point;
public var hitEdges:uint;
public var edgesMask:uint;
public var operations:uint;
public var isTransforming:Boolean;
private var _allowDrag:Boolean;
private var isDraging:Boolean;
public function TransformData(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Rectangle = null, dragBounds:Rectangle = null, grabRange:Number = 5)
{
targetObject = target;
this.sizeBounds = sizeBounds;
this.dragBounds = dragBounds;
this.grabRange = grabRange;
this.edgesMask = edgesMask;
this.operations = operations;
}
public function updateMouseVector () {
var mP:Point = new Point(targetObject.parent.mouseX, targetObject.parent.mouseY);
if (!mouseStart) mouseStart = mP;
mouseVector = mP.subtract(mouseStart);
mouseStart = mP;
}
public function get allowDrag():Boolean
{
return _allowDrag;
}
public function set allowDrag(value:Boolean):void
{
if (_allowDrag && !value) {
targetObject.stage.removeEventListener(MouseEvent.MOUSE_UP, onMUp);
targetObject.removeEventListener(MouseEvent.MOUSE_DOWN, onMDown);
if (isDraging) targetObject.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
_allowDrag = value;
if (value) targetObject.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
}
private function onMDown(e:MouseEvent):void
{
isTransforming = true;
mouseStart = TransformTool.getTargetMouse(this);
targetObject.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
targetObject.stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
private function onMUp(e:MouseEvent):void
{
isTransforming = false;
targetObject.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
private function onMMove(e:MouseEvent):void
{
updateMouseVector();
targetObject.x += mouseVector.x;
targetObject.y += mouseVector.y;
TransformTool.fixPlacement(this);
}
}
}
转换工具事件:
package utils
{
import flash.events.Event;
/**
* ...
* @author Audionysos
*/
public class TransformToolEvent extends Event
{
public static const EDGES_HIT:String = "edgesHit";
private var _data:TransformData;
public function TransformToolEvent(type:String, data:TransformData, bubbles:Boolean=false, cancelable:Boolean=false) {
super(type, bubbles, cancelable);
_data = data;
}
public override function clone():Event {
return new TransformToolEvent(type, _data, bubbles, cancelable);
}
public override function toString():String {
return formatToString("TransformToolEvent", "type", "bubbles", "cancelable", "eventPhase", "data");
}
public function get data():TransformData {
return _data;
}
}
}