Please, anyone can guide me how to do this stuff.
I have a pannel and a box, The pannel is my component pannel(inside component pannel is eg. image, TextArea, Video) and
Box is my target Box for my component creation. The user can select a component he/she want to create (dynamic creation)
and drag it to target Box(drag and drop event). Then after creating the component
the user can drag the component that he/she created and place anywhere on target
Box and also the user can resize the component that he/she created(runtime resize).
i have this code for drag and drop and it seems this code works only on image
//-----action script-----//
private function dragIt(event:MouseEvent, value: String, objParent: String, objName: String):void
{
var dragInitiator:Image = event.currentTarget as Image;
var dragSource:DragSource = new DragSource();
dragSource.addData(value,'value');
dragSource.addData(objParent, 'parent');
dragSource.addData(objName, 'objname');
var dragProxy:Image = new Image();
dragProxy.source = event.currentTarget.source;
DragManager.doDrag(dragInitiator, dragSource, event, dragProxy);
}
private function dragEnterHandler(event:DragEvent):void
{
var dropTarget:Box=event.currentTarget as Box;
dropTarget.setStyle("borderThickness", 5);
DragManager.acceptDragDrop(dropTarget);
}
private function dragExitHandler(event:DragEvent):void
{
var dropTarget:Box=event.currentTarget as Box;
revertBoxBorder();
}
private function revertBoxBorder():void
{
targetBox.setStyle("borderThickness", 1);
}
private function dragDropHandler(event:DragEvent):void
{
var value:String = event.dragSource.dataForFormat('value') as String;
var objParent:String = event.dragSource.dataForFormat('parent') as String;
if(value == "mp3")
{
//do something
}
else if (value == "image")
{
if (objParent == "panel")
{
var imgView: Image = new Image;
imgView.x = event.stageX;
imgView.y = event.stageY;
addChild(imgView);
imgView.name = String(getChildByName(imgView.name).parent.numChildren-1);
imgView.addEventListener(MouseEvent.MOUSE_MOVE, function(e:MouseEvent):void
{
dragIt(e, value, 'box', Image(e.target).name);
});
imgView.source = ImgInsert;
}
else
{
var objName:String = event.dragSource.dataForFormat('objname') as String;
getChildByName(objName).parent.getChildAt(int(objName)).x = event.stageX;
getChildByName(objName).parent.getChildAt(int(objName)).y = event.stageY;
}
}
else if (value == "textarea")
{
//do something
}
}
//-----mxml code------//
<mx:Panel x="0" y="37" width="91" height="417" layout="absolute" title="Component" borderColor="#8DA5AB" color="#345860" borderStyle="outset">
<mx:Image x="7" y="43" width="21" height="18" source="{TxtAreaInsert}" mouseMove="dragIt(event,'textarea','panel','')"/>
<mx:Image x="36" y="43" width="21" height="18" source="{ImgInsert}" mouseMove="dragIt(event,'image','panel','')"/>
<mx:Image x="36" y="80" width="21" height="18" source="{Mp3Insert}" mouseMove="dragIt(event,'mp3','panel','')"/>
<mx:Image x="7" y="80" width="21" height="18" source="{VdoInsert}" mouseMove="dragIt(event,'video','panel','')"/>
</mx:Panel>
<mx:Box id="targetBox" y="37" width="589" height="417" borderColor="#8CC2E8" backgroundColor="#D5DBEE"
dragExit="dragExitHandler(event)" dragEnter="dragEnterHandler(event)" dragDrop="dragDropHandler(event)" left="99">
</mx:Box>;
How to move thus non image component like TxtArea? How to resize the component inside target box?
(This is like GUI of flex when creating component)
Thank you..
check out Rogue-Development.com's Object Handles I've used this with pretty good success for moving / resizing components.
Also try out the Pantaste library which is a lot more sophisticated than Object Handles.
Goto http://sourceforge.net/projects/tcycomponents/
and download package and demo if you want.
Use TcyReziser component for easy moving/resizing like Delphi 2009 does!
Regards,
Mauricio
Related
I have a situation where I need to show several 1-column DataGrids one beside the other and control them with 1 vertical scroll bar. (the result looks like 1 DataGrid but since I use a variable row height, each "column" can have a different row height on each row.
In order to achieve the required result, I created several grids and stacked them in an HBox (I know I should use spark but I want to retain my styles and my entire application is in Halo). Outside of the HBox, I have a VerticalScrollBar and I'm able to control the grid's scroll position since I extended the DataGrid and added a vertical scroll bar getter.
For simplicity, I've stripped the code to the bare essentials:
<mx:Canvas width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:HBox id="viewPort" top="1" right="15" bottom="0" left="1" minWidth="0"
horizontalScrollPolicy="auto" verticalScrollPolicy="off">
</mx:HBox>
<mx:VScrollBar id="vScrollBar" top="24" right="0" bottom="0" scroll="onScroll(event)" />
</mx:Canvas>
private function populateGrids() : void
{
var item:Object;
var maxScrollPosition:Number = 0;
var dataGrid:CustomDataGrid;
var dataProvider:Object = {'1':[11,12,13,14,15,16], '2':[21,22,23,24,25,26,27,28], '3':[31]};
viewPort.removeAllChildren();
for (item in dataProvider) {
var col:DataGridColumn = new DataGridColumn();
col.headerText = "Grid" + item;
col.sortable = false;
dataGrid = new CustomDataGrid();
viewPort.addChild(dataGrid);
dataGrid.minWidth = 200;
dataGrid.percentHeight = 100;
dataGrid.percentWidth = 100;
dataGrid.headerHeight = 23;
dataGrid.selectable = false;
dataGrid.variableRowHeight = true;
dataGrid.columns = [col];
dataGrid.dataProvider = dataProvider[item];
}
viewPort.validateNow();
for (item in dataProvider) {
dataGrid = (viewPort.getChildAt(int(item)) as CustomDataGrid);
maxScrollPosition = Math.max(maxScrollPosition, dataGrid.vScrollBar.maxScrollPosition);
}
vScrollBar.maxScrollPosition = maxScrollPosition;
vScrollBar.scrollPosition = 0;
// need to shut-off the vertical scroller only after the maxScrollPosition is calculated
// otherwise, it doesn't calculate it ...
for (item in dataProvider) {
dataGrid = (viewPort.getChildAt(int(item)) as CustomDataGrid);
dataGrid.verticalScrollPolicy = "off";
}
}
private function onScroll(e:ScrollEvent) : void
{
var grids:Array = viewPort.getChildren();
for each (var grid:CustomDataGrid in grids) {
grid.verticalScrollPosition = e.currentTarget.scrollPosition;
}
}
While this does show the grids and scrolls them, the item renderers are not reused correctly (probably due to the verticalScrollPositon which might be larger than the actual maximum scroll position for each grid).
Am I going at it from a wrong position? Is there a better way to achieve what I want?
If not, is there a way to assign a higher-than-max verticalScrollPosition to a DataGrid and have it show a blank cell where no data exists?
I Hope this was coherent enough ...
BTW: I'm using Flex 4.5.1
I have a swfloader object on to which i want to zoom into (with respect to a point).... this i achieved with some help on the internet.
But now i notice that when i zoom into a point the scroller on the swf loader doesnt work anymore....
Code i am using below... any ideas on how i could correct this problem???
<s:Scroller id="scrollme" width="100%" height="100%" >
<s:HGroup id="mapView" width="100%" height="100%" clipAndEnableScrolling="true" >
<s:SWFLoader id="img" autoLoad="true" addedToStage="img_addedToStageHandler(event)" click="img_clicked(event)" maintainAspectRatio="true" includeIn="normal" />
</s:HGroup>
</s:Scroller>
and the actionscript bit
protected function onZoom(event:TransformGestureEvent):void
{
event.stopImmediatePropagation();
scaleAt(event.scaleX,event.localX,event.localY)
}
public function scaleAt( scale : Number, originX : Number, originY : Number ) : void
{
// get the transformation matrix of this object
affineTransform = img.content.transform.matrix;
//transform.matrix
trace("zooming to " + scale)
// move the object to (0/0) relative to the origin
affineTransform.translate( -originX, -originY )
// scale
affineTransform.scale( scale, scale )
// move the object back to its original position
affineTransform.translate( originX, originY )
// apply the new transformation to the object
img.content.transform.matrix = affineTransform;
//checkscroller();
}
protected function img_addedToStageHandler(event:Event):void
{
Multitouch.inputMode = MultitouchInputMode.GESTURE;
if (!Multitouch.supportsGestureEvents)
currentState = "normal";
else
{
currentState = "normal";
for each (var item:String in Multitouch.supportedGestures)
{
if (item == TransformGestureEvent.GESTURE_PAN)
img.addEventListener(TransformGestureEvent.GESTURE_PAN, onPan);
/* else if (item == TransformGestureEvent.GESTURE_ROTATE)
img.addEventListener(TransformGestureEvent.GESTURE_ROTATE, onRotate); */
else if (item == TransformGestureEvent.GESTURE_SWIPE)
img.addEventListener(TransformGestureEvent.GESTURE_SWIPE, onSwipe);
else if (item == TransformGestureEvent.GESTURE_ZOOM)
img.addEventListener(TransformGestureEvent.GESTURE_ZOOM, onZoom);
}
}
}
Not sure I understand what you're doing. You're using SWFLoader to load an image? Why not just sure the Image component with a source of the url to the image.
Either way, you can't have your HGroup wrapping your component and have clipAndEnableScrolling set to true. Remove that property and you should be good.
<s:Scroller id="scrollme" width="100%" height="100%" >
<s:HGroup id="mapView">
<s:SWFLoader id="img" autoLoad="true" addedToStage="img_addedToStageHandler(event)" click="img_clicked(event)" maintainAspectRatio="true" includeIn="normal" />
</s:HGroup>
</s:Scroller>
When I use <s:Rect> to create a rectangle, I use radiusX to get rounded corners. Problem is all are the same roundedness. Is there something similar to Rect that lets me control the radius for each corner separately? If not, what's the best way to create this from scratch? graphics library or what?
You can do this with a Rect by setting specific values for the topRightRadiusX, topLeftRadiusX, bottomRightRadiusX and bottomLeftRadiusX properties rather than setting radiusX.
public var rectangle:Shape=new Shape();
public var temp:int=1;
public var ui:UIComponent=new UIComponent();
public var i:int=new int;
public var j:int=new int;
public var n:int=0;
public function init(event:Event):void
{
ui.addChild(rectangle);
myCanvas.addChild(ui);
rectangle.graphics.lineStyle(4,0x0000FF,1,false,"normal","none","bevel",9);
rectangle.graphics.drawRoundRect(20,20,200,200,0,0);
}
private function changeSize():void
{
if(temp>=1)
{
rectangle.graphics.clear();
}
rectangle.graphics.lineStyle(4,0x0000FF,1,false,"normal","none","bevel",9);
rectangle.graphics.drawRoundRect(20,20,200,200,hSlider.value,hSlider.value);
}
]]>
</mx:Script>
<mx:Canvas height="100%" width="100%" id="myCanvas">
<mx:HSlider id="hSlider" minimum="0" maximum="170" value="0"
dataTipPlacement="top"
snapInterval="1" tickInterval="1"
labels="['0%','100%']"
liveDragging="true"
change="changeSize();" x="25" y="233"/>
</mx:Canvas>
You might want to check out the StyledBox component here: http://carrythezero.net/blog/2009/06/01/flex-rounding-specific-corners-on-a-box/
It extends box and you can specify through CSS which corners you want rounded.
I need to move a sprite only vertically on mouse move. How do I implement it with as3?
Thanks
Flash version
var s:Sprite = new Sprite();
s.x = 20;
s.graphics.beginFill(0xFF0000);
s.graphics.drawRect(0,0,20,20);
addChild(s);
stage.addEventListener(MouseEvent.MOUSE_MOVE,moveSprite);
function moveSprite(e:MouseEvent):void
{
s.y = e.localY;
}
Flex version
<mx:Canvas width="100" height="100">
<mx:mouseMove>
<![CDATA[
s.y = event.localY;
]]>
</mx:mouseMove>
<mx:Canvas id="s" backgroundColor="#ff0000" width="20" height="20"/>
</mx:Canvas>
Each of these you can paste in and will do what you said. it will create a 20x20 red box that is vertically the same as the mouse but fixed horizontally. The flex version your mouse has to be within the containing Canvas.
addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(e:MouseEvent):void{
mySprite.y += amount;
}
Ok, dragging is a little more complicated. You need to define a rectangle for the bounds of the dragging. If you want to just drag along one axis then you make the rectangle have a width of 0. In this example I've restricted the amount of scrolling and and down to different numbers that you can change below.
import flash.events.MouseEvent;
import flash.geom.Rectangle;
mySprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(event:MouseEvent):void{
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
var scrollUpAmount:int = 10;
var scrollDownAmount:int = 200;
var boundsRect:Rectangle = new Rectangle(mySprite.x,mySprite.y-scrollUpAmount,0,mySprite.y+scrollDownAmount);
mySprite.startDrag(false, boundsRect);
}
function mouseUpHandler(event:MouseEvent):void{
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
mySprite.stopDrag();
}
How do I hide a child in a accordion? Using visible doesn't seem to work and enabled isn't what I'm after.
<mx:Accordion>
<mx:VBox width="100%" height="100%" label="Foo" id="viewOverview" visible="false">
...
</mx:VBox>
...
</mx:Accordion>
I think you can't hide it. Strange that the visible property doesn't work... Anyway, I would control the children through code and remove and insert them as needed by the app. Hiding:
function hideFoo():void {
this.theAccordion.removeChild(this.vboxFoo);
}
You'll probably want to keep a reference to the "hidden" child so that you can add it later again.
This isn't an answer, just some curious things I found out while trying to find another solution to this problem:
Accordion headers have a visible property and a setActualSize method. The latter takes a height and width, and setting each to zero...
acc.getHeaderAt(0).setActualSize(0,0);
...accomplishes the same thing as setting visible = false, that is it hides the contents of the header, but does not remove its area from the accordion. I was hoping to trick the accordion into hiding the child, but no such luck...nonetheless, it might be a path to continue to try. If I get more time I will continue to explore but I'm out of bandwidth at the moment...
You can also create a descendant of accordion with methods like showHeader, hideHeader, isHeaderHidden that contains hash table to keep track of hidden elements similar to the one below:
public class AccordionHideHeader extends Accordion
{
private var _hiddenHeader:Dictionary=new Dictionary();
public function AccordionHideHeader()
{
super();
}
public function hideHeader(header:DisplayObject):void
{
if (contains(header))
{
_hiddenHeader[header]=getChildIndex(header);
removeChild(header);
}
}
public function showHeader(header:DisplayObject):void
{
if (!contains(header))
{
addChildAt(header, _hiddenHeader[header]);
delete _hiddenHeader[header]
}
}
public function isHeaderHidden(header:DisplayObject):Boolean
{
for (var key:Object in _hiddenHeader)
{
if (key==header)
return true;
}
return false;
}
}
Sorry I'm not agree with removing child, because you will having problem when adding it back to its position in exact order.
Example: If you have 5 page in accordion, you remove child 1 and 3, now in any condition you want number 3 back to acordion how do you put it back? because the index is not 3 anymore (rember that 1 is removed too).
I found a good solution here. In short you make your own acordion with enalbe and disable ability where enable and disable define on the child container.
here i paste the acordion code:
/**
* http://blog.flexexamples.com/2008/05/30/preventing-users-from-clicking-on-an-accordion-containers-header-in-flex/
*/
package comps {
import mx.containers.accordionClasses.AccordionHeader;
import mx.events.FlexEvent;
public class MyAccHeader extends AccordionHeader {
public function MyAccHeader() {
super();
addEventListener(FlexEvent.INITIALIZE, accordionHeader_initialize);
}
private function accordionHeader_initialize(evt:FlexEvent):void {
enabled = data.enabled;
}
}
}
Maybe my answer not relevant anymore for you, but i hope can help someone else who face the same problem.
You can override Accordion logic and user includeInLayout property to control visibility of children.
This will work if you set all children in MXML.
import flash.events.Event;
import mx.containers.Accordion;
import mx.core.UIComponent;
public class DynamicAccordion extends Accordion
{
public function DynamicAccordion()
{
}
private var allChildern:Array;
override protected function childrenCreated():void
{
allChildern = new Array();
for (var i:int = numChildren - 1; i >= 0 ; i--)
{
var child:UIComponent = getChildAt(i) as UIComponent;
if (child)
{
child.addEventListener("includeInLayoutChanged", childIncludeLayoutChangedHandler);
if (!child.includeInLayout)
{
removeChild(child);
}
allChildern.push(child);
}
}
allChildern = allChildern.reverse();
super.childrenCreated();
}
private function childIncludeLayoutChangedHandler(event:Event):void
{
var child:UIComponent = event.currentTarget as UIComponent;
if (child.includeInLayout)
{
var index:int = allChildern.indexOf(child);
addChildAt(child, index);
}
else
{
removeChild(child);
}
}
}
I think you might have to actually remove the accordion child itself (e.g. using the State removeChild() mechanism). If you need to preserve the object itself, just keep a reference to it in a global variable.
Cheers
Accordion controls always have 1 child open. By opening another child, the current one will close.
If you want to have more than 1 child open at a time or have all children closed, you can use the VStack component available at: http://weblogs.macromedia.com/pent/archives/2007/04/the_stack_compo.html
<mx:Script>
<![CDATA[
private function hideFn():void
{
acc.removeChildAt(0);
}
private function showFn():void
{
acc.addChildAt(helloBox , 0);
}
]]>
</mx:Script>
<mx:VBox>
<mx:Accordion id="acc" width="200" height="200">
<mx:VBox id="helloBox" label="Test">
<mx:Label text="hello"/>
</mx:VBox>
<mx:VBox label="Test2">
<mx:Label text="hello again"/>
</mx:VBox>
</mx:Accordion>
<mx:Button label="hide" click="hideFn()"/>
<mx:Button label="show" click="showFn()"/>
</mx:VBox>
Here my solution :
http://weflex.wordpress.com/2011/01/25/flex-accordion-hideshow-headers/
I copied and modified the code of the Accordion, so if a child has its "includeInLayout" property to false, it won't be displayed.
Try this one
accrod.getHeaderAt(0).enabled=false;
accrod.getHeaderAt(0).visible=false;
Here is the solution, how to collapse the accordion on click of header.
<mx:Script>
<![CDATA[
import mx.events.IndexChangedEvent;
private var isAccordionClosed:Boolean;
private function myAccordion_clickHandler(event:MouseEvent):void
{
trace(event.currentTarget.label);
var selIdx:int = myAccordion.selectedIndex;
isAccordionClosed = (isAccordionClosed) ? false : true;
if (isAccordionClosed)
{
collapseAccordion(selIdx, !isAccordionClosed);
}
else
{
collapseAccordion(selIdx, !isAccordionClosed);
}
}
private function collapseAccordion(idx:int, showHide:Boolean):void
{
switch(idx)
{
case 0:
vb1.scaleX = vb1.scaleY = int(showHide);
break;
case 1:
vb2.scaleX = vb2.scaleY = int(showHide);
break;
case 2:
vb3.scaleX = vb3.scaleY = int(showHide);
break;
case 3:
vb4.scaleX = vb4.scaleY = int(showHide);
break;
case 4:
vb5.scaleX = vb5.scaleY = int(showHide);
break;
}
}
private function myAccordion_changeHandler(event:IndexChangedEvent):void
{
isAccordionClosed = true;
}
]]>
</mx:Script>
<mx:Accordion id="myAccordion" x="200" y="200" click="myAccordion_clickHandler(event)" resizeToContent="true"
width="399" verticalGap="0" change="myAccordion_changeHandler(event)">
<mx:VBox id="vb1" label="Chapter 1">
<mx:Label text="Accordion 1" width="397" textAlign="center" height="38"/>
</mx:VBox>
<mx:VBox id="vb2" label="Chapter 2">
<mx:Label text="Accordion 2" width="397" textAlign="center" height="43"/>
</mx:VBox>
<mx:VBox id="vb3" label="Chapter 3">
<mx:Label text="Accordion 3" width="397" textAlign="center" height="43"/>
</mx:VBox>
<mx:VBox id="vb4" label="Chapter 4">
<mx:Label text="Accordion 4" width="397" textAlign="center" height="43"/>
</mx:VBox>
<mx:VBox id="vb5" label="Chapter 5">
<mx:Label text="Accordion 5" width="397" textAlign="center" height="43"/>
</mx:VBox>
</mx:Accordion>