View Full Version : extending custom mxml component with AS3 Class
vivoices
02-13-2009, 02:47 AM
I have a custom mxml component - ApplicationActivityMsgs.mxml - like this:<?xml version="1.0" encoding="utf-8"?>
<Panel
xmlns="http://ns.adobe.com/mxml/2009">
<VBox id="msgs" height="100%" width="100%">
<Canvas id="txtContainer" width="100%" height="100%">
<TextView id="txt" width="100%" height="100%" />
<FxVScrollBar id="scroll" />
</Canvas>
<HRule id="hRuler" width="100%"/>
<ProgressBar id="progBar"
width="95%" height="20"
labelPlacement="center"
mode="manual" />
</VBox>
</Panel>Now I extended it with a class like this:package com.David
{
import mxmlComponents.ApplicationActivityMsgs;
public class AppActivityMsgs extends ApplicationActivityMsgs
{
private const _defaultHorizontalCenter:String = "0";
private const _defaultTop:String = "30";
private var _dragable:Boolean;
private var _progressBar:Boolean;
// Consturctor
public function AppActivityMsgs
( width:Number = 400, height:Number = 300,
percentWidth:Number = NaN, percentHeight:Number = NaN,
dragable:Boolean = true, progressBar:Boolean = true )
{
super( );
this.horizontalCenter = _defaultHorizontalCenter;
this.top = _defaultTop;
this.percentWidth = percentWidth;
this.percentHeight = percentHeight;
this.width = width;
this.height = height;
_dragable = dragable;
_progressBar = progressBar;
this.msgs.visible = false; // <--- throws error: #1009: Cannot access a property or method of a null object reference.
// do more
}
}
}The compiler does not complain, but I get the error "#1009: Cannot access a property or method of a null object reference." at runtime.
I understand that the extending class does not see the subcontainers in the mxml component as objects but as properties.
Any ideas of how to change visibility and other properties of the VBox, Canvas, ProgressBar etc from the extending class?
Thanks,
David
wvxvw
02-13-2009, 04:38 AM
As any other children of the UIComponent, your VBox isn't created in constructor, you should try to access it in creationComplete() or later. (maybe sometime a bit earlier is also OK, but, it depends on what are you going to do with it, because, if, for example you try to set it's properties before LayoutManager sets them, you won't see the changes you made applied to them etc.
Another thing, IMO extending MXML classes with AS is'n a good move... MXML is best at laying out visual stuff, and, you can definitely use it for event mapping and a model as well, but, surely not to build patterns to be extended by another visual components. Being converted to AS it brings in a lot of code you may be not aware of, so, it may interfere with what you'll try to do in AS, or be just a useless addition to your AS class. So, what you're doing, IMO, is kind of upside down. Create your AS class and extend it with MXML, not vice versa.
vivoices
02-13-2009, 01:05 PM
Thanks for your reply WVXVW.
I showed my mxml component simplified for clarity sake, but there is actually a lot of functionallity coded within the mxml tags, that I would not want to code in AS. I added an example of what I mean in the FxVScrollBar tag. <?xml version="1.0" encoding="utf-8"?>
<Panel
xmlns="http://ns.adobe.com/mxml/2009">
<VBox id="msgs" height="100%" width="100%">
<Canvas id="txtContainer" width="100%" height="100%">
<TextView id="txt" width="100%" height="100%" />
<FxVScrollBar
id="scroll"
minimum="0"
maximum="{ txt.contentHeight - txt.height }"
change="txt.verticalScrollPosition = scroll.value;"
enabled="{ txt.contentHeight - txt.height > 0 }" />
</Canvas>
<HRule id="hRuler" width="100%"/>
<ProgressBar id="progBar"
width="95%" height="20"
labelPlacement="center"
mode="manual" />
</VBox>
</Panel>I am aware of the extra code created by the mxml tags, but in this case I think that most of it would not be overhead. So for now I decided to listen to the CREATION_COMPLETE event and continue configuring the layout from there (See changes in the class code). package com.David
{
import mxmlComponents.ApplicationActivityMsgs;
public class AppActivityMsgs extends ApplicationActivityMsgs
{
private const _defaultHorizontalCenter:String = "0";
private const _defaultTop:String = "30";
private var _dragable:Boolean;
private var _progressBar:Boolean;
// Consturctor
public function AppActivityMsgs
( width:Number = 400, height:Number = 300,
percentWidth:Number = NaN, percentHeight:Number = NaN,
dragable:Boolean = true, progressBar:Boolean = true )
{
super( );
this.horizontalCenter = _defaultHorizontalCenter;
this.top = _defaultTop;
this.percentWidth = percentWidth;
this.percentHeight = percentHeight;
this.width = width;
this.height = height;
_dragable = dragable;
_progressBar = progressBar;
// do more
}
// event handling
override protected function createChildren( ):void {
super.createChildren();
super.addEventListener( FlexEvent.CREATION_COMPLETE, configChildren );
if( _dragable ) {
super.titleBar.addEventListener( MouseEvent.MOUSE_DOWN, handleMouseDown );
super.titleBar.addEventListener( MouseEvent.MOUSE_UP, handleMouseUp );
super.titleBar.addEventListener( MouseEvent.RIGHT_CLICK, handleRightClick );
}
}
// configuring child containers
private function configChildren( e:FlexEvent ):void {
if( _progressBar) {
// do more
} else {
this.progBar.visible = false;
this.hRuler.visible = false;
// do more
}
// do more
super.removeEventListener( FlexEvent.CREATION_COMPLETE, configChildren );
}
// draging
private function handleMouseDown( e:Event ):void {
this.startDrag( );
this.horizontalCenter = "";
this.top = "";
}
private function handleMouseUp( e:Event ):void {
this.stopDrag( );
}
// resetting position
private function handleRightClick( e:Event ):void {
this.horizontalCenter = _defaultHorizontalCenter;
this.top = _defaultTop;
}
// get definitions
public function get dragable( ):Boolean
{
return _dragable;
}
}
}Thanks for the creationComplete hint. In this case I think extending my mxml class with an AS class is the right move because of the above reasons. Creating the whole component as an AS class extending Panel would be a little bit like going back to assembly language, and I did write some low level machine code in the past. I exaggerated of course.
Am I wrong here?
Any thoughts?
Thanks,
David
wvxvw
02-13-2009, 01:38 PM
Ugh... I still believe it's not the way to go about combining AS + MXML, as you suggested before, you should be extending Panel with AS and write the final view component in MXML (even though MXML components aren't final, just for the designing purposes it's better to assume they are final). BTW, there's the DragManager for what you ware trying to do... so, I'd say what you've done is not so perfect from the design point of view, and it really adds a lot overhead... But that's kind of a lot of fixing... I'd just do it very differently from the start, so, I would never even get close to this sort of problem...
vivoices
02-13-2009, 02:14 PM
I understand what you mean, especially the MXML classes being final assumption.
I don't mind fixing, even a lot.
The DragManager though seems to deal with moving data between components etc in a Drag and Drop fashion. My MouseEvent listeners are just giving the Panel the capabillity to be freely repositioned within the application, no data moving or copying here.
So let's say I extend Panel and write the whole component in AS.
Would you care sharing some architectural thoughts?
Thanks,
David
wvxvw
02-13-2009, 02:35 PM
Moving the same object across the screen isn't really different from moving it from one component to another (also, imagine complex situation, when you need to deal with depth management for eg.)... So, I'd have it set in a way: whenever I need to move this panel, I'd make DragManager move it, not to let the panel to move according to it's own judgment, (it may never know where it's allowed to move, and cannot manage it's focus by itself etc...)
And I don't really see any purpose of creating 2 classes here... but, again, say you cannot avoid it for whatever other reason, then, I'd make functions in AS class which I would extend later with MXML protected and call them whenever I need from MXML...
vivoices
02-13-2009, 03:18 PM
I am working in Flex Builder 3 with the latest Flex4 (Gumbo) SDK.
My application follows MVC architecture.
It's basically a ViewStack with Display and Controller layers and their respective components.
The Model is created and maintained entirely in AS3 classes.
The AppActivityMsgs custom component we are discussing here is on top of the ViewStack and is shown only when the user has to be informed that some application activity is going on, e.g. during initialization, uploads etc.
As I said before, I understand the idea of assuming MXML is final.
So I will build the AppActivityMsgs Panel in one AS3 class extending Panel and add only one MXML tag in the top level application file.
The DragManager seems to be overhead when it's not needed. Since I do not need to restrict the user regarding the positioning of the AppActivityMsgs Panel, I assume listening to two mouse events will serve the purpose better, lighter on "code mass" that is.
Depth management is not needed in this specific application. Everything hast its place and there are no partially overlapping visual components that jump forwards or backwards.
So my general approach is to try to achive what the project demands with as few resources as possible.
I really appreciate your input.
Any further thoughts or corrections?
I might post the new AS3 class later.
Thanks,
David
wvxvw
02-13-2009, 04:02 PM
Then, basically, what you say is: I'm using MVC, but I don't need it :)
Meaning: you don't care about your components being reusable, you don't care about using managers (wherever you like it or not, DragManager is compiled into your application, so, not using it creates overhead code, not the opposite :) )
Also, look at it from this point of view:
You created container class, which already has some predefined children... so, you cannot really use it as a container any longer... thus, once you need the same window to pop-up, but you want it to have 1 more button, you'll either do [Heb: "shminiot ba'avir"] to make the same window add one spare button, or, you'll have to have 2 different components, etc, etc... :)
vivoices
02-13-2009, 04:36 PM
Then, basically, what you say is: I'm using MVC, but I don't need it :)The MVC architecture is applied to the whole application. Model, View and Controller components are seperated and behave according to the MVC architecture.. . . wherever you like it or not, DragManager is compiled into your application . . . Didn't know that. Where is that kind of information available?
So I look into the DragManager.. . . created container class, which already has some predefined children.... which one do you refer to, the top level application MXML file?. . . cannot really use it as a container any longer... thus, once you need the same window to pop-up, but you want it to have 1 more button, you'll either do [Heb: "shminiot ba'avir"] to make the same window add one spare button, or, you'll have to have 2 different components, etc, etc... :)as for the AppActivityMsgs custom component we are discussing here, I do not intend to create an new kind of container, I am creating a View Component for application messages according to MVC architecture, even though this View Component is not listening to the main Data Model but to the Application Messages Model.
As a custom component, displaying application messages, this class will very well be reusable, skinnable, expandable etc.
Maybe we still have some misunderstanding here. Is adding another element to a custom component created in a AS3 class considered "shminiot ba'avir" (any English translation would be saying it less:)) in your book?
It would be interessing to hear your approach for a complete application.
David
wvxvw
02-13-2009, 06:24 PM
As for flash apps I don't really see a point in having model and controllers separated, so, when I plan it I use sort of (MC) + V. And I'm really not a big fan of using patterns whatever the price may be :) I believe that common sense is the thumb rule, not some theory that may prove to be unrelated in every and each particular case.
In FlashDevelop, you can explore the SWF structure, and what was compiled into it... so, it's basically just a single click on the SWF that'll show you what do you have in there. If you cannot use it, you may compile with -verbose switched on, and see what classes it compiles, though, not sure if the classes from SWCs are also output there...
And, my point about non making components reusable was as simple as this: I'm working on the same project for 2 years already... and it's not because it's so complex, it's simply because the customer doesn't have a clear understanding in what he's going to do with it, so, I modify it over and over again... But, being plain lazy, I don't want to work hard :) so, I try to plan whatever I write as it may be used / reused / replaced / modified at least few times a week, and it won't give me any headache, I'll just copy-paste a few lines and go back to read the forum :p
So, believe it or not, prebuilt containers with prebuilt layout will cause you problems if you will want to reuse them, that's just additional work... that's it. But, again if that's some sort of make-it-and-run-away-with-the-money job, so, why would you care? Make it as fast as you can and don't give the customer your phone number!
Ah, and my average project structure looks like this:
src - Entry point
src - event maps - events
src - model (if I need any, but usually, I'd prefer to have the model on the sever, and the client to only reflect it).
src - remote (here go remote classes that I may use for reflection / communication with the server)
src - gui (AS) (this may as well be empty, because for most cases I can do with built-in components, rather then extending them)
src - view (here go all the UI-related MXML files, usually there're no nesting here, but, if there're categories, this folder may contains something like "popups folder" or "tables" etc.)
- skins (CSS / whatever classes I use for programmatic skins)
- library (3d party add-ons + whatever the designer sends me... actually, it's usually is quite a messy place...)
- run (If I need to compile the project from the cmd rather than from the IDE, I put there .BAT files, manifest.xml, services.xml build.xml and stuff like that.)
- bin (whatever I need to deploy on the server)
So, technically, the app looks very simple: from the entry point you're connected to the event map on one hand and visual components on another. Where there's the event map, I usually have the connection to the server managed too. Thus, my visual components don't even "know" there's such thing as server / mediators / commands etc they receive events. So, what's left to code in the components is only the "how to react to events". Thus if I decide to test them separately / move to the different place within the app / substitute temporarily one another etc. That's usually achieved by simply renaming the file.
And I really instantiate very few AS classes through the AS code... meaning that most of the pure-AS classes are skeletons for MXML. Non-MXML classes are usually things like PVD / some pre-made animations etc... And it doesn't have to be a mx framework project, I've found it convenient to use MXML for non-framework projects too, even though some of it's abilities will be missing, it's still more comfy IMO.
vivoices
02-13-2009, 06:54 PM
In this app I have View and Controller allmost combined, but try to keep them seperate in code as much as possible to keep it transparent and manageable.
It's an AIR - Flex app that works with local and remote data and is connected to two servers that exchange data between them during runtime, so I need to seperate the data model completely for said transparency and manageability.
I'll finish the message panel and post the result.
David
vivoices
02-14-2009, 05:50 PM
WVXVW,
after our little discussion I remade the ApplicationActivityMsgs.mxml component.
I used as much mxml as I saw fit.
Initially I moved to the Flex 4 SDK only because of the RTL capabillities it provides. This app uses resource bundles for 4 locales, but here the Flex 4 enhanced ViewStates syntax comes in very handy as well.
This is the new MXML file:<?xml version="1.0" encoding="utf-8"?>
<Panel
xmlns="http://ns.adobe.com/mxml/2009"
width="400" height="300"
horizontalCenter="0" top="30"
dropShadowEnabled="true"
shadowDirection="right"
shadowDistance="7"
borderAlpha="1"
creationComplete="init()" >
<Script source="../../include/DisplayComponents/ApplicationActivityMsgs.as" />
<states>
<State name="Text" />
<State name="TextProgBar" />
<State name="TextOk" />
<State name="TextCancel" />
<State name="TextProgBarOk" />
<State name="TextProgBarOkCancel" />
<State name="TextOkCancel" />
</states>
<VBox id="msgs"
height="100%" width="100%"
horizontalCenter="0" verticalCenter="0" >
<Canvas id="txtContainer"
width="100%" height="100%"
height.Text="100%"
height.TextProgBar="{ this.height - 81 }"
height.TextProgBarOk="{ this.height - 81 }"
height.TextProgBarOkCancel="{ this.height - 81 }">
<TextView id="txt"
width="100%" height="100%"
styleName="appMsgs"
paddingLeft="3" paddingRight="23"
paddingTop="3"
enabled="false" />
<FxVScrollBar id="scroll"
height="100%"
top="0" right="0"
minimum="0"
maximum="{ txt.contentHeight - txt.height }"
baseColor="#D0D0D0"
change="txt.verticalScrollPosition = scroll.value;"
enabled="{ txt.contentHeight - txt.height > 0 }" />
</Canvas>
<HRule id="hRuler"
excludeFrom="Text"
width="100%"/>
<HBox
height="28" width="100%"
horizontalAlign="center"
paddingLeft="5" paddingRight="5"
excludeFrom="Text" >
<Button id="btnOk"
label="OK"
excludeFrom="Text, TextProgBar, TextCancel" />
<ProgressBar id="progBar"
excludeFrom="Text, TextOk, TextOkCancel, TextCancel"
width="97%" height="20"
labelPlacement="center"
label=" label to be set"
styleName="progBar"
mode="manual" />
<Button id="btnCancel"
label="Cancel"
excludeFrom="Text, TextProgBar, TextProgBarOk, TextOk" />
</HBox>
</VBox>
</Panel>I put the remaining AS3 code directly in the MXML class:// ActionScript file
// This code is part of the "ApplicationActivityMsgs.mxml" MXML component
// >>>>> Imports <<<<<
import flash.events.IEventDispatcher;
import app.DataModels.AppMsgs;
import app.System.PpMsgsEvent;
// >>>>> Variable Declarations <<<<<
public var dragable:Boolean;
private var _horizontalCenter:*;
private var _top:*;
// >>>>> Constructor <<<<<
private function init():void
{
_horizontalCenter = this.horizontalCenter;
_top = this.top;
AppMsgs.addEventListener( PpMsgsEvent.PPMSGS_ACT_CHANGED, displayMessages );
if( dragable ) {
this.titleBar.addEventListener( MouseEvent.MOUSE_DOWN, handleMouseDown );
this.titleBar.addEventListener( MouseEvent.MOUSE_UP, handleMouseUp );
this.titleBar.addEventListener( MouseEvent.RIGHT_CLICK, handleRightClick );
}
}
// >>>>> draging <<<<<
private function handleMouseDown( event:Event ):void
{
this.startDrag( );
this.horizontalCenter = "";
this.top = "";
}
private function handleMouseUp( event:Event ):void
{
this.stopDrag( );
}
// >>>>> resetting position <<<<<
private function handleRightClick( event:Event ):void
{
this.horizontalCenter = _horizontalCenter;
this.top = _top;
}
// >>>>> receiving and displaying current Messages Texts from Messages Model <<<<<
private function displayMessages( event:PpMsgsEvent ):void
{
this.txt.text = event.result.text;
var crMax:uint = txt.contentHeight - txt.height;
if ( crMax > 0 ) {
this.scroll.value = crMax;
this.txt.verticalScrollPosition = crMax;
}
this.txt.validateNow();
}Now this Display Component is listening to the Application Activity Messages data model and it works fine.
I did not have the patience to figure out how to make the DragManager do the job of my MouseEvents. Maybe you can help me out here. Any other suggestions are also welcome.
Thanks,
David
wvxvw
02-16-2009, 04:39 PM
In the mean time:
http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&postid=12927&productid=2&loc=en_us
here's something to confirm my suggestion about not extending MXML components which are containers and have display children.
Sorry, I'll look into the code a bit later, got a lot of work to do all of a sudden :)
vivoices
03-01-2009, 11:04 PM
WVXVW,
could you give me a hint regarding the DragManager replacing my mouse events?
Thanks,
David
|
vBulletin® v3.8.4, Copyright ©2000-2009, Jelsoft Enterprises Ltd.