How to make list items as tool tips for combo box items?
import mx.events.ListEvent; import mx.managers.ToolTipManager;
import mx.controls.ToolTip;
public var myTip:ToolTip;
private function fnInit():void
{
cmb.addEventListener(ListEvent.ITEM_ROLL_OVER,fnCreToolTip);
cmb.addEventListener(ListEvent.ITEM_ROLL_OUT,fnCreToolTip);
cmb.addEventListener(ListEvent.CHANGE,fnCreToolTip);
}
private function fnCreToolTip(e:ListEvent):void
{
switch(e.type)
{
case ListEvent.ITEM_ROLL_OVER:
{
//creates a tooltip.
myTip = ToolTipManager.createToolTip(array2[e.rowIndex].tooltip,stage.mouseX+10,stage.mouseY) as ToolTip; // array2 is id of arraylist
break;
}
case ListEvent.ITEM_ROLL_OUT:
{
//destroy the created tooltip, so that we can create a new one for others.
ToolTipManager.destroyToolTip(myTip);
break;
}
case ListEvent.CHANGE:
{
//destroy the created tooltip, so that we can create a new one for others.
ToolTipManager.destroyToolTip(myTip);
break;
}
}
}
In flex 4 create your own item renderer:
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground = "true"
toolTip="{data.description}">
<...>
</s:ItemRenderer>
where description is a property of object you pass to Combobox via addItem().
(e.g. I pass an XML so I do data.#description)
Related
I have a Flex Mobile Project that I am working on. I am trying to pass parameters from one view to another. The only problem is that I cannot use navigator.pushView to push the View and the parameter as the view I am pushing to was the previous view. So this wipes out using the addHandler() and the returnObjectsCreated() as I cannot use pushView. I am having to use popView because it is my previous view that I have to pass parameters too. Any help would be appreciated.
That class that has the parameters I need to pass is below. It is a view that shows a list. So I need to pass list.selectedItem to the popview or previous view...
<?xml version="1.0" encoding="utf-8"?>
<amec:BaseBrowseView xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:amec="com.amec.Components.*"
title="Select an item">
<fx:Script>
<![CDATA[
import com.amec.BaseSql;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import spark.events.IndexChangeEvent;
[Bindable]private var resultArr:ArrayCollection = new ArrayCollection();
protected function myList_changeHandler(event:IndexChangeEvent):void
{
navigator.popView();
//Either send a ref to the last view or override createReturn
}
[Bindable(event="myDataChanged")]
private function get myData():ArrayCollection
{
}
]]>
</fx:Script>
<s:List id="list"
height="100%" width="100%"
dataProvider="{myData}"
labelField="DMV_VALUE_1"
change="myList_changeHandler(event);">
</s:List>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
Now below is the previous view that I want to popView to that I need to pass parameters to so I can populate the TextInput with.
<?xml version="1.0" encoding="utf-8"?>
<amec:BaseControl xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:amec="com.amec.Components.*"
horizontalCenter="true">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Bindable]
protected var textValue:String;
protected function control_creationCompleteHandler(event:FlexEvent):void
{
// todo: get control data from view.data
}
protected function control_clickHandler(event:MouseEvent):void
{
parentView.navigator.pushView(TextListView);
}
]]>
</fx:Script>
<s:Label text="Robert says something meaningful goes here" />
<s:TextInput id="ns" text="{textValue}" editable="false" click="control_clickHandler(event)"/>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
Again I cannot use pushView as the view is already on the stack.
In case you want to do it the right way, on the previous view (the one you want the result going to, add an eventListener for 'add'.
protected function addHandler(event:FlexEvent) : void {
if (navigator.poppedViewReturnedObject != null) {
var returnedObject : Array = navigator.poppedViewReturnedObject.object as Array;
if(!returnedObject) return;
yourData= new ArrayCollection(returnedObject);
}
}
On the view that you are going to pass the object from:
override public function createReturnObject():Object {
var returnedObject : Object = new Object();
returnedObject = dataYouWantToSendBack;
return returnedObject;
}
I looked at using static variables but that was a little messy, I also looked at using Dependency Injection but spending a few hours to set up the framework and get it running is to costly when all I am doing is passing parameters on a popView, so what I came up with is the similar approach I have used when doing Native Android Apps with the Android SDK. A Singleton with getters and setters.
Basically the way I have been able to do this is with the use of a Singleton sharedInstance. See code below:
package com.controls.Text
{
import flash.utils.Dictionary;
[Bindable]
public class ParameterManager
{
private static var instance:ParameterManager = new ParameterManager();
private var dictionary:Dictionary=new Dictionary();
public function ParameterManager( )
{
if (instance != null) { throw new Error('Must use ParameterManager.getInstance().') }
}
public static function getInstance(): ParameterManager {
return instance;
}
public function setParameter(key:*, value:*):void
{
dictionary[key]=value;
}
public function getParameter(key:*):*
{
return dictionary[key];
}
}
}
The method setting the value of the parameter:
protected function myList_changeHandler(event:IndexChangeEvent):void
{
var listViewReturnObject:String = new String();
listViewReturnObject = list.selectedItem.DMV_VALUE_1;
ParameterManager.getInstance().setParameter("selectedItem", listViewReturnObject);
navigator.popView();
}
The method getting the value:
protected function control_creationCompleteHandler(event:FlexEvent):void
{
var listViewReturnObject:Object = new Object();
listViewReturnObject= ParameterManager.getInstance().getParameter("selectedItem");
if (listViewReturnObject != null)
{
dataTxt.text= String(listViewReturnObject);
ParameterManager.getInstance().setParameter("", null); //Make sure objects are cleared when done.
}
}
I have a Flex application that behaves as described below
I want to fix two things
I want to make clear to the user that more info can be shown. Current "Profundidad" is only a label.
The element that is being shown below is not aligned to the one above it, since this is actually another component that is being shown when the state changes
I have tried using Accordion, but when you have a Accordion with a single element, that element is always visible so it can not be collapsed and expanded
What i want is the final result to look as close as posible to this
You can easily achieve this using states. First define two states: 'normal' and 'expanded'
<s:states>
<s:State name="normal"/>
<s:State name="expanded"/>
</s:states>
Then use includeIn or excludeFrom to display components as needed:
<!-- always visible components -->
<s:Label text="FPBAF20F"/>
<s:Label text="N/A"/>
<s:Button label="Profundidad"
click="currentState = currentState == 'expanded' ? 'normal' : 'expanded'"/>
<!-- the compra/venta grid only shown in 'expanded' state -->
<s:DataGrid includeIn="expanded" />
The click handler isn't very pretty, but you get the idea: when you click the Button, the state is toggled from 'normal' to 'expanded' and back when you click again.
That's really all there is to it.
If you prefer an out-of-the-box solution, you're free to use the CollapsiblePanel component I created: https://github.com/RIAstar/CollapsiblePanelFx ;)
Maybe this code will be useful:
MXML file
<?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" minWidth="955" minHeight="600" xmlns:classes="com.classes.*">
<classes:CollapsiblePanel id="cp" title="Profundidad (Click me)" open="false">
<mx:DataGrid>
<mx:ArrayList>
<fx:Object Cantidad="" Precio=""/>
</mx:ArrayList>
</mx:DataGrid>
</classes:CollapsiblePanel>
</s:Application>
CollapsiblePanel.as. Note that in my case, this class is in com.classes package, you can put this in the place as you want.
package com.classes {
import flash.events.*;
import mx.effects.AnimateProperty;
import mx.events.*;
import mx.containers.Panel;
import mx.core.ScrollPolicy;
[Style(name="closedIcon", property="closedIcon", type="Object")]
[Style(name="openIcon", property="openIcon", type="Object")]
public class CollapsiblePanel extends Panel {
private var _creationComplete:Boolean = false;
private var _open:Boolean = true;
private var _openAnim:AnimateProperty;
public function CollapsiblePanel(aOpen:Boolean = true):void
{
super();
open = aOpen;
this.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
}
private function creationCompleteHandler(event:FlexEvent):void
{
this.horizontalScrollPolicy = ScrollPolicy.OFF;
this.verticalScrollPolicy = ScrollPolicy.OFF;
_openAnim = new AnimateProperty(this);
_openAnim.duration = 300;
_openAnim.property = "height";
titleBar.addEventListener(MouseEvent.CLICK, headerClickHandler);
_creationComplete = true;
}
private function headerClickHandler(event:MouseEvent):void { toggleOpen(); }
private function callUpdateOpenOnCreationComplete(event:FlexEvent):void { updateOpen(); }
private function updateOpen():void
{
if (!_open) height = closedHeight;
else height = openHeight;
setTitleIcon();
}
private function get openHeight():Number {
return measuredHeight;
}
private function get closedHeight():Number {
var hh:Number = getStyle("headerHeight");
if (hh <= 0 || isNaN(hh)) hh = titleBar.height;
return hh;
}
private function setTitleIcon():void
{
if (!_open) this.titleIcon = getStyle("closedIcon");
else this.titleIcon = getStyle("openIcon");
}
public function toggleOpen():void
{
if (_creationComplete && !_openAnim.isPlaying) {
_openAnim.fromValue = _openAnim.target.height;
if (!_open) {
_openAnim.toValue = openHeight;
_open = true;
dispatchEvent(new Event(Event.OPEN));
}else{
_openAnim.toValue = _openAnim.target.closedHeight;
_open = false;
dispatchEvent(new Event(Event.CLOSE));
}
setTitleIcon();
_openAnim.play();
}
}
public function get open():Boolean {
return _open;
}
public function set open(aValue:Boolean):void {
_open = aValue;
if (_creationComplete) updateOpen();
else this.addEventListener(FlexEvent.CREATION_COMPLETE, callUpdateOpenOnCreationComplete, false, 0, true);
}
override public function invalidateSize():void {
super.invalidateSize();
if (_creationComplete)
if (_open && !_openAnim.isPlaying) this.height = openHeight;
}
}
}
Yon can see this SWF in action here.
The source code of this collapsible panel is here.
I hope this will be help you.
I would like to programmatically change a selected item, in a tree or list, to the item currently "marked/focused" under the mouse pointer .
I'm working with an Flex Air standalone application.
I was thinking in the lines of:
myTree.selectedItem = EVENT.TARGET (where EVENT could be a mouseover/rightclick/rollOver event, and TARGET should be the node/item currently under the mouse pointer).
Is there a way of doing this (or in any other way)?
Ahh, and i want to do it without left clicking ;-)
Thank you in advance,
Sebastian
I found this interesting enough so I am asking if this is the easiest way to achieve this. First off, instead of the list, you need to add the rollOver-listener to the ItemRenderer, not to the list itself (as the event.target and event.currentTarget will just show your list).
So lets create a custom ItemRenderer and add a rollOver listener
<xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true" height="20" rollOver="itemrenderer1_rollOverHandler(event)">
<fx:Script>
<![CDATA[
protected function itemrenderer1_rollOverHandler(event:MouseEvent):void
{
this.dispatchEvent(new CustomEvent(CustomEvent.SELECT_ITEM, data, true));
}
]]>
<s:Label id="label1" text="{data.label}"/>
</s:ItemRenderer>
You need to somehow get the value of the selected item (which is the data on the itemRenderer) so I created a CustomEvent-class just to do so.
package
{
import flash.events.Event;
public class CustomEvent extends Event
{
public var selectedItem:Object;
public static const SELECT_ITEM:String = "selectItem";
public function CustomEvent(type:String, selectedItem:Object, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this.selectedItem = selectedItem;
}
}
}
then I added a eventListener to the main class and set the list.selectedItem property accordingly:
//for the main MXML initializer:
this.addEventListener(CustomEvent.SELECT_ITEM, rollOverChangeSelected);
//and the function:
protected function rollOverChangeSelected(ce:CustomEvent):void{
list.selectedItem = ce.selectedItem;
}
Another way: bindable variable
The list:
s:List id="list" allowMultipleSelection="true" selectionColor="red" rollOverColor="red" itemRenderer="customItemRenderer" selectedItem="{_rollOverSelectedItem}">
The variable and set / get methods:
[Bindable] public var _rollOverSelectedItem:Object;
public function get rollOverSelectedItem():Object
{
return _rollOverSelectedItem;
}
public function set rollOverSelectedItem(value:Object):void
{
_rollOverSelectedItem = value;
}
and the ItemRenderer's rollOver-method:
protected function itemrenderer1_rollOverHandler(event:MouseEvent):void
{
this.parentApplication.rollOverSelectedItem = data;
}
What is the best/proper way?
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...
I need a control in Flex 3 that is like NumericStepper, but that can display arbitrary strings. Does this control exist? If not, what are your suggestions for creating it, or references you would recommend?
For convenience, I'm calling this a TextStepper. I want this as a compact way to display a list of string choices that a user can cycle through by clicking the up/down buttons. Compact means no drop-down or pop-up aspects of the control: the only way to change the selected index is to click the up/down button (which updates the text input value). Value cycling means that I really want to treat the underlying dataProvider as a circular buffer. So up/down clicks modify selectedIndex in modulo fashion.
The idea is to use valueFormatFunction:
<?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" minWidth="955" minHeight="600" xmlns:local="*">
<local:StringStepper horizontalCenter="0" verticalCenter="0" width="200">
<local:dataProvider>
<s:ArrayCollection>
<fx:String>Hello!</fx:String>
<fx:String>I love you.</fx:String>
<fx:String>Won't you tell me your name?</fx:String>
</s:ArrayCollection>
</local:dataProvider>
</local:StringStepper>
</s:Application>
Source for StringStepper:
package
{
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
import spark.components.NumericStepper;
public class StringStepper extends NumericStepper
{
public function StringStepper()
{
enabled = false;
valueFormatFunction = defaultValueFormatFunction;
valueParseFunction = defaultValueParseFunction;
}
private var _dataProvider:ArrayCollection;
public function get dataProvider():ArrayCollection
{
return _dataProvider;
}
public function set dataProvider(value:ArrayCollection):void
{
if (_dataProvider == value)
return;
if (_dataProvider)
_dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
dataProvider_collectionChangeHandler);
_dataProvider = value;
commitDataProvider();
if (_dataProvider)
_dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE,
dataProvider_collectionChangeHandler);
}
/**
* Same event as for <code>value</code>.
*/
[Bindable("valueCommit")]
public function get selectedItem():Object
{
return _dataProvider && value <= _dataProvider.length - 1 ? _dataProvider[value] : null;
}
public function set selectedItem(value:Object):void
{
if (!_dataProvider)
return;
value = _dataProvider.getItemIndex(value);
}
private function defaultValueFormatFunction(value:Number):String
{
return _dataProvider && value <= _dataProvider.length - 1 ? _dataProvider[value] : String(value);
}
private function defaultValueParseFunction(value:String):Number
{
if (!_dataProvider)
return 0;
var n:int = _dataProvider.length;
for (var i:int = 0; i < n; i++)
{
var string:String = _dataProvider[i];
if (string == value)
return i;
}
return 0;
}
private function commitDataProvider():void
{
if (!_dataProvider)
{
minimum = 0;
maximum = 0;
enabled = false;
return;
}
enabled = true;
minimum = 0;
maximum = _dataProvider.length - 1;
}
private function dataProvider_collectionChangeHandler(event:CollectionEvent):void
{
commitDataProvider();
}
}
}
I created one of these (as an MXML comoponent) by overlaying a TextInput over a NumericStepper (absolutely positioned) so that the TextInput covered the input portion of the NumericStepper.
The dataProvider was an ArrayCollection of strings, and the value of the NumericStepper was used to access an index in the ArrayCollection.
The change event of the NumericStepper changed the text of the TextInput to whatever was at index n of the dataProvider. I gave the component an editable property, which set the TextInput to editable and inserted the new string into the dataProvider at the current index.