I've got a really simple flex application, with a main file Rec.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="215" minHeight="138" width="215" height="138" backgroundAlpha="0.0">
<fx:Script>
<![CDATA[
var rec:LRec = new LRec();
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
And an AS3 class:
package
{
import mx.core.Application;
import mx.events.FlexEvent;
public class LRec extends Application
{
public function LRec()
{
trace("CONSTRUCTED");
addEventListener(FlexEvent.APPLICATION_COMPLETE, this.mainInit);
}
/**
* After the application startup is complete, debug
*/
public function mainInit(event:FlexEvent):void {
trace("COMPLETE");
}
}
}
The trace ("CONSTRUCTED") is printed, but not "COMPLETE" -- it looks like the FlexEvent.APPLICATION_COMPLETE event is never registering. Any ideas why?
Also, this is the first time I've really done this sort of programming, so if anything else looks wrong, please tell me!
I've updated your code below with some comments on where you were going wrong. If you have any other questions feel free to ask.
Test.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="215" minHeight="138" width="215" height="138" backgroundAlpha="0.0"
initialize="handle_initialize(event)"
>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
// Probably want to keep your rec object around
private var rec:LRec;
// Construct your LRec instance in the Application's inititialize state,
// rather than declaring it statically.
protected function handle_initialize(event:FlexEvent):void
{
// Construct a new LRec instance, assign it to our private variable.
this.rec = new LRec();
// The <s:Applicaiton instance we define in this mxml is the object that
// will actually dispatch the applicationComplete event, so we want to
// listen for that here and pass it on to our LRec instance's mainInit
// method when it fires.
this.addEventListener(FlexEvent.APPLICATION_COMPLETE, this.rec.mainInit);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
LRec.as
package
{
import mx.events.FlexEvent;
// Don't inherit from Application, as you've already defined your application
// in your mxml, and you should have only one Application instance per application.
public class LRec
{
public function LRec()
{
trace("CONSTRUCTED");
// Doesn't need the event listener anymore.
// Do any instantiation needed.
}
/**
* After the application startup is complete, debug
*/
public function mainInit(event:FlexEvent):void {
trace("COMPLETE");
// Do any of the work that needs to wait for the applicationComplete
// event to fire.
}
}
}
Here's a good article (though a bit dated) on the Flex Instantiation Model.
Related
I'm using FlashBuilder 4.7 and Flex SDK 4.11.
I've created new Mobile Flex Project and created 2 files in default package:
bestPairs.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:bestpairs="*"
width="640"
height="480">
<s:layout>
<s:BasicLayout />
</s:layout>
<s:Label text="Hello World!" horizontalCenter="0" verticalCenter="0" />
<s:Button id="myButton"/>
</s:Application>
Main.as:
package
{
import flash.events.MouseEvent;
import mx.events.FlexEvent;
import spark.components.Button;
import spark.components.Group;
public class Main extends Group
{
public var myButton:Button;
public function Main()
{
super();
this.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
trace("main!");
}
private function onCreationComplete(e:FlexEvent):void {
this.removeEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
myButton.addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(e:MouseEvent):void {
// Do something
trace("clicked!");
}
}
}
because I want to split code from design. Anyway trace are not showing at all. In Debug Mode too. I tried also this: https://stackoverflow.com/a/3627826/1264375 (I made flex-config.xml file in src/config and added parameter to compiler - http://blog.flexexamples.com/2008/12/21/using-a-custom-flex-configxml-file-in-flex-builder-3/) and other googled solutions. Nothing is working I just see this:
[SWF] bestPairs.swf - 3,190,645 bytes after decompression
and later on:
[Unload SWF] bestPairs.swf
I'm using iPhone4 Air simulator to test app.
Is there any way to display trace logs? It's hard to develop without them.
Any help will be appreciated,
Regards!
Unless I am missing something, you never add a Main object to your application. For the trace to occur, you have to instantiate an instance of Main. Prior to that, none of the code in that class will run
The proposed UX I am trying to achieve is this:
user clicks menu item (via a listBase subclass: e.g. ButtonBar or TabBar)
prevent initial selection
validate if user needs to address issues (e.g. unsaved data on a form, etc.)
if valid, take selection and set the listBase to that selectedIndex, otherwise present warnings to user and cancel out the selection process altogether
This does not work as you'd expect. Utilizing the IndexChangeEvent.CHANGING type and the preventDefault works to kill the selection, but at step 4, when I am programmatically setting the selectedIndex of the listBase, it then tries to redispatch the CHANGING event (this despite what the API docs claim).
Here is a sample application src code if you'd like to try this for yourself. I look forward to your comments & solutions.
Thanks.
J
http://snipt.org/vUji3#expand
<?xml version="1.0" encoding="utf-8"?>
<s:Application minWidth="955" minHeight="600"
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 flash.utils.setTimeout;
import mx.core.mx_internal;
import spark.events.IndexChangeEvent;
use namespace mx_internal;
[Bindable]
private var doPreventDefault:Boolean;
[Bindable]
private var delayMS:uint = 500;
private function buttonbar_changingHandler( event:IndexChangeEvent ):void
{
// TODO Auto-generated method stub
if ( doPreventDefault )
{
event.preventDefault();
setTimeout( delayedLogic, delayMS, event.newIndex );
}
}
private function delayedLogic( index:int ):void
{
//disabling this results in an endless loop of trying to set the selected index
// doPreventDefault = false;
//this should NOT be hitting the changing handler since we're supposed to be dispatching a value commit event instead.
bb.setSelectedIndex( index, false );
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout horizontalAlign="center"/>
</s:layout>
<s:ButtonBar id="bb"
changing="buttonbar_changingHandler(event)">
<s:dataProvider>
<s:ArrayList>
<fx:String>btn 0</fx:String>
<fx:String>btn 1</fx:String>
<fx:String>btn 2</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ButtonBar>
<s:CheckBox label="preventDefault?"
selected="#{ doPreventDefault }"/>
<s:NumericStepper maximum="5000" minimum="500"
stepSize="500" value="#{ delayMS }"/>
</s:Application>
Looking at the SDK, the IndexChangeEvent.CHANGING event is actually preventable - despite the documentation here says that cancelable is false, so my bad on that (although ASDoc went a little sideways), however things get a little interesting from here.
In ListBase #1296 this is only ever dispatched from the commitSelection(dispatchEvents:Boolean = true) method. In ButtonBarBase:dataProvider_changeHandler() is the only place that specifically calls to not dispatch the event, but in ListBase, it's called in commitProperties #939 when there is a proposedSelectionIndex.
So from your code above, if you are trying to set the selection - this is going to call the commitSelection, which I believe is causing the call stack issue. The Timer delay is just going to exacerbate the issue, since at 500ms the UI will have gone through its invalidation cycle at least once, meaning the commitSelection will be executed again because of an invalidateProperties flag is being set from the proprosedSelectionIndex eventually stemming from setSelectedIndex #729
So how to fix this.
I would look at only doing the prevent if the validation fails, otherwise allow it to proceed as normal. If it does fail, call the prevent, set an errorString or equivalent, but don't attempt to change the selection.
[edit] Read RiaStar's comment, and I just concurred with the same 'solution'.
I have a crash that only happens with the installed application I can't make it cvrash in the IDE(Flash Builder debug or run option)
After a long time of commenting and uncomenting code I found the problem and I am posting the code below
<?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"
xmlns:ns="generic_components.*"
creationComplete="windowedapplication1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
//import core.Logger;
import mx.controls.Alert;
import mx.events.FlexEvent;
import spark.events.TextOperationEvent;
protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
//Logger.init();
}
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
//Logger.write("camel case for "+txt);
for (var i:int=1;i<txt.length;i++)
{
// Logger.write("camel iter "+i);
var c:String=txt.charAt(i);
//Logger.write("camel char is "+c);
if(c==c.toUpperCase())
{
res=res+" "+c;
}
else
res=res+c;
}
return res;
}
protected function test_clickHandler(event:Event):void
{
Alert.show(humanFromCamelCase("CompanyId"));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:Button id="test" label="TEST" click="test_clickHandler(event)"/>
</s:WindowedApplication>
Also see a web sample here http://ploscariu.com/crash/TestWeb.html (may be not there in the future)
What is weird about this crash:
1 I have no idea what happens
2 The usual crash handler in the player does not show up
3 is not crashing in the development enviroment IDE
4 if i uncomment those Logger.write then the code works on my machine fine(it could not work on all machines), the Logger.write writes the sting in a file and is placed in another project swf (I did not included the logger code)
I a, assuming that the call to Logger.write can cause a delay or something similar
It is something wrong in my code or the player is buggy? or the compiler??
Any ideas?
Edit:
-is not the logger i use since the error happens when I am not using it like in the sample code or page, no logger the app it crashes
-i get no dialog from Flash with a crash report
This is so incredibly odd!!!! I have NO idea why this happening (yet)... but I have a workaround:
Instead of res=res+c, use res+=c:
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
for (var i:int=1;i<txt.length;i++)
{
var c:String=txt.charAt(i);
if(c === c.toUpperCase())
{
res += " " + c;
}
else
res += c;
}
return res;
}
I have no idea why you're having an error, however, I would replace the function with this instead:
public static function humanFromCamelCase(txt:String):String{
return txt.replace(/([A-Z])/g, ' $1').replace(/^ /, "");
}
Haven't tested it, but you get the idea. This is a much simpler and faster approach.
I also thought of another way:
public static function humanFromCamelCase(txt:String):String{
return txt.split(/(?=[A-Z])/).join(' ');
}
I'm asked about Display List architecture in Flex at an interview. Later I searched about it but no use. Any help is appreciated.
The Display List is like a tree. Imagine the Stage object as the base of the tree. Think of MovieClips and Sprites that are added to the stage as branches and leaves coming off of the tree. The Display List also serves as the core for the event system in AVM2. Objects that are attached to the DisplayList (that is, they themselves or their parent, parents parent etc end up connecting to the Stage) can "bubble" events through the Display List.
Anyway that's my short little way of explaining it but you can get much more detailed information from these links:
http://www.adobe.com/devnet/flash/quickstart/display_list_programming_as3.html
http://tv.adobe.com/watch/colin-moocks-lost-actionscript-weekend/the-display-list/
seems like the question should really sound as follows:
when you write <s:Application> (or any other SkinnableContainer / UIComponent) in your mxml code -- what is the structure of the resulting display list?
so you should do something like:
<?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" applicationComplete="onAppComplete();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import mx.controls.Alert;
import mx.core.UIComponent;
import spark.components.SkinnableContainer;
private function onAppComplete(e:* = null):void {
trace(parseList(stage));
//Alert.show(parseList(stage));
}
private function parseList(uic:DisplayObjectContainer, prefix:String = '>'):String{
prefix = prefix || '>';
var retStr:String = '';
for (var i:int = 0; i < uic.numChildren; i++ ) {
retStr += prefix + uic.getChildAt(i).name + '\n';
if (uic.getChildAt(i) is DisplayObjectContainer) {
retStr += parseList(uic.getChildAt(i) as DisplayObjectContainer, prefix + '>');
}
}
return retStr;
}
]]>
</fx:Script>
<s:SkinnableContainer>
<s:Panel>
<mx:UIComponent>
</mx:UIComponent>
</s:Panel>
</s:SkinnableContainer>
</s:Application>
(or maybe more complex) and study the output
the code above outputs
>root1
>>NewFile1
>>>ApplicationSkin3
>>>>Group4
>>>>>Group5
>>>>>>SkinnableContainer6
>>>>>>>SkinnableContainerSkin7
>>>>>>>>Group8
>>>>>>>>>Panel9
>>>>>>>>>>PanelSkin10
>>>>>>>>>>>RectangularDropShadow11
>>>>>>>>>>>Group12
>>>>>>>>>>>>Group13
>>>>>>>>>>>>instance36
>>>>>>>>>>>>Group14
>>>>>>>>>>>>>Group15
>>>>>>>>>>>>>>Label16
>>>>>>>>>>>>>>>instance33
>>>>>>>>>>>>>>>instance37
>>>>>>>>>>>>>Group17
>>>>>>>>>>>>>>UIComponent18
I have a class called S3Uploader which extends Sprite, which has a private function init, which looks sometihng like this:
private function init(signatureUrl:String,
prefixPath:String,
fileSizeLimit:Number,
queueSizeLimit:Number,
fileTypes:String,
fileTypeDescs:String,
selectMultipleFiles:Boolean,
buttonWidth:Number,
buttonHeight:Number,
buttonUpUrl:String,
buttonDownUrl:String,
buttonOverUrl:String
):void {
//do stuff
}
In my flex app, I am trying to display the sprite and call the init function when the app is loaded. my code so far is this:
<?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"
initialize="init();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import S3Uploader;
function init() {
var s3upload:S3Uploader = new S3Uploader();
s3upload.init('/s3_uploads2.xml', '', 524288000, 100, '*.*', 'All Files', true, 100, 30, '/images/upload-button.png', '/images/upload-button.png', '/images/upload-button.png');
uploader.addChild(s3upload);
}
]]>
</fx:Script>
<s:SpriteVisualElement id="uploader" />
</s:Application>
however, on the line where i call s3upload.init, i get a 1195 error saying "1195: Attempted access of inaccessible method init through a reference with static type S3Uploader."
When i looked up this error, it seems like almost everyone getting this was trying to call a function with set or get. However, I am not doing this and i have no idea why i am getting this error. Does anyone know what I am doing wrong?
You should learn the basics of OOP. You cannot call private functions from not within function owner objects. Mark it as public.