How to set flex 3 tree label clickable? - actionscript-3

How to set tree label clickable so tree node can expand? (not only click on arrow icon)

Solved.
<mx:Script>
<![CDATA[
import mx.collections.ICollectionView;
import mx.events.ListEvent;
private function tree_itemClick(evt:ListEvent):void {
var item:Object = Tree(evt.currentTarget).selectedItem;
if (tree.dataDescriptor.isBranch(item)) {
tree.expandItem(item, !tree.isItemOpen(item), true);
}
}
]]>
<mx:XML id="dp">
<root>
<folder label="One">
<folder label="One.A">
<item label="One.A.1" />
<item label="One.A.2" />
<item label="One.A.3" />
<item label="One.A.4" />
<item label="One.A.5" />
</folder>
<item label="One.1" />
<item label="One.2" />
</folder>
</root>
</mx:XML>
<mx:Tree id="tree" dataProvider="{dp}" showRoot="false" labelField="#label" width="300" rowCount="6"
itemClick="tree_itemClick(event);" />

Related

How to change the tab layout theme programmatically?

I have created a custom style for my tab layout in styles.xml file.
styles.xml:
<style name="AppTabLayout" parent="Widget.Design.TabLayout">
<item name="tabMaxWidth">#dimen/tab_max_width</item>
<item name="tabIndicatorColor">?attr/colorAccent</item>
<item name="tabIndicatorHeight">4dp</item>
<item name="tabPaddingStart">6dp</item>
<item name="tabPaddingEnd">6dp</item>
<item name="tabBackground">?attr/selectableItemBackground</item>
<item name="tabTextAppearance">#style/AppTabTextAppearance</item>
<item name="tabSelectedTextColor">#color/range</item>
</style>
<!-- for text -->
<style name="AppTabTextAppearance" parent="TextAppearance.Design.Tab">
<item name="android:textSize">12sp</item>
<item name="android:textColor">#color/orange</item>
<item name="textAllCaps">false</item>
</style>
Apply:
<android.support.design.widget.TabLayout
style="#style/AppTabLayout"
app:tabTextAppearance="#style/AppTabTextAppearance"
android:layout_width="match_parent"
.... />
I used this code for my tablayout.
Everything works fine. But I want to change the style at runtime. I have gone through stackoverflow, but haven't found anything about this. Is it possible ?
styles.xml
<resources>
<attr name="tabLayoutStyle" format="reference" />
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
</style>
<style name="AppTheme.Blue">
<item name="tabLayoutStyle">#style/Blue.TabLayout</item>
</style>
<style name="Blue.TabLayout" parent="Base.Widget.Design.TabLayout">
<item name="tabSelectedTextColor">#color/selected_textBlue</item>
<item name="tabIndicatorColor">#color/accent_blue</item>
<item name="tabBackground">#color/primary_blue</item>
</style>
<style name="AppTheme.Red">
<item name="tabLayoutStyle">#style/Red.TabLayout</item>
</style>
<style name="Red.TabLayout" parent="Base.Widget.Design.TabLayout">
<item name="tabSelectedTextColor">#color/selected_textRed</item>
<item name="tabIndicatorColor">#color/accent_red</item>
<item name="tabBackground">#color/primary_red</item>
</style>
<color name="selected_textBlue">#000055</color>
<color name="accent_blue">#0000ff</color>
<color name="primary_blue">#0099ff</color>
<color name="selected_textRed">#880022</color>
<color name="accent_red">#550000</color>
<color name="primary_red">#ff0000</color>
</resources>
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<android.support.design.widget.TabLayout
style="?attr/tabLayoutStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TabItem
android:text="Tab 1" />
<android.support.design.widget.TabItem
android:text="Tab 2" />
</android.support.design.widget.TabLayout>
<Button
android:id="#+id/mainButton0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Red"
android:onClick="onClick" />
<Button
android:id="#+id/mainButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Blue"
android:onClick="onClick" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(PreferenceManager.getDefaultSharedPreferences(this)
.getInt("theme", R.style.AppTheme_Blue));
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(android.view.View v) {
switch (v.getId()) {
case R.id.mainButton0:
PreferenceManager.getDefaultSharedPreferences(this)
.edit().putInt("theme",
R.style.AppTheme_Red).commit();
break;
case R.id.mainButton1:
PreferenceManager.getDefaultSharedPreferences(this)
.edit().putInt("theme",
R.style.AppTheme_Blue).commit();
break;
}
recreate();
}
}

loading Skin images dynamically

(another of my never ending questions...)
I need an image component with states which behaves like a ToggleButton. Rather than build from scratch I thought I would try subclassing ToggleButton and defining a custom Flex skin. I don't have much experience with skinning and have cobbled together the code below.
It seems to work well – binding BitmapImages in the skin to BitmapData loading in the button instance: <s:BitmapImage source="{hostComponent.upImageData}"
Am I on the right track with this approach? Is there a more standard approach to this sort of thing?
ToggleButton Skin
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
minWidth="21" minHeight="21"
alpha.disabledStates="0.5">
<fx:Metadata>[HostComponent("components.EventButton")]</fx:Metadata>
<!-- host component -->
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" stateGroups="overStates" />
<s:State name="down" stateGroups="downStates" />
<s:State name="disabled" stateGroups="disabledStates" />
<s:State name="upAndSelected" stateGroups="selectedStates, selectedUpStates" />
<s:State name="overAndSelected" stateGroups="overStates, selectedStates" />
<s:State name="downAndSelected" stateGroups="downStates, selectedStates" />
<s:State name="disabledAndSelected" stateGroups="selectedUpStates, disabledStates, selectedStates" />
</s:states>
<s:BitmapImage source="{hostComponent.upImageData}"
includeIn="up, disabled"
left="0" right="0" top="0" bottom="0" />
<s:BitmapImage source="{hostComponent.overImageData}"
left="0" right="0" top="0" bottom="0"
includeIn="over"/>
<s:BitmapImage source="{hostComponent.downImageData}"
left="0" right="0" top="0" bottom="0"
includeIn="down, upAndSelected, overAndSelected, downAndSelected"/>
</s:Skin>
ToggleButton
<?xml version="1.0" encoding="utf-8"?>
<s:ToggleButton 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:skins = "skins.*"
skinClass="skins.EventSkin"
creationComplete="creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
[Bindable]
public var upImageData:BitmapData;
[Bindable]
public var overImageData:BitmapData;
[Bindable]
public var downImageData:BitmapData;
[Bindable]
public var disabledImageData:BitmapData;
// image loading code removed
]]>
</fx:Script>
</s:ToggleButton>
Yep, you are going in right way. The "Skin mechanism" is really powerful and flexible tool. I had similar task about year ago and I solved it in the same way (just with standard ToggleButton and custom skin). All changes in visual representation of spark component might to be in skin class.
As another option, you should be able to use the state variable syntax:
<s:ToggleButton icon.up="{upIcon}"
icon.over="{overIcon}"
icon.down="{downIcon}"
icon.disabled="{disabledIcon}"
icon.upAndSelected="{upAndSelectedIcon}"
icon.overAndSelected="{overAndSelectedIcon}"
icon.downAndSelected="{downAndSelectedIcon}"
icon.disabledAndSelected="{disabledAndSelectedIcon}" />
See this Apache mailing list thread for more discussion on this.

Preventing Flex tree drop feedback

I'd like to allow a user to reorder items within a Flex tree folder, but not move those items outside of the folder. I can prevent the outside drop from succeeding, but I'd like to give the user feedback (before the drop) that the drop will not succeed. I've found many examples regarding the drop action, but nothing that shows the correct feedback to the user.
According to the Tree documentation, I should be able to call DragManager.showFeedback(DragManager.NONE) during the dragOver event, but that's not working. A short sample project is included below. Is there any way to indicate to the user during a drag event that the drop will not succeed?
Thanks in advance for any solution!
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="354"
height="480">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.core.IUIComponent;
import mx.core.mx_internal;
import mx.events.DragEvent;
import mx.events.FlexEvent;
import mx.managers.DragManager;
protected function tree_dragEnterHandler(event:DragEvent):void {
// only items can be dragged - not folders
if (tree.selectedItem.#type == "item") {
DragManager.acceptDragDrop(IUIComponent(event.currentTarget));
} else {
event.preventDefault();
DragManager.showFeedback(DragManager.NONE);
}
}
protected function tree_dragOverHandler(event:DragEvent):void {
var dropData:Object = tree.mx_internal::_dropData;
var dragItem:XML = event.dragSource.dataForFormat("treeItems")[0];
if (!dropData || !dropData.parent || !dragItem.parent() || dragItem.parent() != dropData.parent) {
trace("preventing drop");
DragManager.showFeedback(DragManager.NONE);
return;
}
trace("allowing drop");
DragManager.showFeedback(DragManager.MOVE);
}
protected function tree_dragDropHandler(event:DragEvent):void {
}
]]>
</fx:Script>
<fx:Declarations>
<fx:XML id="treeData">
<folder id="root"
label="root"
type="root">
<folder id="folder1"
label="Folder 1"
type="folder">
<folder id="folder2"
label="Folder 2"
type="folder">
<item id="item1"
label="Item 1"
type="item"/>
<item id="item2"
label="Item 2"
type="item"/>
<item id="item3"
label="Item 3"
type="item"/>
<item id="item4"
label="Item 4"
type="item"/>
<item id="item5"
label="Item 5"
type="item"/>
</folder>
</folder>
<folder id="folder3"
label="Folder 3"
type="folder"/>
<folder id="folder4"
label="Folder 4"
type="folder"/>
<folder id="folder5"
label="Folder 5"
type="folder"/>
</folder>
</fx:XML>
</fx:Declarations>
<mx:Tree id="tree"
left="29"
right="28"
top="28"
bottom="27"
dragEnabled="true"
dropEnabled="true"
dragMoveEnabled="true"
dataProvider="{treeData}"
labelField="#label"
dragEnter="tree_dragEnterHandler(event)"
dragOver="tree_dragOverHandler(event)"
dragDrop="tree_dragDropHandler(event)"
showRoot="false">
</mx:Tree>
</s:WindowedApplication>
It's frustrating that the default drag-and-drop functionality almost provides everything necessary to accomplish this, but not quite. It seems that IlyaZ's answer should work, but that may be a bug in Flex's mx:Tree control.
I ended up accomplishing this by rolling my own drag-and-drop implementation as SunilD alluded to. The code is included below for anyone who may run into the same problem in the future.
Note that there's still a small visual feedback issue when the user is dragging over the boundary between maxDropIndex and maxDropIndex+1: At the lower part of the boundary the drop indicator will shift to indicate that it's possible to drop an item at the folder level. I'm still looking for a good solution to this (can anyone point me to the tree source?).
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="354"
height="480">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.core.DragSource;
import mx.core.IUIComponent;
import mx.core.mx_internal;
import mx.events.DragEvent;
import mx.events.FlexEvent;
import mx.managers.DragManager;
protected var dragging:Boolean = false;
protected var minDropIndex:int = 0;
protected var maxDropIndex:int = 0;
protected function tree_dragEnterHandler(event:DragEvent):void {
// only items can be dropped
if (event.dragSource.hasFormat("tree_item_node")) {
DragManager.acceptDragDrop(IUIComponent(event.currentTarget));
trace("accepting DragDrop");
} else {
event.preventDefault();
DragManager.showFeedback(DragManager.NONE);
trace("rejecting DragDrop");
}
}
protected function tree_dragOverHandler(event:DragEvent):void {
var index:int = tree.calculateDropIndex(event);
if (index < minDropIndex || index > maxDropIndex) {
trace("preventing drop");
DragManager.showFeedback(DragManager.NONE);
this.tree.hideDropFeedback(event);
return;
}
trace("allowing drop");
DragManager.showFeedback(DragManager.MOVE);
this.tree.showDropFeedback(event);
}
protected function tree_dragDropHandler(event:DragEvent):void {
trace("dragDropHandler");
}
protected function tree_mouseMoveHandler(event:MouseEvent):void {
// see if we should start a drag operation
if (event.buttonDown && !dragging && tree.selectedItem && tree.selectedItem.#type == "item") {
// TODO: calculate the min and max drag indices from currently-selected index
minDropIndex = 2;
maxDropIndex = 7;
// start the drag
dragging = true;
var dragSource:DragSource = new DragSource();
dragSource.addData(tree.selectedItem, "tree_item_node");
DragManager.doDrag(IUIComponent(event.currentTarget), dragSource, event);
}
}
protected function tree_dragCompleteHandler(event:DragEvent):void {
trace("dragComplete: no longer dragging");
this.tree.hideDropFeedback(event);
dragging = false;
}
]]>
</fx:Script>
<fx:Declarations>
<fx:XML id="treeData">
<folder id="root"
label="root"
type="root">
<folder id="folder1"
label="Folder 1"
type="folder">
<folder id="folder2"
label="Folder 2"
type="folder">
<item id="item1"
label="Item 1"
type="item"/>
<item id="item2"
label="Item 2"
type="item"/>
<item id="item3"
label="Item 3"
type="item"/>
<item id="item4"
label="Item 4"
type="item"/>
<item id="item5"
label="Item 5"
type="item"/>
</folder>
</folder>
<folder id="folder3"
label="Folder 3"
type="folder"/>
<folder id="folder4"
label="Folder 4"
type="folder"/>
<folder id="folder5"
label="Folder 5"
type="folder"/>
</folder>
</fx:XML>
</fx:Declarations>
<mx:Tree id="tree"
left="29"
right="28"
top="28"
bottom="27"
dragEnabled="false"
dropEnabled="false"
dataProvider="{treeData}"
labelField="#label"
dragEnter="tree_dragEnterHandler(event)"
dragOver="tree_dragOverHandler(event)"
dragDrop="tree_dragDropHandler(event)"
dragComplete="tree_dragCompleteHandler(event)"
mouseMove="tree_mouseMoveHandler(event)"
showRoot="false">
</mx:Tree>
</s:WindowedApplication>

How to show tool tip in mx Datagrid Row in Flex?

I want to know how i show the tool tip of each data grid row or show some specific column's data in tool tip.
If you have a DataGrid and you want to display row specific data on mouseOver, here is how this can be done.
The first step is to enable showDataTips property for every DataGridColumn that you want to enable this functionality on.
Secondly, you need to have a dataTipFunction function on the DataGrid itself. Because dataTipFunction passes over the Grid row data as an Object to the calling function, you dont need to pass any arguments to it. Here is a little example that shows how to do it.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="doInit();">
<mx:Script>
<!![CDATA[
import mx.collections.ArrayCollection; // this holds the grid data
[Bindable]
private var myData:ArrayCollection = new ArrayCollection();
private function doInit():void {
myData.addItem({fname:"Joe",lname:"Bloggs"});
myData.addItem({fname:"Joe1",lname:"Bloggs"});
}
private function buildToolTip(item:Object):String {
var myString:String = "";
if(item != null) {
myString = myString + "Firstname : " + item.fname + "\n";
myString = myString + "Lastname : " + item.lname + "\n";
}
return myString;
}
]]>
</mx:Script>
<mx:DataGrid id="dGrid" dataProvider="{myData}" visible="true" dataTipFunction="buildToolTip">
<mx:columns>
<mx:DataGridColumn dataField="fname" headerText="FirstName" showDataTips="true" />
<mx:DataGridColumn dataField="lname" headerText="LastName" showDataTips="true" />
</mx:columns>
</mx:DataGrid>
</mx:Application>
Source: http://www.anujgakhar.com/2008/01/13/flex-how-to-have-tooltip-on-every-row-of-datagrid/
Here's another explanation from a different source:
I used the itemRollOver and the itemRollOut events.
in the itemRollOver we find the value of the object in the row, we get the label of the object and we set it as the datagrid tooltip.
itemRollOut behaves as a cleaner...
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="white">
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridItemRenderer;
import mx.events.ListEvent;
import mx.controls.ToolTip;
private function createToolTip(event:ListEvent):void {
var str:String = DataGridItemRenderer(event.itemRenderer).data.label;
dataGrid.toolTip = str;
}
private function deleteToolTip(obj:Object):void {
dataGrid.toolTip = null;
}
]]>
</mx:Script>
<mx:ArrayCollection id="arrColl">
<mx:source>
<mx:Array>
<mx:Object label="Student A" score="85" />
<mx:Object label="Student B" score="48" />
<mx:Object label="Student C" score="71" />
<mx:Object label="Student D" score="88" />
<mx:Object label="Student E" score="24" />
<mx:Object label="Student F" score="64" />
</mx:Array>
</mx:source>
</mx:ArrayCollection>
<mx:DataGrid id="dataGrid"
dataProvider="{arrColl}"
itemRollOut="deleteToolTip(event)"
itemRollOver="createToolTip(event)"
>
<mx:columns>
<mx:DataGridColumn dataField="label" />
<mx:DataGridColumn dataField="score" />
</mx:columns>
</mx:DataGrid>
</mx:Application>
Source: http://www.flexdeveloper.eu/forums/mxml/tooltip-on-datagrid-row/
-Hope that helps
Adding to Aarons answer, if you want to ONLY show tooltips when the text is longer than the column width then you can use this code (based on the roll over events example):
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="plain">
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridItemRenderer;
import mx.events.ListEvent;
import mx.controls.ToolTip;
private function createToolTip(event:ListEvent):void {
if (event.itemRenderer.measuredWidth>event.itemRenderer.width) {
var str:String = DataGridItemRenderer(event.itemRenderer).data.label;
dataGrid.toolTip = str;
}
}
private function deleteToolTip(obj:Object):void {
dataGrid.toolTip = null;
}
]]>
</mx:Script>
<mx:ArrayCollection id="arrColl">
<mx:source>
<mx:Array>
<mx:Object label="Student A" score="85" />
<mx:Object label="Student B" score="48" />
<mx:Object label="Student C" score="71" />
<mx:Object label="Student D" score="88" />
<mx:Object label="Student E" score="24" />
<mx:Object label="Student F" score="64" />
</mx:Array>
</mx:source>
</mx:ArrayCollection>
<mx:DataGrid id="dataGrid"
dataProvider="{arrColl}"
itemRollOut="deleteToolTip(event)"
itemRollOver="createToolTip(event)"
>
<mx:columns>
<mx:DataGridColumn dataField="label" />
<mx:DataGridColumn dataField="score" />
</mx:columns>
</mx:DataGrid>
</mx:Application>

ActionScript 3 parsing XML data

My Flash Code
var myLoader:URLLoader = new URLLoader;
var xmlData = new XML();
myLoader.addEventListener(Event.COMPLETE, LoadXML);
myLoader.load(new URLRequest("mydata.xml"));
function LoadXML(e:Event):void
{
xmlData = new XML(e.target.data);
trace(xmlData);
}
My XML Data (mydata.xml)
<xml>
<items>
<item Name="Test" ID="1" />
<item Name="Home" ID="2" />
<item Name="Car" ID="3" />
<item Name="Balloon" ID="4" />
<item Name="Harry" ID="5" />
<item Name="Lion" ID="6" />
</items>
</xml>
How can I get each item in the xml file to be able to then use it in my flash file.
I have tried several things but none seem to work. I am using ActionScript 3.0.
Using E4X you can loop over each item in your XML
for each (var item:XML in xmlData.items.item) {
trace(item.#Name, item.#ID);
}
I changed it to this xmlData..item and it worked. Does anyone know why?
for each (var item:XML in xmlData..item) {
trace(item.#Name, item.#ID);
}