Flex custom item renderer for the displayed item in the combobox - apache-flex

I am using a custom item renderer in a combobox to display a custom drawing instead of the default text label.
This works fine for the dropdown list but the displayed item ( when the list is closed) is still the textual representation of my object.
Is there a way to have the displayed item rendered the same way as the one in the dropdown?

By default you cannot do this. However, if you extend ComboBox you can add this functionality easily. Here is a quick example, it is a rough version and probably needs testing / tweaking but it shows how you could accomplish this.
package
{
import mx.controls.ComboBox;
import mx.core.UIComponent;
public class ComboBox2 extends ComboBox
{
public function ComboBox2()
{
super();
}
protected var textInputReplacement:UIComponent;
override protected function createChildren():void {
super.createChildren();
if ( !textInputReplacement ) {
if ( itemRenderer != null ) {
//remove the default textInput
removeChild(textInput);
//create a new itemRenderer to use in place of the text input
textInputReplacement = itemRenderer.newInstance();
addChild(textInputReplacement);
}
}
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
if ( textInputReplacement ) {
textInputReplacement.width = unscaledWidth;
textInputReplacement.height = unscaledHeight;
}
}
}
}

I tried the above solution, but found that the selectedItem did not display when the combobox was closed. A extra line of code was required to bind the itemRenderer data property to the selectedItem:
if ( !textInputReplacement ) {
if ( itemRenderer != null ) {
//remove the default textInput
removeChild(textInput);
//create a new itemRenderer to use in place of the text input
textInputReplacement = itemRenderer.newInstance();
// ADD THIS BINDING:
// Bind the data of the textInputReplacement to the selected item
BindingUtils.bindProperty(textInputReplacement, "data", this, "selectedItem", true);
addChild(textInputReplacement);
}
}

I've extended Dane's code a bit further. In some cases clicking did not open the drop box with my renderer and I noticed that the normal Flex ComboBox skins did not fire. Thus in replaceTextInput() I added some additional event listeners and save a reference to the ComboBox button used to display the skins. Now it behaves just like the normal ComboBox.
Here's the code:
package
{
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import mx.binding.utils.BindingUtils;
import mx.controls.Button;
import mx.controls.ComboBox;
import mx.core.IFactory;
import mx.core.UIComponent;
import mx.events.DropdownEvent;
/**
* Extension of the standard ComboBox that will use the assigned 'itemRenderer'
* for both the list items and the selected item.
*
* Based on code from:
* http://stackoverflow.com/questions/269773/flex-custom-item-renderer-for-the-displayed-item-in-the-combobox
*/
public class ComboBoxFullRenderer extends ComboBox
{
protected var textInputReplacement:UIComponent;
private var _increaseW:Number = 0;
private var _increaseH:Number = 0;
/**
* Keeps track of the current open/close state of the drop down list.
*/
protected var _isOpen:Boolean = false;
/**
* Stores a reference to the 'Button' which overlays the ComboBox. Allows
* us to pass events to it so skins are properly triggered.
*/
protected var _buttonRef:Button = null;
/**
* Constructor.
*/
public function ComboBoxFullRenderer() {
super();
}
/**
* Sets a value to increase the width of our ComboBox to adjust sizing.
*
* #param val Number of pixels to increase the width of the ComboBox.
*/
public function set increaseW(val:Number):void {
_increaseW = val;
}
/**
* Sets a value to increase the height of our ComboBox to adjust sizing.
*
* #param val Number of pixels to increase the height of the ComboBox.
*/
public function set increaseH(val:Number):void {
_increaseH = val;
}
/**
* Override the 'itemRenderer' setter so we can also replace the selected
* item renderer.
*
* #param value The renderer to be used to display the drop down list items
* and the selected item.
*/
override public function set itemRenderer(value:IFactory):void {
super.itemRenderer = value;
replaceTextInput();
}
/**
* Override base 'createChildren()' routine to call our 'replaceTextInput()'
* method to replace the standard selected item renderer.
*
* #see #replaceTextInput();
*/
override protected function createChildren():void {
super.createChildren();
replaceTextInput();
}
/**
* Routine to replace the ComboBox 'textInput' child with our own child
* that will render the selected data element. Will create an instance of
* the 'itemRenderer' set for this ComboBox.
*/
protected function replaceTextInput():void {
if ( !textInputReplacement ) {
if ( this.itemRenderer != null && textInput != null ) {
//remove the default textInput
removeChild(textInput);
//create a new itemRenderer instance to use in place of the text input
textInputReplacement = this.itemRenderer.newInstance();
// Listen for clicks so we can open/close the drop down when
// renderer components are clicked.
textInputReplacement.addEventListener(MouseEvent.CLICK, _onClick);
// Listen to the mouse events on our renderer so we can feed them to
// the ComboBox overlay button. This will make sure the button skins
// are activated. See ComboBox::commitProperties() code.
textInputReplacement.addEventListener(MouseEvent.MOUSE_DOWN, _onMouseEvent);
textInputReplacement.addEventListener(MouseEvent.MOUSE_UP, _onMouseEvent);
textInputReplacement.addEventListener(MouseEvent.ROLL_OVER, _onMouseEvent);
textInputReplacement.addEventListener(MouseEvent.ROLL_OUT, _onMouseEvent);
textInputReplacement.addEventListener(KeyboardEvent.KEY_DOWN, _onMouseEvent);
// Bind the data of the textInputReplacement to the selected item
BindingUtils.bindProperty(textInputReplacement, "data", this, "selectedItem", true);
// Add our renderer as a child.
addChild(textInputReplacement);
// Listen for open close so we can maintain state. The
// 'isShowingDropdown' property is mx_internal so we don't
// have access to it.
this.addEventListener(DropdownEvent.OPEN, _onOpen);
this.addEventListener(DropdownEvent.CLOSE, _onClose);
// Save a reference to the mx_internal button for the combo box.
// We will need this so we can call its dispatchEvent() method.
for (var i:int = 0; i < this.numChildren; i++) {
var temp:Object = this.getChildAt(i);
if (temp is Button) {
_buttonRef = temp as Button;
break;
}
}
}
}
}
/**
* Detect open events on the drop down list to keep track of the current
* drop down state so we can react properly to a click on our selected
* item renderer.
*
* #param event The DropdownEvent.OPEN event for the combo box.
*/
protected function _onOpen(event:DropdownEvent) : void {
_isOpen = true;
}
/**
* Detect close events on the drop down list to keep track of the current
* drop down state so we can react properly to a click on our selected
* item renderer.
*
* #param event The DropdownEvent.CLOSE event for the combo box.
*/
protected function _onClose(event:DropdownEvent) : void {
_isOpen = false;
}
/**
* When we detect a click on our renderer open or close the drop down list
* based on whether the drop down is currently open/closed.
*
* #param event The CLICK event from our selected item renderer.
*/
protected function _onClick(event:MouseEvent) : void {
if (_isOpen) {
this.close(event);
} else {
this.open();
}
}
/**
* React to certain mouse/keyboard events on our selected item renderer and
* pass the events to the ComboBox 'button' so that the skins are properly
* applied.
*
* #param event A mouse or keyboard event to send to the ComboBox button.
*
*/
protected function _onMouseEvent(event:Event) : void {
if (_buttonRef != null) {
_buttonRef.dispatchEvent(event);
}
}
} // end class
} // end package

Thank you maclema and Maurits de Boer. I added a couple more things to this class to make it fit my needs:
I overrode set itemRenderer so that this will work if you set the itemRenderer through AS instead of mxml. I moved the text input replacement code to its own function to avoid duplication.
I added setters for 'increaseW' and 'increaseH' to resize the combobox if necessary because my renderer was too big for the combobox at first.
I subtracted 25 from the textInputReplacement width so it doesn't ever overlap the dropdown button... may be better to use something more proportional to accommodate different skins and such.
Code:
package
{
import mx.binding.utils.BindingUtils;
import mx.controls.ComboBox;
import mx.core.IFactory;
import mx.core.UIComponent;
public class ComboBox2 extends ComboBox
{
public function ComboBox2()
{
super();
}
protected var textInputReplacement:UIComponent;
private var _increaseW:Number = 0;
private var _increaseH:Number = 0;
public function set increaseW(val:Number):void
{
_increaseW = val;
}
public function set increaseH(val:Number):void
{
_increaseH = val;
}
override public function set itemRenderer(value:IFactory):void
{
super.itemRenderer = value;
replaceTextInput();
}
override protected function createChildren():void
{
super.createChildren();
replaceTextInput();
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
unscaledWidth += _increaseW;
unscaledHeight += _increaseH;
super.updateDisplayList(unscaledWidth, unscaledHeight);
if ( textInputReplacement ) {
textInputReplacement.width = unscaledWidth - 25;
textInputReplacement.height = unscaledHeight;
}
}
protected function replaceTextInput():void
{
if ( !textInputReplacement ) {
if ( this.itemRenderer != null ) {
//remove the default textInput
removeChild(textInput);
//create a new itemRenderer to use in place of the text input
textInputReplacement = this.itemRenderer.newInstance();
addChild(textInputReplacement);
// ADD THIS BINDING:
// Bind the data of the textInputReplacement to the selected item
BindingUtils.bindProperty(textInputReplacement, "data", this, "selectedItem", true);
addChild(textInputReplacement);
}
}
}
}
}

I was looking for a way to do this using the Spark ComboBox.
This thread was very useful to me but so far there have only been answers on how to do it using an mx:ComboBox. I thought that I should append my answer on how to do it using a spark ComboBox.
Create a new skin of the ComboBox
Hide and disable the textInput
Insert your own component
This is what the skin would look like:
<s:SparkSkin>
<... Lots of other stuff/>
<s:BorderContainer height="25">
<WHATEVER YOU NEED HERE!/>
</s:BorderContainer>
<!-- Disable the textInput and hide it -->
<s:TextInput id="textInput"
left="0" right="18" top="0" bottom="0"
skinClass="spark.skins.spark.ComboBoxTextInputSkin"
visible="false" enabled="false"/>
</s:SparkSkin>
With the Spark ComboBox this process is very easy and does not require you to extend ComboBox.

I found an easier way of changing the renderer for the selected element. This one only works if your element inherits from the TextInput class, in Flex 4.0 or above.
In Flex v4.5, in ComboBase.createChildren at line 1177, you will find that the class definable for the textInput can be passed using the style key textInputClass:
// Mechanism to use MXFTETextInput.
var textInputClass:Class = getStyle("textInputClass");
if (!textInputClass || FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_0)
{
textInput = new TextInput();
}
else
{
textInput = new textInputClass();
}
Just change the value of this key in the constructor of your combo and now you have your own renderer for the selectedItem.
public function ComboAvailableProfessor()
{
super();
itemRenderer = new ClassFactory( ProfessorAvailableListItemRenderer );
setStyle( 'textInputClass', ProfessorAvailableSelectedListItemRenderer );
}
Finally you must bind the data property to the selectedItem property in your combo in order to get data displayed.
override protected function createChildren():void
{
super.createChildren();
BindingUtils.bindProperty( textInput, 'data', this, 'selectedItem', true );
}

Related

Flex Disabled Checkbox toolTip

I need to be able to show a toolTip on disabled checkboxes. A solution I've seen here on stackoverflow and other places is to just wrap the checkbox in a Group and give the Group the toollTip. This works, but I'm trying to do this generically.
I want to be able to set a property on a custom Checkbox component and at that point wrap the Chexbox in a Group that has the toolTip set.
My problem is, I can't figure out how to add the Checkbox to a Group component at run time in the Checkbox ActionScript code. I've tried adding a showDisabledToolTip property to the Checkbox Class and when that is set do something like this:
var parent = this.parent;
var gp:Group = new Group();
gp.toolTip = this.toolTip;
gp.addElement(this);
if(parent is Group) {
parent.addElement(gp);
} else {
parent.addChild(gp);
}
My main problem at that point is this.parent is null. Besides that though, I don't even know if this will really work.
Help is appreciated. Thanks!
i came up with the solution to extend the CheckBox class and create a new CheckBoxSkin with 2 new SkinStates inside (disabledWithTooltip and disabledWithTooltipSelected)
The extended Checkbox class adds a new disabledWithTooltip property and overrides the getCurrentSkinState method and the mouseEventHandler from ButtonBase
Custom CheckBox class
package components
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.events.FlexEvent;
import spark.components.CheckBox;
[SkinState (disabledWithToolTip)]
[SkinState (disabledWithToolTipSelected)]
public class CustomCheckBox extends CheckBox
{
private var _disabledKeepToolTip:Boolean = false;
public function CustomCheckBox()
{
super();
this.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete, false, 0, true);
}
protected function onCreationComplete(ev:FlexEvent):void {
//_storedState = this.currentState;
}
protected override function getCurrentSkinState():String {
if(!_disabledKeepToolTip)
return super.getCurrentSkinState();
else {
if(!selected)
return "disabledWithToolTip";
else
return "disabledWithToolTipSelected";
}
}
protected override function mouseEventHandler(event:Event):void {
var skinState:String = getCurrentSkinState();
if(skinState != "disabledWithToolTip" && skinState != "disabledWithToolTipSelected") {
super.mouseEventHandler(event);
}
}
[Bindable]
[Inspectable(category="General", enumeration="true,false", defaultValue="true")]
public function get disabledKeepToolTip():Boolean {
return _disabledKeepToolTip;
}
public function set disabledKeepToolTip(value:Boolean):void {
_disabledKeepToolTip = value;
this.invalidateSkinState();
}
}
}
Create a new Skin based on (spark) CheckBoxSkin and change the hostcomponent in the metadata
[HostComponent("components.CustomCheckBox")]
and add two new skinStates
<s:State name="disabledWithToolTip" stateGroups="disabledStates" />
<s:State name="disabledWithToolTipSelected" stateGroups="disabledStates, selectedStates" />
Usage e.g.
<s:HGroup>
<components:CustomCheckBox id="custom_chk" label="KeepTooltipCheckbox" skinClass="skins.CustomCheckBoxSkin" toolTip="See this tooltip"/>
<s:CheckBox id="enable_chk" label="enable/disable" change="{custom_chk.disabledKeepToolTip = enable_chk.selected}"/>
</s:HGroup>
You have to adapt your own package structure if it's different...

How to disable the icon on a Flex3 Button

I have a button which I use for sending a message. When the message text is empty, it should not be possible to click the button.
This is all fine and not an issue. The only thing that is bugging me is the fact that I can disable the send button but the image does not get disabled (like I would expect).
Is there a way to do this elegantly because I don't want to provide a sendicon_disabled.png and change it myself (I don't think this should be my job).
You can use the following button for that:
package
{
import mx.controls.Button;
import mx.core.mx_internal;
use namespace mx_internal;
public class IconButton extends Button
{
private var enabledChanged:Boolean = false;
override public function set enabled(value:Boolean):void
{
if (super.enabled == value)
{
return;
}
super.enabled = value;
enabledChanged = true;
invalidateDisplayList();
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (enabledChanged)
{
if (!enabled && currentIcon)
{
currentIcon.alpha = 0.5;
}
enabledChanged = false;
}
}
}
}
You can use your custom alpha value or move it to separate style.

Flex combobox needs to be selected twice to open drop down list

When a combobox is elected in the flex app, there is a quick flicker, then the combobox needs to be selected again in order to get the dropdown to open. After that, the dropdown works as expected, but only while selecting the control subsequent times while on the form. Reloading the form requires the double selection again. Any insights to how to clear this up would be very much appreciated.
The way I had to get around this issue was my creating a custom component that extends the ComboBox control that will set the ComboBox's List dataProvider at the same time as the ComboBox's dataProvider.
ComboBoxFix.as
package
{
import mx.controls.ComboBox;
public class ComboBoxFix extends ComboBox
{
public function ComboBoxFix()
{
super();
}
override public function set dataProvider(value:Object):void
{
super.dataProvider=value;
if(dropdown != null)
{
super.dropdown.dataProvider=value;
}
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number ):void
{
super.updateDisplayList (unscaledWidth, unscaledHeight);
if (dropdown != null)
{
dropdown.width = unscaledWidth;
}
}
}
}

Datagrid selects the wrong custom cell in my datagrid

I am working on a problem since a week soon, but I still couldn't make it work as expected. I have a DataGrid which has HBox with a CheckBox an a Label as itemRenderer (see Code below). When I tap in to the Cell the standard itemEditor pops up and lets you enter the content of the label. Thats the standard behavior. I works fine except for 2 problems:
If I enter to much text, the horizontal srollbar pops up, and the cell is filled with that scrollbar. As you see I tried to set the horizontalScrollPolicy to off, but that doesnt work at all... I tried to do that for all the different elements, but the failure is still existent.
When I have filled more than one row, there is an other mistake happening. If I tap on a row, the datagrid selects the one below that row. That's only if one line is already selected. If I tap outside the datagrid and then, tap at any row the itemEditor of the right row will show up... Is there anything now wright in the setup of my set data method?
__
package components
{
import mx.containers.HBox;
import mx.controls.CheckBox;
import mx.controls.Label;
public class ChoiceRenderer extends HBox
{
private var correctAnswer:CheckBox;
private var choiceLabel:Label;
public function ChoiceRenderer()
{
super();
paint();
}
private function paint():void{
percentHeight = 100;
percentWidth = 100;
setStyle("horizontalScrollPolicy", "off");
super.setStyle("horizontalScrollPolicy", "off");
correctAnswer = new CheckBox;
correctAnswer.setStyle("horizontalScrollPolicy", "off");
addChild(correctAnswer);
choiceLabel = new Label;
choiceLabel.setStyle("horizontalScrollPolicy", "off");
addChild(choiceLabel);
}
override public function set data(xmldata:Object):void{
if(xmldata.name() == "BackSide"){
var xmlText:Object = xmldata.TextElements.TextElement.(#position == position)[0];
super.data = xmlText;
choiceLabel.text = xmlText.toString();
correctAnswer.selected = xmlText.#correct_answer;
}
}
}
Thanks in advance!
Markus
I am not sure if this is the reason behind your issues, but the standard way of creating children is to override the createChildren method.
Also, you are missing an else statement - you are not calling super.data when if condition fails. That doesn't look good either.
Try:
package components
{
public class ChoiceRenderer extends HBox {
private var correctAnswer:CheckBox;
private var choiceLabel:Label;
public function ChoiceRenderer() {
super();
percentHeight = 100;
percentWidth = 100;
setStyle("horizontalScrollPolicy", "off");
}
override protected function createChildren():void {
super.createChildren();
correctAnswer = new CheckBox();
addChild(correctAnswer);
choiceLabel = new Label();
choiceLabel.setStyle("horizontalScrollPolicy", "off");
addChild(choiceLabel);
}
override public function set data(xmldata:Object):void {
if(xmldata.name() == "BackSide") {
var xmlText:Object = xmldata.TextElements.TextElement.(#position == position)[0];
super.data = xmlText;
choiceLabel.text = xmlText.toString();
correctAnswer.selected = xmlText.#correct_answer;
}
else {
//what if xmldata.name() is not "BackSide"?
//you are not calling super.data in that case
}
}
}
in order to avoid scroll bar you have to let datagrid have variable height
<mx:DataGrid id="dg"
dataProvider="{dp}"
variableRowHeight="true"
creationComplete="dg.height=dg.measureHeightOfItems(0,dp.length)+dg.headerHeight+2"/>

Flex AdvancedDataGrid Tree Custom Drag

I'd like to implement a custom drag on an AdvancedDataGrid tree structure, which only allows the drag on the branches (not leaves).
I'm having much difficultly with this, trying to use the MouseDown event, but not having luck!
Okay, I think I've got the mousedown able to figure out if the item is a branch of leaf. Any help on how to perform the custom drag with an advanceddatagrid??
var grid : AdvancedDataGrid = AdvancedDataGrid(event.currentTarget);
if(grid.selectedItem.hasOwnProperty("categories")
&& grid.selectedItem.categories!=null) {
Alert.show("yes");
}
else { Alert.show("no"); }
I've tried many different ways to do this, and this is the best solution that I have come up with. AdvancedDataGrid already has logic built in to handle the mouseMove/mouseOver/mouseDown events, so there's no need to recreate it. Simply override the DragEvent handlers.
I have duplicated the code I use in several applications that need similar functionality, included your logic for determining if the item can be dragged, as well as some logic to determine if it can be dropped in a certain location. I have also included extensive commenting to help explain why certain things are done. I hope this helps!
CustomADG.as:
package
{
import mx.controls.AdvancedDataGrid;
import mx.controls.listClasses.IListItemRenderer;
import mx.core.DragSource;
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.utils.ObjectUtil;
public class DragDropADG extends AdvancedDataGrid
{
private var itemRendererUnderPoint:IListItemRenderer
public function DragDropADG()
{
super();
}
override protected function dragStartHandler(event:DragEvent):void
{
/* Create a new Array from the Array of selectedItems, filtering out items
that are not "branches". */
var selectedBranches:Array /* of Object */ =
selectedItems.filter(hasCategories);
function hasCategories(element:*, index:int, array:Array):Boolean
{
/* Returns true if the item is a Branch (has children in the categories
property). */
return (element.hasOwnProperty("categories") &&
element.categories != null);
}
/* Exit if no Branches are selected. This will stop the drag operation from
starting. */
if (selectedBranches.length == 0)
return;
/* Reset the selectedItems Array to include only selected Branches. This
will deselect any "non-Branch" items. */
selectedItems = selectedBranches;
/* Create a copy of the Array of selected indices to be sorted for
display in the drag proxy. */
var sortedSelectedIndices:Array /* of int */ =
ObjectUtil.copy(selectedIndices) as Array /* of int */;
// Sort the selected indices
sortedSelectedIndices.sort(Array.NUMERIC);
/* Create an new Array to store the selected Branch items sorted in the
order that they are displayed in the AdvancedDataGrid. */
var draggedBranches:Array = [];
var itemRendererAtIndex:IListItemRenderer;
for each (var index:int in sortedSelectedIndices)
{
itemRendererAtIndex = indexToItemRenderer(index);
var branchItem:Object = itemRendererAtIndex.data;
draggedBranches.push(branchItem);
}
// Create a new DragSource Object to store data about the Drag operation.
var dragSource:DragSource = new DragSource();
// Add the Array of Branches to be dragged to the DragSource Object.
dragSource.addData(draggedBranches, "draggedBranches");
// Create a new Container to serve as the Drag Proxy.
var dragProxy:DragProxyContainer = new DragProxyContainer();
/* Update the labels in the Drag Proxy using the "label" field of the items
being dragged. */
dragProxy.setLabelText(draggedBranches);
/* Create a point relative to this component from the mouse
cursor location (for the DragEvent). */
var eventPoint:Point = new Point(event.localX, event.localY);
// Initiate the Drag Event
DragManager.doDrag(this, dragSource, event, dragProxy,
-eventPoint.x, -eventPoint.y, 0.8);
}
/* This function runs when ANY item is dragged over any part of this
AdvancedDataGrid (even if the item is from another component). */
override protected function dragEnterHandler(event:DragEvent):void
{
/* If the item(s) being dragged does/do not contain dragged Branches,
it/they are being dragged from another component; exit the function to
prevent a drop from occurring. */
if (!event.dragSource.hasFormat("draggedBranches"))
return;
var dropIndex:int = calculateDropIndex(event);
/* Get the itemRenderer of the current drag target, to determine if the
drag target can accept a drop. */
var dropTargetItemRenderer:IListItemRenderer =
indexToItemRenderer(dropIndex);
/* If the item is being dragged where there is no itemRenderer, exit the
function, to prevent a drop from occurring. */
if (dropTargetItemRenderer == null)
return;
/* If the item is being dragged onto an itemRenderer with no data, exit the
function, to prevent a drop from occurring. */
if (dropTargetItemRenderer.data == null)
return;
/* Store the underlying item for the itemRenderer being dragged over, to
validate that it can be dropped there. */
var dragEnterItem:Object = dropTargetItemRenderer.data
if (!dragEnterItem.hasOwnProperty("categories")
return;
if (dragEnterItem.categories == null)
return;
var eventDragSource:DragSource = event.dragSource;
eventDragSource.addData(dragEnterItem, "dropTargetItem");
/* Add an dragDrop Event Listener to the itemRenderer so that the
necessary will run when it is dropped.*/
dropTargetItemRenderer.addEventListener(DragEvent.DRAG_DROP,
itemRenderer_dragDropHandler);
// Specify that the itemRenderer being dragged over can accept a drop.
DragManager.acceptDragDrop(dropTargetItemRenderer);
}
/* Perform any logic that you want to occur once the user drops the item. */
private function itemRenderer_dragDropHandler(event:DragEvent):void
{
var eventDragSource:DragSource = event.dragSource;
var dropTargetItem:Object =
eventDragSource.dataForFormat("dropTargetItem");
if (dropTargetItem == null)
return;
var draggedBranchesData:Object =
eventDragSource.dataForFormat("draggedBranches");
var draggedBranches:Array /* of Object */ =
draggedBranchesData as Array /* of Object */;
// Call any other functions to update your underlying data, etc.
}
}
}
DragProxyContainer.as:
package
{
import mx.containers.VBox;
import mx.core.UITextField;
[Bindable]
public class DragProxyContainer extends VBox
{
private var textField:UITextField = new UITextField();
public function DragProxyContainer()
{
super();
minWidth = 150;
addChild(textField);
}
public function setLabelText(items:Array, labelField:String = "label"):void
{
var labelText:String;
var numItems:int = items.length;
if (numItems > 1)
{
labelText = numItems.toString() + " items";
}
else
{
var firstItem:Object = items[0];
labelText = firstItem[labelField];
}
textField.text = labelText;
}
}
}
You can try handling the dragEnter() event to stop dragging if the object is a leaf.

Resources