flex spark buttonbar : how to determine which button in mouseOver event - apache-flex

re: spark.components.ButtonBar
In the spark ButtonBar's mouseOver event, how do you determine which of the several buttons the mouse is hovering over? There is, of course, no selected index at this juncture. If it makes a difference, my ButtonBar is not defined in MXML but is instantiated in ActionScript and an ArrayList is assigned to the dataProvider property of my ButtonBar instance.
Thanks for the help.

There's no real easy/built-in way to do this if Flex 4, and I think that's a good thing. Instead, they give you access to the renderers via ElementExistenceEvent.RENDERER_ADD and ElementExistenceEvent.RENDERER_REMOVE, so you can look for all kinds of events on the children. Try this out:
<?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">
<fx:Script>
<![CDATA[
import mx.core.IVisualElement;
import spark.events.RendererExistenceEvent;
protected function rendererAddHandler(event:RendererExistenceEvent):void
{
var element:IVisualElement = event.renderer;
element.addEventListener(MouseEvent.MOUSE_MOVE, renderer_mouseMoveHandler);
}
protected function rendererRemoveHandler(event:RendererExistenceEvent):void
{
var element:IVisualElement = event.renderer;
element.removeEventListener(MouseEvent.MOUSE_MOVE, renderer_mouseMoveHandler);
}
protected function renderer_mouseMoveHandler(event:MouseEvent):void
{
trace(event.currentTarget.label);
}
]]>
</fx:Script>
<s:ButtonBar id="buttonBar"
rendererAdd="rendererAddHandler(event)"
rendererRemove="rendererRemoveHandler(event)">
<s:dataProvider>
<mx:ArrayList source="[one, two, three, four]"/>
</s:dataProvider>
</s:ButtonBar>
</s:Application>
Hope that helps,
Lance

You can simply use the itemRollOver event of the spark buttonbar.

Related

Flex Spark RadioButton Deselected Event?

Is there a way to listen for this? I can easily listen for click which selects a RadioButton, but I can't seem to find a way to listen for when the RadioButton has been deselected.
Any ideas?
Thanks!
Back in the Flex 2 days, the "change" event triggered when a radio button was deselected. However, this little convenience disappeared in Flex 3, for some reason, and I don't believe that we were provided with any sort of replacement event.
Handling your events at the RadioButtonGroup level is all fine and well, except that there are times when you really want to handle the events on the radio button level -- particularly if you were hoping to interact with a data provider entry via an itemRenderer that is drawing the radio button.
Conveniently, I have a little bit of boilerplate code you can use as drop-in replacements for RadioButton and RadioButtonGroup that provide a "unselect" event at the radio button level. Here is the SmartRadioButton, first of all:
<?xml version="1.0" encoding="utf-8"?>
<s:RadioButton xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import events.SmartRadioButtonEvent;
public function notifyDeselect():void {
dispatchEvent(new SmartRadioButtonEvent('deselect'));
}
]]>
</fx:Script>
<fx:Metadata>
[Event(name="deselect", type="events.SmartRadioButtonEvent")]
</fx:Metadata>
</s:RadioButton>
And here is the SmartRadioButtonGroup:
<?xml version="1.0" encoding="utf-8"?>
<s:RadioButtonGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
change="selectionChanged();"
>
<fx:Script>
<![CDATA[
import spark.components.RadioButton;
import components.SmartRadioButton;
protected var oldSelection:SmartRadioButton = null;
// Notify our old selection that it has been deselected, and update
// the reference to the new selection.
public function selectionChanged():void {
var newSelection:SmartRadioButton = this.selection as SmartRadioButton;
if (oldSelection == newSelection) return;
if (oldSelection != null) {
oldSelection.notifyDeselect();
}
oldSelection = newSelection;
}
// Override some properties to make sure that we update oldSelection correctly,
// in the event of a programmatic selection change.
override public function set selectedValue(value:Object):void {
super.selectedValue = value;
oldSelection = super.selection as SmartRadioButton;
}
override public function set selection(value:RadioButton):void {
super.selection = value;
oldSelection = super.selection as SmartRadioButton;
}
]]>
</fx:Script>
</s:RadioButtonGroup>
The two property overrides are in there to make sure that we correctly update the oldSelection, in the event of a programmatic change to the group's selection.
SmartRadioButtonEvent isn't anything fancy or important. It could probably just be a plain Event, since there isn't a special payload.
I have tested the above code, and it all works, but there are surely edge conditions, and other oddities that should be addressed, if it's used in a larger system.

Get variable from ItemRenderer to Main Application

I have a List with TextInput as item renderer. I want to get the value entered in the TextInput (form the TextInputItemRenderer) and pass it the main application to do some checks(upon tapping enter on the textInput -- see code below).
I know that we can do it thru dispatching event but I still don't understand how to pass a variable from the ItemRenderer to the main app.
Help Pls.
Thanks
<?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" xmlns:components="components.*" width="100%"
>
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
override public function set data( value:Object ) : void {
super.data = value;
}
protected function myTextInput_enterHandler(event:FlexEvent):void
{
trace(myTextInput.text);
What Next??
}
]]>
</fx:Script>
<components:ClearableTextInput text="{data.label}" id="myTextInput" enter="myTextInput_enterHandler(event)"/>
</s:ItemRenderer>
i'm not sure if I got your question correctly but would this help?
http://www.ajibanda.blogspot.com/2011/02/changing-currentstate-of-main-and.html
Instead of trying to access from MainApp to itemRenderer, i think you can do backward. Follow one of two solutions below:
In itemRenderer, assign value you want to check later to a public global variable on the MainApp. The limitation is you then only enable to check it on MainApp, not any where esle (other itemRenderer, component, module etc.)
Use EvenBus to put the value to a global container. Create a static eventBus instance in AppUtils, for example. In itemRenderer, AppUtils.eventBus.dispatch() an event with the value attached to it each time the value changed. And then use AppUtils.eventBus again to addEventListener() to retrieve the value and check wherever you want. Google AS3Commons for EventBus.

in Flex DropDownList, is there a way to bind to a property of an item in dataProvider?

I have following code.
<s:DropDownList dataProvider={_dataProvider}/>
<fx:Script>
private var _dataProvider:ArrayCollection = new ArrayCollection([{label:"one", data:1}, {label:"two", data:2}]);
</fx:Script>
I want to bind the data property of the selectedItem in the DropDownList. Is there a way to do this?
Not sure if this another approach to the question... but I created a custom dropdownlist and binded the selectedItem to incoming changes. When the value of my desired data changes it will trigger the dropdownlist to change its selection.
DropDownListBindable.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:DropDownList xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
[Bindable] public var valueField:String = "";
override public function set selectedItem(value:*):void{
try{
for(var i:uint=0;i<this.dataProvider.length;i++){
if(this.dataProvider[i][this.valueField]==value){
this.selectedIndex=i;
break;
}else{
this.selectedIndex=-1;
}
}
}catch(e:Error){}
}
]]>
</fx:Script>
</s:DropDownList>
On the application I import the custom dropdownlist and bind the valuefield with whatever needs to be binded... in your case its 'data'. I also created an object called 'mydata' for the dropdownlist to listen to for changes. When mydata changes the list will too. I've added a button to demonstrate how the list changes.
main.mxml
<?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"
xmlns:components="com.components.*">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable] private var myData:Object = new Object();
[Bindable] private var _dataProvider:ArrayCollection = new ArrayCollection([{label:"one", data:1}, {label:"two", data:2}]);
]]>
</fx:Script>
<s:HGroup>
<components:DropDownListBindable
dataProvider="{_dataProvider}"
prompt="--select one--"
selectedItem="{this.myData}"
id="ddl"
valueField="data"
labelField="label"/>
<s:Button label="change datafield" click="this.myData=1"/>
</s:HGroup>
</s:Application>
I'm pretty sure the answer is no, but just to be clear; I'm confused.
If your dataProvider contains objects like this:
{label:"one", data:1}
First off, this syntax will create a generic object with no customization. If none of the properties on that object are explicitly defined, none of them can implement the Bindable metadata tag, and therefore when used as the source for data binding, the target will never update.
Second off, even if you created your own non-generic object with properties being bindable, binding doesn't usually go multiple levels deep into an object's properties of an array.
The selectedItem will point to an object like are in your _dataProvider, or possibly null, based on user interaction with the dropDownList. Binding the selectedItem to a property inside the item doesn't make sense; because you'd be comparing an literal to an object and nothing would ever be selected.
I'm unclear, without looking, what happens in the DropDownList when you try to set selectedItem to an item not in your dataProvider. I imagine it resets the selection, though.
If you can expand on what exactly you're trying to accomplish we may be able to help more.
<s:DropDownList id="ddl" dataProvider="{_dataProvider}"/>
<s:Label text="{ddl.selectedItem.data.toString()}"/>
Yes. You can do this. It is quite simple, actually. I do it all the time:
<s:DropDownList dataProvider="{_dataProvider}" selectedItem="#{_selectedItem}" />
With ActionScript that looks like this:
private var _dataProvider:ArrayCollection = new ArrayCollection([{label:"one", data:1}, {label:"two", data:2}]);
[Bindable] private var _selectedItem;
Every time the user selects an item in the drop down list, the _selectedItem will get set.

how to show a tooltip on a disabled control?

I'm displaying a list of buttons, some of which might be disabled. I need to show a tooltip on the disabled buttons with an explanation of why it's disabled, but it seems I can't disable the button without disabling the tooltip. Is there a simple way around this?
Wrap the Button in a Group, and apply the toolTip to the group instead.
<s:Group toolTip="My toolTip">
<s:Button enabled="false"/>
</s:Group>
It's a bit ugly, but it works.
One way to do this is to override the enabled getter and setter to do what you want. So in my case, I still wanted most mouse events to fire, just not the click event.
<?xml version="1.0" encoding="utf-8"?>
<s:Button buttonMode="true" click="handleClick(event)" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
public var data:Object;
private var _enabled:Boolean = true;
public override function get enabled():Boolean
{
return _enabled;
}
public override function set enabled(value:Boolean):void
{
_enabled = value;
invalidateDisplayList();
dispatchEvent(new Event("enabledChanged"));
invalidateSkinState();
}
protected function handleClick(event:MouseEvent):void
{
if (!_enabled)
{
event.stopPropagation();
}
}
]]>
</fx:Script>
</s:Button>
Since mouse events now fire, the tooltips work again.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.managers.ToolTipManager;
import mx.controls.ToolTip;
private var tooltip:ToolTip;
private var p:Point;
private function whyDisable():void
{
//calculate the button position , so that roll over shows the tooltip
p=new Point();
p=localToGlobal(new Point(btn.x,btn.y));
if(btn.enabled==false)
tooltip = ToolTipManager.createToolTip('Button is disabled',p.x+(btn.width/2),p.y-20,'errorTipAbove') as ToolTip;
else
tooltip=ToolTipManager.createToolTip('Button is enabled',p.x+(btn.width/2),p.y-20,'errorTipAbove') as ToolTip;
}
]]>
</mx:Script>
<mx:VBox height="100%" width="100%" horizontalAlign="center" verticalAlign="middle">
<mx:Button id="btn" label="Show Tooltip" buttonDown="trace('ankur')" autoRepeat="true" enabled="true" rollOver="whyDisable();" rollOut="{ToolTipManager.destroyToolTip(tooltip);}"/>
</mx:VBox>
</mx:Application>
Hi, this application works on the disabled button,I used ToolTipManager to do this,
i hope this works for you
have a gr8 time
Ankur Sharma
The best choice for me was to put a void label around and in front of the element. Then, if necessary, I set the element to disable and the tooltip works in the label. If not, I put sent the label to back. It works pretty well.
if (new MainListsAdmin(this.mainApp).temInvestimentoComAqueleTipo(t)) {
deletarGroupInto.setTooltip(new Tooltip("Há investimentos vinculados a Tipo de Investimento.\nDeleção bloqueada."));
this.deletarButton.setDisable(true);
}else{
deletarGroupInto.toBack();
}
You will need to use the ToolTipManager class to create and destroy the tool tips manually.
This article should give you all the info you need to accomplish this:
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf60d65-7ff6.html

change button appearance on click

I wahnt to change button appearance when it was clicked.
<?xml version="1.0" encoding="utf-8"?>
<s:Button xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="init()">
<fx:Script>
<![CDATA[
public var _clicked:Boolean = false;
public function init():void{
addEventListener(MouseEvent.CLICK, changeButtonClickStatus);
}
public function changeButtonClickStatus(event:MouseEvent):void{
var that:TopMenuButton = event.currentTarget as TopMenuButton;
that._clicked = !(that._clicked);
if(that._clicked == true){
//change button appearance
}else{
//change button appearance
}
}
]]>
</fx:Script>
</s:Button>
Is there a method using states? I could then use the skin convention.
Thanks in advance for Your help.
If you are looking for a ToggleButton that you can skin the different states of then it already exists in Flex 4.
Check out the source code for ToggleButtonSkin.mxml to see how to skin the different states.
Have a look on the following example:
Applying styles to different states on a Spark Button control in Flex 4

Resources