How do I get rid of a null StyleProtoChain object reference? - apache-flex

Here is the error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.styles::StyleProtoChain$/initProtoChainForUIComponentStyleName()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\styles\StyleProtoChain.as:72]
at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::initProtoChain()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:7469]
at mx.core::UIComponent/regenerateStyleCache()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:7690]
at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::addingChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:5239]
at mx.core::UIComponent/addChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:4955]
at mx.controls.listClasses::ListBase/createChildren()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\controls\listClasses\ListBase.as:3103]
at mx.core::UIComponent/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:5370]
at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:5267]
at mx.core::Container/http://www.adobe.com/2006/flex/mx/internal::childAdded()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3305]
at mx.core::Container/addChildAt()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2217]
at mx.core::Container/addChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2140]
at model::MessageBoard()[C:\Documents and Settings\dbabbitt\My Documents\Flex Builder 3\ListExample\src\model\MessageBoard.as:56]
at model::MessageBoard$cinit()
at global$init()[C:\Documents and Settings\dbabbitt\My Documents\Flex Builder 3\ListExample\src\model\MessageBoard.as:7]
at main()[C:\Documents and Settings\dbabbitt\My Documents\Flex Builder 3\ListExample\src\main.mxml:56]
at _main_mx_managers_SystemManager/create()
at mx.managers::SystemManager/initializeTopLevelWindow()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3188]
at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::docFrameHandler()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3064]
at mx.managers::SystemManager/docFrameListener()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:2916]
Here is main.mxml:
<?xml version="1.0"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
>
<mx:Script>
<![CDATA[
import model.MessageBoard;
public var _messageBoard:MessageBoard = MessageBoard.instance;
]]>
</mx:Script>
</mx:Application>
Here is MessageBoard.as:
package model {
import mx.containers.VBox;
import mx.controls.Label;
[Bindable]
public class MessageBoard extends VBox {
/** The message list title. */
private var _messageTitle:Label;
/** The maximum message count. */
private var _maxMessageCount:int = 4;
/** Storage for the singleton instance. */
private static const _instance:MessageBoard = new MessageBoard( SingletonLock );
/** Provides singleton access to the instance. */
public static function get instance():MessageBoard {
return _instance;
}
/**
* Constructor
*
* #param lock The Singleton lock class to pevent outside instantiation.
*/
public function MessageBoard( lock:Class ) {
super();
// Verify that the lock is the correct class reference.
if ( lock != SingletonLock ) {
throw new Error( "Invalid Singleton access. Use MessageBoard.instance." );
}
_messageTitle = new Label();
_messageTitle.text = "Message Board";
this.addChild(_messageTitle);
}
} // end class
} // end package
class SingletonLock {
} // end class
Maybe you could school me in how to keep null object references out of complex Classes?
Thanx
Dave

It looks like the error may be coming from the call to the addChild() method in the constructor of your MessageBoard class. You may very well be invoking this method too early in the UIComponent lifecycle. I would recommend overriding the createChildren() method and adding your child element(s) there.
override protected function createChildren():void
{
super.createChildren();
_messageTitle = new Label();
_messageTitle.text = "Message Board";
this.addChildAt(_messageTitle, 0);
}

Related

Error #1009, navigator is null

I've got some problem in Flex. Basically I want to navigate to other pages by using navigator.pushview from list through custom item renderer. This is my CustomItemRender.as. Edit:
package renderer
{
import flash.events.MouseEvent;
import mx.core.FlexGlobals;
import mx.events.FlexEvent;
import mx.events.ItemClickEvent;
import spark.components.LabelItemRenderer;
import spark.components.NavigatorContent;
import spark.components.ViewNavigator;
public class CustomItemRender extends LabelItemRenderer
{
protected var var_A:Image;
[Bindable]
public var navigator:ViewNavigator = new ViewNavigator();
public function PrgListItemRenderer()
{
super();
}
override public function set data(value:Object):void
{
super.data = value;
}
override protected function createChildren():void
{
super.createChildren();
if(!takeAtt)
{
var_A= new Image();
var_A.source = "data/pics/var_A.png";
var_A.width = 23;
var_A.height = 23;
var_A.buttonMode = true;
var_A.addEventListener(MouseEvent.CLICK, var_AItem);
addChild(var_A);
}
}
override protected function measure():void
{
super.measure();
// measure all the subcomponents here and set measuredWidth, measuredHeight,
// measuredMinWidth, and measuredMinHeight
}
/**
* #private
*
* Override this method to change how the background is drawn for
* item renderer. For performance reasons, do not call
* super.drawBackground() if you do not need to.
*/
override protected function drawBackground(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.drawBackground(unscaledWidth, unscaledHeight);
// do any drawing for the background of the item renderer here
if(selected || showsCaret)
{
graphics.beginFill(0xffffff, 1);
graphics.endFill();
}
}
public function var_AItem(event:MouseEvent):void
{
trace("navigator: "+navigator);
navigator.pushView(nextView); //this is the line that have error #1009
}
}
}
But I got Error #1009. Help me please. Thanks.
I think it's a bad idea to listen to the click event inside the item renderer.
Your basic setup should look something like this:
->ViewNavigatorApplication>
-->SomeCustomView
---> SomeListBasedComponent id="list" itemRenderer="someCustomRenderer"
Fill the list with some data, which will be presented by your itemRenderer.
Now listen to the "IndexCangeEvent" of the list (from your view) and handle the 'click' there
To your view add:
private function init():void
{
list.addEventListener(IndexChangeEvent.CHANGE , onIndexChange );
}
protected function onIndexChange(e:IndexChangeEvent):void
{
// find out which item was selected. You can use the selectedItem property for this
var item:Object = list.selectedItem;
// start the view;
navigator.pushView(MyViewClass , item.someViewData );
}
Your view will hold the reference to the ViewNavigator.
P.S. dont forget to call the init() function onCreationComplete() of your view.
To your view declaration add:
View ... creationComplete="init()" >

Can't figure out why I'm getting an "Access of undefined object" error in Flex 4.5

I'm very new to Flex 4.5 and I created a class (Project.as) with the following code in it:
package classes
{
public class Project
{
public var projectName:String;
public var description:String;
public var fileLoc:String;
public function Project()
{
// This is the constructor
}
public function SayHello() {
import mx.controls.Alert;
Alert.show('howdy!','Greeting');
}
}
}
In my main.mxml file, I have the following code:
<fx:Script>
<![CDATA[
import classes.Project;
import mx.controls.Alert;
public var aProject:Project = new Project;
aProject.SayHello();
]]>
</fx:Script>
And Flex Builder is saying this:
1120: Access of undefined property aProject.
Why is it telling me this, and how can I fix it? I don't see why it's not working.
Lots of issues here.
First, I have never seen anyone put import statements inside a method. Usually they are put between the package and class definition:
package classes
{
import mx.controls.Alert;
public class Project
{
public var projectName:String;
public var description:String;
public var fileLoc:String;
public function Project()
{
// This is the constructor
}
public function SayHello() {
Alert.show('howdy!','Greeting');
}
}
}
Second; the line of ActionSCript code that you write to call a method on your class instance should be placed inside a method; not "random". Like this:
<fx:Script>
<![CDATA[
import classes.Project;
import mx.controls.Alert;
public var aProject:Project = new Project;
protected function sayHello():void{
aProject.SayHello();
}
]]>
</fx:Script>
Some way you'll want to call that method. A commenter on the original post suggested using creationComplete, which would work. However, you should be cautious about using creationComplete for "constructor-style" code in an MXML Component. preinitialize is better, and the event will fire right after the actual constructor runs. If you need to access any MXML children, have your code in an initialize event handler which runs right after createChildren() runs.
creationComplete handlers execute right after the component finishes initializing; and people often do things in creationComplete that make the component go through it's Lifecycle again, updating the display list.

Alert Box Class

I want to make a reusable Alert Box Class which will be instantiated on various screens of my Flex Project.
Can some tell me whats next in the code below, because am sort of lost regarding how to set the message and title and how to call the Class in my project?
Any help.
Thanks
package components
{
import mx.controls.Alert;
import mx.core.mx_internal;
public class myAlertBox extends Alert
{
public function AlertBoza()
{
super();
var a:Alert;
}
override public static function show():void{
}
}
}
You do not need to extend Alert since the Alert.show() function is static. But you can set it as follows inserting a constructor for a message string and a class member. With that cou can just call the class with the constructor and show the alertbox.
package components
{
import mx.controls.Alert;
import mx.core.mx_internal;
public class myAlertBox
{
private var message:String;
public function myAlertBox(message:String = "")
{
super();
this.message = message;
}
public function show():void{
Alert.show(message);
}
}
}
In another class you can call:
var box:myAlertBox = new myAlertBox("Error");
myAlertBox.show();
If you just want to show a simple alert box, just use mx.controls.Alert directly as you can specify the title and the message show then:
import mx.controls.Alert;
Alert.show("the message", "the title");

Some [Bindable] properties in Flex work, some don't

Problem solved, see below
Question
I'm working in Flex Builder 3 and I have two ActionScript 3 classes (ABC and XYZ) and a Flex MXML project (main.mxml). I have an instance of XYZ as a property of ABC, and I want XYZ's properties to be visible ([Bindable]) in the Flex project in text controls.
Unfortunately, only prop3 and prop4 update when they are changed. I've entered the debugger to make sure that prop1 and prop2 change, but they are not being updated in the text controls.
Here's the code:
ABC.as
[Bindable]
public class ABC extends UIComponent {
/* Other properties */
public var xyz:XYZ = new XYZ();
/* Methods that update xyz */
}
XYZ.as
[Bindable]
public class XYZ extends Object {
private var _prop1:uint = 0;
private var _prop2:uint = 0;
private var _prop3:uint = 0;
private var _prop4:uint = 1;
public function get prop1():uint {
return _prop1;
}
public function set prop1(value:uint):void {
_prop1 = value;
}
/* getters and setters for prop2, prop3, and prop4 */
}
main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:com="com.*" />
<com:ABC id="abc" />
<mx:Text text="{abc.xyz.prop1}" />
<mx:Text text="{abc.xyz.prop2}" />
<mx:Text text="{abc.xyz.prop3}" />
<mx:Text text="{abc.xyz.prop4}" />
</mx:Application>
Answer
It's not apparent from the small code snippets that I posted, but from within XYZ I was updating _prop3 and _prop4 using their setters. In constrast, I updated _prop1 and _prop2 through their private variables, not their setters. Thus, properties 1 and 2 were not dispatching update events.
It looks like your getters are returning voids. They should be returning uints, according to your field types.
Otherwise your code should be working fine. I've assembled and tested a working version with a Timer that sets all four values, so you can see all four updating:
Main.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*" creationComplete="onCreationComplete()">
<mx:Script>
<![CDATA[
private function onCreationComplete():void
{
var t:Timer = new Timer(1000);
t.addEventListener(TimerEvent.TIMER, t_tick);
t.start();
}
private function t_tick(event:TimerEvent):void
{
var i:uint = Timer(event.currentTarget).currentCount;
abc.xyz.prop1 = i;
abc.xyz.prop2 = i;
abc.xyz.prop3 = i;
abc.xyz.prop4 = i;
}
]]>
</mx:Script>
<local:ABC id="abc" />
<mx:VBox>
<mx:Text text="{abc.xyz.prop1}" />
<mx:Text text="{abc.xyz.prop2}" />
<mx:Text text="{abc.xyz.prop3}" />
<mx:Text text="{abc.xyz.prop4}" />
</mx:VBox>
</mx:Application>
ABC.as
package
{
import mx.core.UIComponent;
[Bindable]
public class ABC extends UIComponent
{
public var xyz:XYZ = new XYZ();
public function ABC()
{
super();
}
}
}
XYZ.as
package
{
[Bindable]
public class XYZ extends Object
{
private var _prop1:uint = 0;
private var _prop2:uint = 0;
private var _prop3:uint = 0;
private var _prop4:uint = 1;
public function XYZ()
{
super();
}
public function get prop1():uint {
return _prop1;
}
public function set prop1(value:uint):void {
_prop1 = value;
}
public function get prop2():uint {
return _prop2;
}
public function set prop2(value:uint):void {
_prop2 = value;
}
public function get prop3():uint {
return _prop3;
}
public function set prop3(value:uint):void {
_prop3 = value;
}
public function get prop4():uint {
return _prop4;
}
public function set prop4(value:uint):void {
_prop4 = value;
}
}
}
Have a look at those, plug things in and you should see it all come together. Post back if you have any questions. Cheers.
When you define your bindable sources through the use of getters and setters, the bindings don't seem to work. The solution is to declare a bindable event for your getter and dispatch the event in your setter:
[Bindable]
public class XYZ extends Object {
private var _prop1:uint = 0;
private var _prop2:uint = 0;
private var _prop3:uint = 0;
private var _prop4:uint = 1;
[Bindable(event="prop1Changed")]
public function get prop1():uint {
return _prop1;
}
public function set prop1(value:uint):void {
_prop1 = value;
dispatchEvent (new Event ("prop1Changed"));
}
/* getters and setters for prop2, prop3, and prop4 */
}
So whenever your private member changes, an event is dispatched that notifies any component linked to the getter that the property has changed.

Why is my override protected function createChildren being ignored?

Here is the error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at view::ScoreBoard/setChipCount()[C:\Flex Builder 3\StackOverflowQuestion\src\view\ScoreBoard.as:32]
at model::MainDeckScoreBoard()[C:\Flex Builder 3\StackOverflowQuestion\src\model\MainDeckScoreBoard.as:21]
at model::MainDeckScoreBoard$cinit()
at global$init()[C:\Flex Builder 3\StackOverflowQuestion\src\model\MainDeckScoreBoard.as:5]
at main()[C:\Flex Builder 3\StackOverflowQuestion\src\main.mxml:13]
at _main_mx_managers_SystemManager/create()
at mx.managers::SystemManager/initializeTopLevelWindow()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3188]
at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::docFrameHandler()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3064]
at mx.managers::SystemManager/docFrameListener()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:2916]
Here is main.mxml:
<?xml version="1.0"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp()"
>
<mx:Script>
<![CDATA[
import model.MainDeckScoreBoard;
public var _mainDeckScoreBoard:MainDeckScoreBoard = MainDeckScoreBoard.instance;
private function initApp():void {
this.addChild(_mainDeckScoreBoard);
}
]]>
</mx:Script>
</mx:Application>
Here is MainDeckScoreBoard.as:
package model {
import view.ScoreBoard;
[Bindable]
public dynamic class MainDeckScoreBoard extends ScoreBoard {
/** Storage for the singleton instance. */
private static const _instance:MainDeckScoreBoard = new MainDeckScoreBoard( SingletonLock );
/** Provides singleton access to the instance. */
public static function get instance():MainDeckScoreBoard {
return _instance;
}
public function MainDeckScoreBoard( lock:Class ) {
super();
// Verify that the lock is the correct class reference.
if ( lock != SingletonLock ) {
throw new Error( "Invalid Singleton access. Use MainDeckScoreBoard.instance." );
}
this.setChipCount("0");
}
} // end class
} // end package
class SingletonLock {
} // end class
Here is ScoreBoard.as:
package view {
import mx.containers.HBox;
import view.ScoreBoardLabel;
import view.ChipCountContainer;
import view.CardRankList;
public dynamic class ScoreBoard extends HBox {
/** The chip count. */
public var _chipCount:ChipCountContainer;
public function ScoreBoard() {
super();
this.width = 489;
this.height = 40;
this.setStyle("horizontalScrollPolicy", "off");
}
override protected function createChildren():void {
super.createChildren();
if(!_chipCount) {
_chipCount = new ChipCountContainer();
this.addChild(_chipCount);
}
}
public function setChipCount(labelText:String):void {
_chipCount._chipCountLabel.text = labelText;
invalidateDisplayList();
}
}
}
Here is ChipCountContainer.as:
package view {
import mx.containers.Canvas;
public dynamic class ChipCountContainer extends Canvas {
/** The label. */
public var _chipCountLabel:ChipCountLabel;
public function ChipCountContainer() {
super();
this.width = 20;
this.height = 20;
}
override protected function createChildren():void {
super.createChildren();
if(!_chipCountLabel) {
_chipCountLabel = new ChipCountLabel();
this.addChild(_chipCountLabel);
}
}
}
}
I've methodically moved things around and waved the invalidate Display List incense while performing a create Children dance but I've only succeeded in completely confusing myself. I've searched the Flex libraries for similar constructions, and it looks OK to me, but I guess I'm just not getting the concept.
I think you're confusing the order of instantiation. Namely, if you want to use setChipCount after the children of the component have been initialized, you should wait for the initialize event to fire, i.e.:
public dynamic class MainDeckScoreBoard extends ScoreBoard {
...
public function MainDeckScoreBoard( lock:Class ) {
super();
// Verify that the lock is the correct class reference.
if ( lock != SingletonLock ) {
throw new Error( "Invalid Singleton access. Use MainDeckScoreBoard.instance." );
}
// wait for the children to be created
addEventListener(FlexEvent.INITIALIZE, onInitialize);
}
// executes when the children of this component have been created
private function onInitialize(event:FlexEvent):void {
this.setChipCount("0");
}
} // end class
For a more detailed explanation of the component instantiation lifecycle, this adobe doc may be helpful:
http://livedocs.adobe.com/flex/3/html/help.html?content=components_06.html

Resources