I have to create the image object using something like this
[Embed("/assets/images/Header.png")]
public static var HeaderIcon:Class;
but now the string within embedd is dynamically brought from some xml
like xmlObject.child("icon"); which I tried it like
[Embed(xmlObject.child('icon').toString())]
public static var HeaderIcon:Class;
However it gives errors like
invalid metadata
I am using the above code in action script(as is obvious)
Is there any way to solve this?
You need to use the Loader class: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Loader.html
It's a bit more complicated than with embedded resources, but there are good examples in the documentation.
Class Name: -HeaderIconClass
//////////
package
{
import spark.components.Image;
internal dynamic class HeaderIconClass extends Image
{
public function HeaderIconClass()
{
super();
}
}
}
Inside your component or Application level: -
<?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="application1_creationCompleteHandler(event)">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Bindable]
public var headerIcon:HeaderIconClass = new HeaderIconClass();
//For your testing
protected function button1_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
imageID.source = headerIcon.source
}
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
// TODO Auto-generated method stub
headerIcon.source = "#Embed('/assets/images/Header.png')";
}
]]>
</fx:Script>
<mx:VBox x="100" y="100">
<s:Button label="Show Image" click="button1_clickHandler(event)"/>
<s:Image id="imageID" width="50" height="50"/>
</mx:VBox>
</s:Application>
If you want to use this you can save this in variable: -
private var imagePath:String = xmlObject.child('icon').toString();
and change below function as: -
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
// TODO Auto-generated method stub
headerIcon.source = "#Embed('"+imagePath+"')";
}
Hope this may help .....
Related
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;
I can't get my TextArea to take the focus skin which I did in the mxml skin file below. Can anyone help me with this. Note that in my application css file I have specified the focus skin as such : focus-skin: ClassReference("skins.focusSkin");
Skin File Code:
<?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">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import spark.components.supportClasses.SkinnableComponent;
private var _target:SkinnableComponent;
public function get target():SkinnableComponent
{
return _target;
}
public function set target(value:SkinnableComponent):void
{
_target = value;
if (_target.skin)
_target.skin.addEventListener(FlexEvent.UPDATE_COMPLETE,
skin_updateCompleteHandler, false, 0, true);
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
this.setActualSize(target.width, target.height);
super.updateDisplayList(target.width, target.height);
}
private function skin_updateCompleteHandler(event:Event):void
{
invalidateDisplayList();
}
]]>
</fx:Script>
<s:BitmapImage id="focusGroup" source="#Embed(source='mySkinFile.swf', symbol='mySymbol')" />
</s:Group>
Take a look at the examples in this blog post that demonstrates how to create custom focus skins in spark:
http://flexponential.com/2010/01/24/custom-focusskin-for-spark-components-in-flex-4/
I created a somewhat custom Spark button by doing the File > New > MXML skin and basing it on spark.components.button. The problem is that I need to add an extra text field to the button component and dynamically change that text...but of course, the property isn't recognized on a Spark Button.
Is there a simple way to add this field to my custom button skin & its property so it can be addressed? If not, is there a simple way to take what I've done and just extend the Spark Button? I can't seem to find any examples that show how to do it without writing it all up in ActionScript.
I'm glad you asked! This is much easier than you'd think so don't be discouraged! ActionScript is pretty easy once you get the hang of it.
First of all, let's define what we want. After reading your question I believe you would like to use your button something like this:
<local:MyCustomButton label="Hello" label2="World!"/>
So let's go over how to make that a reality.
Now, I would highly suggest extending Button with ActionScript, but it is also possible to do in mxml:
//MyCustomButton.mxml
<?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">
</s:Button>
Then you can add the SkinParts you need in a <fx:Script>:
<?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">
<fx:Script>
<![CDATA[
[SkinPart]
public var secondLabelDisplay:spark.components.Label;
]]>
</fx:Script>
</s:Button>
So now when you make a skin you should include something like the original label, just with a different ID to reflect your new SkinPart:
But wait! What text should our second label show?? Well, we will need to add another property that you can set for each individual instance of the button:
<?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">
<fx:Script>
<![CDATA[
[SkinPart]
public var secondLabelDisplay:spark.components.Label;
private var _label2:String;
public function get label2():String
{
return _label2;
}
public function set label2(value:String):void
{
_label2 = value;
}
]]>
</fx:Script>
</s:Button>
Cool, so now we can set label2 when we use our button, but at this point it won't change the label's actual text property. We need to hook up our label2 to our secondLabelDisplay. We do this by calling invalidateProperties when the label2 changes and then change the label in commitProperties (which will be called because of the invalidateProperties() call):
<?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">
<fx:Script>
<![CDATA[
[SkinPart]
public var secondLabelDisplay:spark.components.Label;
private var _label2:String;
private var label2Changed:Boolean;
public function get label2():String
{
return _label2;
}
public function set label2(value:String):void
{
_label2 = value;
label2Changed = true;
invalidateProperties();
}
override protected function commitProperties():void
{
super.commitProperties();
if(label2Changed)
{
label2Changed = false;
secondLabelDisplay.text = label2;
}
}
]]>
</fx:Script>
</s:Button>
Lastly, you'll notice that if you change label2 again afte runtime, the label will show the change. But it won't show the change if you set an initial label2 like in our target usage. The Flex team made a special method just for this case, partAdded(). I won't go over too many details about it because there is already a good amount of literature on the subject.
Finally, here's our finished, custom button awaiting a skin to put it to use:
<fx:Script>
<![CDATA[
[SkinPart]
public var secondLabelDisplay:spark.components.Label;
private var _label2:String;
private var label2Changed:Boolean;
public function get label2():String
{
return _label2;
}
public function set label2(value:String):void
{
_label2 = value;
label2Changed = true;
invalidateProperties();
}
override protected function commitProperties():void
{
super.commitProperties();
if(label2Changed)
{
label2Changed = false;
secondLabelDisplay.text = label2;
}
}
override protected function partAdded(partName:String, instance:Object):void
{
if(instance == secondLabelDisplay)
{
secondLabelDisplay.text = _label2;
}
}
]]>
</fx:Script>
Best of luck!
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.
I'm trying to prevent a custom tooltip from disappearing. I've tried three runs at this, borrowing from the usual suspects: Peter Dehann, MonkeyPatch and others. As you can see from the code below I'd like to stay within the tool tip paradigm and not go to popups.
Can anyone suggest a way to persist a tooltip? The intent here is to have a component which can be cut and paste from.
Thanks,
Doug
<?xml version="1.0" encoding="utf-8"?>
<s:Application minHeight="600" creationComplete="application1_creationCompleteHandler(event)"
minWidth="955"
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[
import mx.events.FlexEvent;
import mx.events.ToolTipEvent;
protected function button1_clickHandler(event:MouseEvent):void {
// TODO Auto-generated method stub
}
protected function button1_toolTipCreateHandler(event:ToolTipEvent):void {
createCustomToolTip("title", "", event);
}
// TODO Auto-generated method stub
private function createCustomToolTip(title:String, body:String, event:ToolTipEvent):void {
var ptt:CustomToolTip = new CustomToolTip();
ptt.title = title;
ptt.bodyText = (event.currentTarget as Button).toolTip;
event.toolTip = ptt;
}
protected function button1_toolTipHideHandler(event:ToolTipEvent):void
{
// TODO Auto-generated method stub
event.stopPropagation();
event.preventDefault();
event.stopImmediatePropagation();
}
import mx.managers.ToolTipManager;
private var tt:CustomToolTip;
private var cc:CustomToolTip;
private function create_toolTip():void {
var str:String = "Tooltip text goes here...";
// We only want one tooltip.
if (tt == null) {
tt = ToolTipManager.createToolTip(str, 100, 50) as CustomToolTip;
}
}
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
// TODO Auto-generated method stub
mx.managers.ToolTipManager.toolTipClass = CustomToolTip;
//mx.managers.ToolTipManager.scrubDelay = 100000;
//mx.managers.ToolTipManager.hideDelay = 1000000;
}
protected function button1_toolTipEndHandler(event:ToolTipEvent):void
{
event.preventDefault();
event.stopImmediatePropagation();
// TODO Auto-generated method stub
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:VBox>
<mx:Button click="button1_clickHandler(event)"
toolTip="helloWorld" toolTipHide="button1_toolTipHideHandler(event)" toolTipEnd="button1_toolTipEndHandler(event)"
toolTipCreate="button1_toolTipCreateHandler(event)" >
</mx:Button>
<mx:Button label="create tool tip" click="create_toolTip();" />
<mx:Button toolTip="hello world" label="hello">
</mx:Button>
</mx:VBox>
</s:Application>
Use some JavaScript that to show the tooltip in the onmouseover portion of the link:
<a href="page.aspx" onmouseover=showtooltip("Tooltip Text")></a>
don't include any JavaScript routine like onmouseout=hidetooltip() in your link, it will stay open.
P.S.: You can put a link in the "Tooltip Text" that includes onmouseout=hidetooltip(), something like:
<a href=originalpage.aspx onclick=hidetooltip()>Close</a>