dropdown following moving calloutbutton - apache-flex

Flex Actionscript question.
I have a calloutbutton that is moving on the screen.
When I open the dropdown (by a click) it stays at the same position on the screen (only the arrow is moving). It does not follow the calloutbutton's position
I would like this dropdown to follow the position of the calloutbutton when it has moved (as it does when one clicks on the button again when it has moved).
I have tried to dispatch a MouseEvent.CLICK. It does not work.
Tried also to open, then close again dropdown with actionscript sing closeDropDown() and openDropDown(). No change.
Thanks
Sample code (call init() from creationComplete) :
creationComplete="init();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import flash.events.MouseEvent;
import mx.events.DropdownEvent;
private function init():void {
var minuteTimer:Timer = new Timer(1*1000);
minuteTimer.addEventListener(TimerEvent.TIMER, updateCalloutPosition);
// starts the timer ticking
minuteTimer.start();
}
private function updateCalloutPosition(event:Event):void {
myButton.closeDropDown();
myButton.x = this.width * Math.random();
myButton.y = this.height * Math.random();
// myButton.openDropDown();
myButton.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
protected function myButton_clickHandler(event:MouseEvent):void
{
if (myButton.isPopUp) {
myButton.closeDropDown();
}
else {
myButton.openDropDown();
}
}
]]>
</fx:Script>
<s:CalloutButton id="myButton" click="myButton_clickHandler(event)">
</s:CalloutButton>

I tried some workaround but openDuration and closeDuration is not working for DropDownList if it can be achieved than following code may help you. Hope following code may help you.
<?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"
creationComplete="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<s:ArrayCollection id="ac">
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
<fx:String>AR</fx:String>
</s:ArrayCollection>
</fx:Declarations>
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/halo";
s|DropDownList {
openDuration: 0;
closeDuration: 0;
}
</fx:Style>
<fx:Script>
<![CDATA[
import flash.events.MouseEvent;
import spark.components.supportClasses.DropDownListBase;
import spark.components.supportClasses.TextBase;
import spark.events.DropDownEvent;
import spark.skins.spark.DropDownListSkin;
import spark.utils.LabelUtil;
private var storeVisible:Boolean = false;
private function init():void {
var minuteTimer:Timer = new Timer(1*1000);
minuteTimer.addEventListener(TimerEvent.TIMER, updateCalloutPosition);
minuteTimer.start();
}
private function updateCalloutPosition(event:Event = null):void {
myButton.x = this.width * Math.random();
myButton.y = this.height * Math.random();
if(myButton.isDropDownOpen)
{
myButton.closeDropDown(false);
storeVisible = true;
}
}
private function updateComp():void
{
if(storeVisible)
{
myButton.openDropDown();
storeVisible = false;
}
}
]]>
</fx:Script>
<s:DropDownList id="myButton" selectedIndex="0" dataProvider="{ac}" updateComplete="updateComp()"/>
</s:Application>

Related

How do you place the Flex Alert box in a certain x,y position?

How do you place the Flex Alert box in a certain x,y position, the following code does not work, the Alert box is always centered in the screen.
<?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.controls.Alert;
protected function showAlert(event:MouseEvent):void
{
myAlert = Alert.show('alert', 'Error - ');
myAlert.x = 40;
myAlert.y = 50;
// myAlert.move(-400,-500); // doesn't work either
}
private var myAlert:Alert;
]]>
</fx:Script>
<s:Button label="click me" click="showAlert(event)" />
</s:Application>
Calling the centerPopUp function of the PopUpManager before setting the x & y co-ordinates will allow you to change the position of the Alert window. I've updated the script that you provided so that it does position the Alert window appropriately:
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.managers.PopUpManager;
private var myAlert:Alert;
protected function showAlert(event:MouseEvent):void
{
myAlert = Alert.show('alert', 'Error - ');
PopUpManager.centerPopUp(myAlert);
myAlert.x = 40;
myAlert.y = 50;
}
]]>
</fx:Script>

Flex 4 Itemrenderer for List

I just started working with Flex. I know it's pathetic but it's a long story.
Now, the problem I am facing is that I have a list component which has a dataprovider on it. What I would like to do is when an item on the list is clicked I would like to have a check sign right next to the label.
Below is the component:
<s:List id="tabList" width="100%"
borderVisible="false" click="tabList_clickHandler(event)"
selectedIndex="{this.hostComponent.selectedIndex}"
itemRenderer="MultiTabListRenderer" />
Below is the Itemrenderer code:
protected function AddCheck_clickHandler(event:MouseEvent):void {
// TODO Auto-generated method stub
var checkLabel:Label;
checkLabel = new Label();
checkLabel.text = "checkMark";
var e: ItemClickEvent = new ItemClickEvent(ItemClickEvent.ITEM_CLICK, true);
e.item = data;
e.index = itemIndex;
dispatchEvent(e);
this.checkRectGroup.addElementAt(checkLabel, e.index);
}
<s:Label id="customMultitabList" text="{data.label}"
left="10" right="0" top="6" bottom="6" click="AddCheck_clickHandler(event)"/>
My code inside the function is wrong which is mainly due to the fact that I do not understand each and everything in flex. I am not in a mood to learn the language in detail because it's not a long term work for me. Also, in the renderer file when I use s:List instead of s:label I do not see the labels anymore. Of course I replace the attribute text with dataprovider={data.selectedItem}.
One way to approach this is to add a field to the objects in your dataProvider that tracks whether or not the item has been selected.
Then, in your item renderer, you inspect this field and decide whether or not to display the checkmark. Here's a working example app and renderer:
Application:
<?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="*"
creationComplete="application1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
import mx.events.FlexEvent;
import mx.events.PropertyChangeEvent;
import mx.events.PropertyChangeEventKind;
private var collection:ArrayCollection;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
collection = new ArrayCollection([
{ label: 1, selected: false },
{ label: 2, selected: false },
{ label: 3, selected: false }]);
listbert.dataProvider=collection;
}
protected function listbert_clickHandler(event:MouseEvent):void
{
var index:int = listbert.selectedIndex;
var item:Object = listbert.selectedItem;
item.selected = !item.selected;
// Create these events because the items in the ArrayCollection
// are generic objects. It shouldn't be necessary if items in
// your collection are a Class that extends EventDispatcher
// see ArrayList::startTrackUpdates()
var e:PropertyChangeEvent = new PropertyChangeEvent(
PropertyChangeEvent.PROPERTY_CHANGE, false,false,
PropertyChangeEventKind.UPDATE, 'selected', !item.selected,
item.selected, item);
collection.dispatchEvent(new CollectionEvent(
CollectionEvent.COLLECTION_CHANGE, false,false,
CollectionEventKind.UPDATE, index, index, [e]));
}
]]>
</fx:Script>
<s:List id="listbert" click="listbert_clickHandler(event)" itemRenderer="TestRenderer"/>
</s:Application>
Item Renderer:
<?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" >
<fx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
labelDisplay.text = value.label;
if (value.selected)
checkMarkLabel.text = "✓";
else
checkMarkLabel.text = "";
}
]]>
</fx:Script>
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<s:Label id="labelDisplay" />
<s:Label id="checkMarkLabel" />
</s:ItemRenderer>

Display an alert which cannot be closed by user, closes automatically on event

I have a Flex application which sends a query to a database when an user clicks a button. Since the query might be heavy, and can take up to a minute, I want to display an alert, which will close only after an event comes back from the database (user won't be able to close it himself). Is it possible in Flex? How do I do that?
I have functions sendQuery() and dataEventHandler(). I think I need to put code in sendQuery() to display the alert and in dataEventHandler() to close it after data comes from the DB, but how do I make the alert "unclosable" by the user?
The built in Flex Alert class will always have some type of close button.
However, there is no reason you can't create your own component; and then open and close it using the PopUpManager.
Following code may help you… (One of the solution...)
You can find I have made Solution 1 and Solution 2… You can use any one of it and third solution is to create your own Custom Component.
Please find below code…. You can use below logic to solve your problem..
Use Timer to check if data received or you can dispatch custom event and call updateAlertPosition function.
Hope it may help: -
<?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"
>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.managers.PopUpManager;
private var minuteTimer:Timer;
private var alert:Alert;
private var displayInitialText:String = "Data Not Received, Please wait....";
private var displayDataReveivedText:String = "Data Received...";
private function timerInit():void
{
//Logic to check if data Received.
minuteTimer = new Timer(3000);
minuteTimer.addEventListener(TimerEvent.TIMER, updateAlertPosition);
minuteTimer.start();
}
private function updateAlertPosition(event:Event = null):void {
minuteTimer.stop();
//Solution 1
//add your flag here if y you want to check if data is received or not
//if(Data Received)
alert.mx_internal::alertForm.mx_internal::buttons[0].enabled = true;
alert.mx_internal::alertForm.mx_internal::buttons[1].enabled = true;
alert.mx_internal::alertForm.mx_internal::textField.text = displayDataReveivedText;
//Solution 2
//alert.enabled = true;
//If you want to remove it automatically
//closeAutomatically();
}
private function closeAutomatically():void
{
PopUpManager.removePopUp(alert);
}
private function clickHandler():void
{
//Start Timer
timerInit();
//Solution 1
alert = Alert.show(displayInitialText, "Alert", Alert.OK|Alert.CANCEL,this,alertCloseHandler);
alert.mx_internal::alertForm.mx_internal::buttons[0].enabled = false;
alert.mx_internal::alertForm.mx_internal::buttons[1].enabled = false;
//Solution 2
//alert.enabled = false;
}
private function alertCloseHandler(event:CloseEvent):void
{
if(event.detail == Alert.CANCEL)
{
//Some Code on close
}
else
{
//Some Code on OK
}
}
]]>
</fx:Script>
<s:Button label="Show Alert" x="100" y="100" click="clickHandler()"/>
</s:Application>
make a 0-0.2 alpha shape what covers the whole application (probably you'll want to listen for resizeevents), and add a custom panel to the middle of it, with the message.
As an idea you can create a custom alert then:
Show Alert
Disable Application.
Hide Alert.
Enable Application.
An alert example:
<?xml version="1.0" encoding="utf-8"?>
<s:Group 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="400" height="300"
creationComplete="onCreationComplete(event)">
<s:Rect>
<s:fill>
<s:SolidColor color="0xFFFFFF"/>
</s:fill>
<s:stroke>
<s:SolidColorStroke />
</s:stroke>
</s:Rect>
<s:Label text="Please Wait..."/>
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
public static function show():void
{
PopUpManager.createPopUp(FlexGlobals.topLevelApplication);
}
public static function hide():void
{
PopUpManager.removePopUp(this);
FlexGlobals.topLevelApplication.enabled = true;
}
protected function onCreationComplete(event:FlexEvent):void
{
PopUpManager.centerPopUp(this);
FlexGlobals.topLevelApplication.enabled = false;
}
]]>
</fx:Script>
</s:Group>
Usage:
YourAlert.show();
YourAlert.hide();
#Alex, I used your code but modify it a bit, because there was some errors:
<?xml version="1.0" encoding="utf-8"?>
<s:Group 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="creationCompleteHandler()" width="100%" height="100%">
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import mx.core.UIComponent;
import mx.managers.PopUpManager;
///////////////////////////////////////
//// public functions - my group is ImageViewer.mxml component
public static function show():ImageViewer {
return PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, ImageViewer) as ImageViewer;
}
public function hide():void {
PopUpManager.removePopUp(this);
FlexGlobals.topLevelApplication.enabled = true;
}
////////////////////////////
//// component events
private function creationCompleteHandler():void {
PopUpManager.centerPopUp(this);
FlexGlobals.topLevelApplication.enabled = false;
}
]]>
</fx:Script>
</s:Group>
And call it like:
var imageviewer:ImageViewer = ImageViewer.show();
//imageviewer.imageURL = _value_dto.value;

Air Application - Start in system tray?

I'd be extremely grateful if somebody could help me, or point me in the right direction.
I've been trying to get an adobe air application start in system tray, so far I've used this snippet: http://www.swamicharan.com/blog/air/minimizing-an-air-app-to-systemtray/ which works as described, however no matter what I do I can't seem to make it start, minimized, in the system tray. This is the code I have so far:
<?xml version="1.0" encoding="utf-8"?>
<mx: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="300" height="100" creationComplete="initApp()" layout="horizontal">
<fx:Script>
<![CDATA[
import mx.events.CloseEvent;
private var trayIcon:BitmapData;
public function initApp():void{
loadTrayIcon();
this.addEventListener(Event.CLOSING, minToTray);
}
public function loadTrayIcon():void{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, readyToTray);
loader.load(new URLRequest("assets/icon.PNG"));
}
private function minToTray(event:Event):void{
event.preventDefault();
dock();
}
public function readyToTray(event:Event):void{
trayIcon = event.target.content.bitmapData;
var myMenu:NativeMenu = new NativeMenu();
var openItem:NativeMenuItem = new NativeMenuItem("Options");
var closeItem:NativeMenuItem = new NativeMenuItem("Close");
openItem.addEventListener(Event.SELECT, unDock);
closeItem.addEventListener(Event.SELECT, closeApp);
myMenu.addItem(openItem);
myMenu.addItem(new NativeMenuItem("", true));
myMenu.addItem(closeItem);
if(NativeApplication.supportsSystemTrayIcon){
SystemTrayIcon(NativeApplication.nativeApplication.icon).tooltip = "Notifier";
SystemTrayIcon(NativeApplication.nativeApplication.icon).
addEventListener(MouseEvent.CLICK, unDock);
stage.nativeWindow.addEventListener(
NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING, winMinimized);
SystemTrayIcon(NativeApplication.nativeApplication.icon).menu = myMenu;
}
}
private function winMinimized(displayStateEvent:NativeWindowDisplayStateEvent):void{
if(displayStateEvent.afterDisplayState == NativeWindowDisplayState.MINIMIZED){
displayStateEvent.preventDefault();
dock();
}
}
public function dock():void{
stage.nativeWindow.visible = false;
NativeApplication.nativeApplication.icon.bitmaps = [trayIcon];
}
public function unDock(event:Event):void{
stage.nativeWindow.visible = true;
stage.nativeWindow.orderToFront();
NativeApplication.nativeApplication.icon.bitmaps = [];
}
private function closeApp(event:Event):void{
stage.nativeWindow.close();
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
s|WindowedApplication
{
skinClass:ClassReference("spark.skins.spark.SparkChromeWindowedApplicationSkin");
background-color:#999999;
background-alpha:"0.7";
}
</fx:Style>
<s:Label text="Hello AIR"/>
</mx:WindowedApplication>
Many Thanks.
I think you'll manage by calling dock() at the end of readyToTray(event:Event).
To make sure your initialWindow is invisible when it launches you can set it's visible property to false in the application descriptor file.

Flex / ActionScript3 - Object Attribute / Variable null

If I execute the code below in FlashBuilder, I get the following error (I translate it)
TypeError: Error #1009: Access to an Attribute or Method of an null-Object is not possible.
at components::NumDisplay()[\src\components\NumDisplay.mxml:39]
This line in NumDisplay.mxml is the problem:
[Bindable]
public var oneled_top:OneDisplay = new OneDisplay(numberData.led_top);
If i change it from the above to:
[Bindable]
public var oneled_top:OneDisplay = new OneDisplay(1);
It is working, because I send a real Number.
So how can I access the value from numberData.led_top?
If I test the access in the samefile NumDisplay.mxml with the line
<s:Label text="{numberData.led_top}" color="#FF0000">
</s:Label>
it accesses the value, the same as if I put it in my component
<components:oneLedDisplay showData="{numberData.led_top}" x="10" y="10" />
I don't get it after searching a couple of hours...
Thanks in advance.
My main method tasachenrechner.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" minWidth="600" minHeight="500" xmlns:components="components.*">
<fx:Script>
<![CDATA[
import components.NumberDisplay;
[Bindable]
protected var firstNumber:NumberDisplay = new NumberDisplay(1);
[Bindable]
protected var secondNumber:NumberDisplay = new NumberDisplay(2);
]]>
</fx:Script>
<components:NumDisplay
numberData="{firstNumber}"
x="10"
y="20"/>
<components:NumDisplay
numberData="{secondNumber}"
x="73"
y="20"/>
</s:Application>
My AS-Class NumberDisplay.as:
package components
{
import flash.display.DisplayObject;
[Bindable]
public class NumberDisplay
{
public var num:Number;
public var led_top:Number=0;
public var led_r1:Number=0;
public var led_r2:Number=0;
public var led_middle:Number=0;
public var led_l1:Number=0;
public var led_l2:Number=0;
public var led_bottom:Number=0;
public function NumberDisplay(num:Number)
{
this.num = num;
switch(this.num)
{
case 0:
trace("ZERo");
break;
case 1:
led_top = 1;
led_r1 = 1;
led_r2 = 1
trace("EINS" + led_top + " num:" + num);
break;
//[... some more cases]
default:
break;
}
}
}
}
My NumDisplay.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Group 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="45" height="59"
xmlns:components="components.*">
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
#namespace components "components.*";
</fx:Style>
<fx:Script>
<![CDATA[
import components.NumberDisplay;
import components.OneDisplay;
[Bindable]
public var numberData:NumberDisplay;
[Bindable]
public var oneled_top:OneDisplay = new OneDisplay(numberData.led_top);
// some more init calls of data-objects same type
]]>
</fx:Script>
<s:Label text="{numberData.led_top}" color="#FF0000">
</s:Label>
<components:oneLedDisplay showData="{oneled_top}" x="10" y="10" />
// some more objects of same type
</s:Group>
My AS-Class OneDisplay.as:
package components
{
import flash.display.DisplayObject;
public class OneDisplay
{
[Bindable]
public var show:Number;
[Bindable]
public var value:Number=0;
public function OneDisplay(show:Number)
{
this.show = show;
switch(this.show)
{
case 0:
value = 0.3;
trace(value);
break;
case 1:
value = 1.0;
trace(value);
break;
}
}
}
}
My oneLedDisplay.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Group 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 components.OneDisplay;
[Bindable]
public var showData:OneDisplay;
]]>
</fx:Script>
<s:Rect id="stroke" width="40" height="6" alpha="{showData.value}">
<s:fill>
<s:SolidColor color="#000000"/>
</s:fill>
</s:Rect>
<s:Label text="{showData.value}" color="#FF0000">
</s:Label>
</s:Group>
Remember that you are not only assigning a value, but declaring the member variable oneled_top. At that point, you cannot access numberData because it has not been instantiated (there is no call to new NumberData()! You have to find a way to make your call to new OneDisplay (numberData.led_top) at a later time, when there actually is a value to access.
You provided lots of code which I don't want to reverse engineer.
The answer is that oneled_top is being initialized before numberData. You have no control over initialization of variables when using MXML.
Set default values in the commitProperties() method, or if oneled_Top is supposed to be a skin part, set the default values in the PartAdded method.
You'll benefit from reading up on the Component Lifecycle.
You can use BindingUtils.bindSetter() to detect changes to numberData and then initialize oneled_top
BindingUtils.bindSetter(_setOneLabel_top, this, "numberData");
and setter:
function _setOneLabel_top(disp:NumberDisplay):void
{
/* if(this.oneled_top == null) */
this.oneled_top = new OneDisplay(disp.led_top);
}
But I think, that u're using [Bindable] where you shouldn't have to need it.

Resources