Receiving Error 1026 in AS3 and do not know why - actionscript-3

I am getting error 1026 which is "Constructor functions must be instance methods" and I don't know why. I am creating a media player type program and am having trouble with my music portion. I made a function music player before this and copied the code over to my new project. The only thing that is different now is that the code is in a state and not the main.mxml file. This is my code below and I am receiving the error where it says "public var music:Sound;" I don't see why I am getting this error and any help would be appreciated!
<fx:Declarations>
<fx:XML id="musicXML" source="data/musak.xml" />
<s:XMLListCollection id="musicCollection" source="{musicXML.song}" />
</fx:Declarations>
<s:HGroup>
<s:DataGrid id="musicGrid" dataProvider="{musicCollection}" click="onClick()" />
<local:MusicPosition id="mProgress" width="319" height="83"/>
<s:VGroup height="55">
<s:Label text="Now playing: {musicGrid.selectedItem.#name}" />
<s:Label id="txtPosition" width="91"/>
</s:VGroup>
</s:HGroup>
<s:Button x="146" y="93" label="play" click="playMusic()"/>
<s:Button x="270" y="93" label="pause" click="pauseMusic()"/>
<fx:Script>
<![CDATA[
//set your variables
public var music:Sound;
[Bindable]public var musicChannel:SoundChannel;
public var pausedTime:Number = 0;
public function onClick():void {
if(musicChannel) {
musicChannel.stop();
//clean up the variables
music = null;
musicChannel = null;
}
music = new Sound();
music.load(new URLRequest(musicGrid.selectedItem.file.toString()));
music.addEventListener(Event.COMPLETE, onMusicLoad);
}
public function onMusicLoad(e:Event):void {
mProgress.update(0);
//new channel
musicChannel = music.play();
}
protected function onE(e:Event):void {
if(musicChannel) {
txtPosition.text = millisecondsToSeconds(musicChannel.position).toString() + "/" +
millisecondsToSeconds(music.length).toString();
mProgress.update(musicChannel.position/music.length);
mProgress.alpha = 1;
} else
mProgress.alpha = 0;
}
protected function millisecondsToSeconds(milliseconds:Number):Number {
return Math.round(milliseconds/1000);
}
public function pauseMusic():void {
if(musicChannel) {
pausedTime = musicChannel.position;
musicChannel.stop();
}
}
public function playMusic():void {
if(musicChannel) {
musicChannel = music.play(pausedTime);
}
}
]]>
</fx:Script>

Be very careful when naming thing. You cannot create a variable, or method, inside your class that is the same name as the class itself.
A common--but not required--naming convention is this:
Use CamelCase for classes. In this case, your class would be named either Music.mxml or music.as. Based on your code, it seems you already follow this convention with your MusicPosition class.
Use camelcase for method, but make the first letter lowercase. Your variable could be named music in this case. Or, you may create a variable named musicPosition. Remember in Flex, the id attribute of an MXML tag is the equivalent of a variable name.
For constants, use all uppercase. Constants are commonly used as event types.
Once, again, these are common conventions [in programming languages beyond Flex/ActionSCript] but are not required or enforced by the Flex SDK.

Related

Binding in Flex: How to make a variable automatically update when another variable is changed?

I know that it is possible to make a parameter of a component depend on a variable, provided that variable contains the [Bindable] tag. This means that updating the value of the Bindable variable automatically updates the component.
Is it possible to make another variable depend on a Bindable variable?
In the example below I have a variable btnClicked that is bound. When btnClicked is changed by the function btnClick() being called, the text in the TextArea is updated as expected.
I would like to be able to make another variable, btnText, be updated when btnClicked is updated. I do not know how to communicate this dependency. In the code below the value of btnText is initially "clickMe" as expected. However, when btnClicked changes, the text on the button does not update to "unclickMe".
<fx:Script>
<![CDATA[
[Bindable]
public var btnClicked:Boolean = false;
public function btnClick():void{
btnClicked = !btnClicked;
}
[Bindable]
public function get btnText():String{
return btnClicked?"unclickMe":"clickMe";
}
]]>
</fx:Script>
<s:Button click="btnClick()" label="{btnText}"/>
<s:TextArea y="50" text="{btnClicked?'Button is clicked':'Button is unclicked'}"/>
How can I change the code above so that btnText automatically updates when btnClicked is changed?
Would it be possible to have an arbitrarily long chain of connected variables each of which updates when the previous one updates?
You can also use a ChangeWatcher to detect when your bindable property is updated :
<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" creationComplete="init(event)">
<fx:Script>
<![CDATA[
import mx.binding.utils.ChangeWatcher;
import mx.events.FlexEvent;
public var watcher:ChangeWatcher;
[Bindable]
public var btnClicked:Boolean = false;
[Bindable]
public var btnText:String = 'clickMe';
protected function btnClick():void {
btnClicked = !btnClicked;
}
protected function init(event:FlexEvent):void
{
watcher = ChangeWatcher.watch(this, 'btnClicked', watcherListener);
}
protected function watcherListener(event:Event):void {
btnText = btnClicked ? 'unclickMe' : 'clickMe';
}
]]>
</fx:Script>
<s:Button x="303" y="30" label="{btnText}" click="btnClick()"/>
<s:TextArea x="303" id="txt" y="96" text="{btnClicked ? 'Button is clicked' : 'Button is unclicked'}"/>
</s:Application>
Hope that can help.
In this case, all you have to do is update your btnClick function to dispatch a PropertyChangeEvent:
public function btnClick():void{
btnClicked = !btnClicked;
dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE));
}
This works because of the way [Bindable] works - see What does [Bindable] mean in actionscript? for a nice explanation.
Using the Bindable metadata tag and Binding to functions, Objects, and Arrays are good resources for background reading, too.
Edit: Don't forget the import statement!
import mx.events.PropertyChangeEvent;
Flash Builder will insert the import statement for you if you ctrl-space while typing PropertyChangeEvent.
I have found a solution, but if someone has a cleaner solution that makes use of in built Flex features please post it.
The following code updates the value of btnText each time the value of btnClicked is changed. It does this by having a setter function for btnClicked that explicitly calls function updateBtnText. See this explanation for more information about how getters and setters allow you to call other functions any time a variable is read or written.
<fx:Script>
<![CDATA[
private var _btnClicked:Boolean = false;
[Bindable]
public function get btnClicked():Boolean{
return _btnClicked;
}
public function set btnClicked(newBtnClicked:Boolean):void{
_btnClicked = newBtnClicked;
updateBtnText();
}
private function updateBtnText():void{
btnText = btnClicked?"unclickMe":"clickMe";
}
public function btnClick():void{
btnClicked = !btnClicked;
}
[Bindable]
public var btnText:String = btnClicked?"unclickMe":"clickMe";
]]>
</fx:Script>
<s:Button click="btnClick()" label="{btnText}"/>
<s:TextArea y="50" text="{btnClicked?'Button is clicked':'Button is unclicked'}"/>

How to add dynamic objects to bindable ArrayCollection in Flex?

I have an ArrayCollection that serves as dataprovider for a TabBar.
Each item added must have two properties: a label and a description.
I define these items dynamically as follows:
[Bindable] //required to serve as data provider
private var mybar:ArrayCollection;
public function init() {
mybar = new ArrayCollection();
mybar.addItem({label: "Test1", description: "long test test"});
}
<s:TabBar dataProvider="{mybar}">
<s:ItemRenderer>
<s:ButtonBarButton label="{data.label}" /> //description might also be used here, but omitted
</s:ItemRenderer>
</s:TabBar>
Problem: as the properties "label" and "description" are not set [Bindable], there is the following error log:
warning: unable to bind to property 'label' on class 'Object' (class is not an IEventDispatcher)
warning: unable to bind to property 'description' on class 'Object' (class is not an IEventDispatcher)
How could I prevent this?
The warning disappears if I use ObjectProxy:
mybar.addItem(new ObjectProxy( {label: "Test1", description: "long test test"}));
But is that correct?
The way to get rid of the warning would be using an custom class with Bindable properties.
[Bindable]
public class BarData
{
public var label:String;
public var description:String;
public function BarData(label:String, description:String)
{
this.label = label;
this.description = description;
}
}
and to do this to initialize it
public function init():void {
mybar = new ArrayCollection();
mybar.addItem(new BarData("Test1", "some description"));
mybar.addItem(new BarData("Test2", "some description"));
}
another way as described above wrap it in an ObjectProxy:
public function init():void {
mybar = new ArrayCollection();
mybar.addItem(new ObjectProxy({label:"Test1", description:"some description"}));
mybar.addItem(new ObjectProxy({label:"Test2", description:"some description"}));
}
I'm curious which SDK you're using because in my FlashBuilder, with SDK 4.7, the way you define your TabBar is leading to disappointing results. I have to do this to get it working:
<s:TabBar dataProvider="{mybar}">
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer>
<s:ButtonBarButton label="{data.label}" />
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:TabBar>
still more easy is defining it this way:
<s:TabBar dataProvider="{mybar}" />
the item renderer is not really adding extra functionality here so you could just do it this way.
Hope this helps.

Script copied from adobe adobe tutorial and still not working zero result

This is a script which asks for and validate a user
name against a predefined list of names.
I copied the whole script from tutorial but result is nothing i cannot even understand why no errors ! I learn by first copying the script and afterward understanding it but unfortunately the result is nothing with no errors ! i am new to programming so please try to explain things
script in frame 1 :
var myGreeter:Greeter = new Greeter();
mainText.text = myGreeter.sayHello("")
script in an action script file named greeter:
package
{
public class Greeter
{
/**
* Defines the names that should receive a proper greeting.
*/
public static var validNames:Array = ["Sammy", "Frank", "Dean"];
/**
* Builds a greeting string using the given name.
*/
public function sayHello(userName:String = ""):String
{
var greeting:String;
if (userName == "")
{
greeting = "Hello. Please type your user name, and then press the Enter key.";
}
else if (validName(userName))
{
greeting = "Hello, " + userName + ".";
}
else
{
greeting = "Sorry, " + userName + ", you are not on the list.";
}
return greeting;
}
/**
* Checks whether a name is in the validNames list.
*/
public static function validName(inputName:String = ""):Boolean
{
if (validNames.indexOf(inputName) > -1)
{
return true;
}
else
{
return false;
}
}
}
}
Presumably you're referencing Adobe's Getting started with ActionScript: Creating a basic application.
This older tutorial is more geared towards Flex 3, in which you would implement a front-end presentation to wire to the Greeter class.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
layout="vertical"
creationComplete="initApp()">
<mx:Script>
<![CDATA[
private var myGreeter:Greeter = new Greeter();
public function initApp():void
{
// says hello at the start, and asks for the user's name
mainTxt.text = myGreeter.sayHello();
}
]]>
</mx:Script>
<mx:TextArea id="mainTxt" width="400" backgroundColor="#DDDDDD"
editable="false"/>
<mx:HBox width="400">
<mx:Label text="User Name:"/>
<mx:TextInput id="userNameTxt" width="100%"
enter="mainTxt.text=myGreeter.sayHello(userNameTxt.text);"/>
</mx:HBox>
</mx:Application>
By simply pasting the Greeter class, you would not receive errors since no part of this class is executing. Nothing from that class is being called.
This is a rather poor tutorial, and combined with being dated it would be advisable to look elsewhere for tutorials and examples such as:
ActionScript Technology Center
Adobe Developer Connection
Wonderfl.net

how to work with event in Flex?

import flash.events.Event;
public class RequestEvent extends Event
{
public static const REQUEST:String = "request";
private var Results:Boolean;
public function get Results():Boolean
{
return _Results;
}
public function RequestEvent(Results:Boolean=false)
{
super(REQUEST);
Results = Results;
}
override public function clone():Event
{
return new RequestEvent(Results);
}
}
}
hi can some body explain why we are doing overridding of function clone and calling super(request), new in flex ........so don't mind.
One needs to implement the clone method just so that Flex could re-clone the event in the case when an event handler wishes to dispatch the same event again. Flex does provide a default implementation but one may override the method to clone the event differently, if need be.
As for calling the super method, you must call the super becasue you are extending the Event class. The type (in your case, REQUEST) must be a unique string that would uniquely identify the event to Flex platform.
Hope it helps
Regards.
The question about the overriding of the clone method in custom events is very popular and it seems to be one of the Flex strange things. You can read about it here.
So you have to override this method and only in this method you can define values of custom properties. The method is not usual, so if you try to debug it you will never get the debugger in its body.
If you try to define the value of your custom property in the constructor, the value will be ignorred.
It can be unpractical to use a constant string as the event's type value. In this case all instances of your RequestEvent are of the same type and you could not tell them appart using in different situations. As you can see in the example below, this string is used in action listener to map the listener function.
In this example I have three buttons with different events - normal Event, my version of RequestEvent and your version of it. Have a look at it, I hope it can help to understand the case.
//Application
<fx:Script>
<![CDATA[
import fld02.com.customevent.RequestEvent;
import fld02.com.customevent.RequestEvent2;
import mx.controls.Alert;
private function onCustomGroupBtn2Clicked(evt:RequestEvent):void
{
Alert.show('Btn2Clicked: results = ' + evt.results.toString(), 'This is RequestEvent');
}
private function onCustomGroupBtn3Clicked(evt:RequestEvent2):void
{
Alert.show('Btn3Clicked: Results = ' + evt.Results.toString(), 'This is your RequestEvent');
}
]]>
</fx:Script>
<customevent:CustomGroup
BUTTON1_CLICKED="{Alert.show('Btn1Clicked', 'This is Event')}"
BUTTON2_CLICKED="onCustomGroupBtn2Clicked(event)"
request="onCustomGroupBtn3Clicked(event)"/>
</s:Application>
//CustomGroup
<?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="346" height="144">
<fx:Metadata>
[Event(name="BUTTON1_CLICKED", type="flash.events.Event")]
[Event(name="BUTTON2_CLICKED", type="fld02.com.customevent.RequestEvent")]
[Event(name="request", type="fld02.com.customevent.RequestEvent2")]
</fx:Metadata>
<fx:Script>
<![CDATA[
private function onBtn1Click():void
{
this.dispatchEvent(new Event("BUTTON1_CLICKED"));
}
private function onBtn2Click():void
{
var requestEvent:RequestEvent = new RequestEvent("BUTTON2_CLICKED");
requestEvent.results = true;
this.dispatchEvent(requestEvent);
}
]]>
</fx:Script>
<s:Button x="43" y="31" width="183" label="Generate Event" click="onBtn1Click()"/>
<s:Button x="43" y="62" width="183" label="Generate RequestEvent" click="onBtn2Click()"/>
<s:Button x="43" y="93" width="183" label="Generate Your RequestEvent" click="{this.dispatchEvent(new RequestEvent2(true))}"/>
</s:Group>
//My RequestEvent
package fld02.com.customevent
{
import flash.events.Event;
public class RequestEvent extends Event
{
private var _results:Boolean;
public function RequestEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
override public function clone():Event
{
var requestEvent:RequestEvent = new RequestEvent(this.type);
requestEvent.results = this.results;
return requestEvent;
}
public function get results():Boolean
{
return _results;
}
public function set results(value:Boolean):void
{
_results = value;
}
}
}
//Your RequestEvent
package fld02.com.customevent
{
import flash.events.Event;
public class RequestEvent2 extends Event
{
public static const REQUEST:String = "request";
public function RequestEvent2(Results:Boolean=false)
{
super(REQUEST);
Results = Results;
}
private var _Results:Boolean;
public function get Results():Boolean
{
return _Results;
}
override public function clone():Event
{
return new RequestEvent2(Results);
}
}
}

Flex3: Custom Item Renderer does not listen to events dispatched by parent

I have a List with a custom ItemRenderer. The ItemRenderer contains a Checkbox and a Label.
The component with the List has a 'select all' checkbox.
When the 'select all' checkbox is checked, it dispatches an event that each item should listen to in order to select its own checkbox.
The eventlistener is added on creationComplete of each item, and the event is dispatched correctly when the 'select all' checkbox is selected, but the listener in the custom ItemRenderer does not listen.
How do I make the ItemRenderer listen to an event that is dispatched in its parent??
I'll add some code examples to clarify:
------- container ----------
<mx:VBox>
<mx:Script>
<![CDATA[
public var user1 = new User(1, "Jack");
public var user2 = new User(2, "John");
public var user3 = new User(3, "Mary");
[Bindable]
public var users:ArrayCollection = new ArrayCollection([user1], [user2], [user3]);
public static const SELECT_ALL_USERS:String = "selectAllUsers";
private function selectAllChangeHandler():void
{
if (selectAll.selected)
dispatchEvent(new Event(SELECT_ALL_USERS,true));
}
]]>
</mx:Script>
<mx:CheckBox id="selectAll" change="{selectAllChangeHandler()}" />
<mx:List dataProvider="{users}" itemRenderer="myRenderer" />
</mx:VBox>
------- renderer ----------
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox creationComplete="{init()}">
<mx:Script>
<![CDATA[
private function init():void
{
addEventListener (Container.SELECT_ALL, selectAllHandler, false, 0, true);
}
private function selectAllHandler():void
{
checkbox.selected=true;
}
private function selected(id:int):Boolean
{
return id==1 || id==3;
}
]]>
</mx:Script>
<mx:CheckBox id="checkbox" selected="{selected(data.id)}" />
<mx:Label text="{data.name}" />
</mx:HBox>
Please note that the users ArrayCollection or its containing user objects cannot be changed because I need the values later on.
So when 'selectAll' is clicked, each checkbox in the list should also be checked.
Your custom ItemRenderers should not register an event listener with their parent, but with your "select all" checkbox, i.e.
theCheckbox.addEventListener(YourEvent.YOUR_EVENT, itemRendererSelectAllHandler);
Failing that, can you post your code which adds the event listener and which dispatches the event form the checkbox?
edit:
Here's your bug: In renderer's init(), you need to add an event listener not to the renderer, but to the container which dispatches the event. So make that a
container.addEventListener(Container.SELECT_ALL_USERS, selectAllHandler, false, 0, true);
Doing select all in flex is little complex but I will tell you the way we did it and it works great.
We created a List derived control called "ExList" which has a property "selectAllCB" which we bind it to existing check box which will work for select all logic. Please note, when we set selectAllCB property, we make ExList to listen to checkbox's events.
When checkbox is checked, we manually set selectedItems array to array of dataProvider and all items are selected.
Playing with itemRenderer doesnt work correctly because when you program your list again and again everytime you have to write so much of code.
I am attaching some sample code here below..
public class ExList extends List
{
public function ExTileList()
{
super();
this.allowMultipleSelection = true;
}
private var _selectAllCB:CheckBox = null;
[Bindable]
public function get selectAllCB():CheckBox
{
return _selectAllCB;
}
public function set selectAllCB(v:CheckBox):void
{
if(v==null)
return;
_selectAllCB = v;
v.addEventListener(ListEvent.ITEM_CLICK, handleAllChange,false, 0 , true);
v.addEventListener("change", handleAllChange,false, 0 , true);
}
private function handleAllChange(e:Event):void
{
if(_selectAllCB.selected)
{
this.selectedItems = this.dataProvider.toArray();
}
else
{
this.selectedItems = new Array();
}
}
}
And you can use it as...
<CheckBox id="sAll"/>
<ExList selectAllCB="{sAll}"/>
// Please note its in curly braces
This is how I achieved the solution:
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" height="150" verticalGap="0">
<mx:Script>
<![CDATA[
import mx.events.ListEvent;
import mx.controls.CheckBox;
import mx.collections.ArrayCollection;
public var listData:ArrayCollection;
private function selectAll():void
{
listChkBox.selectedItems = listData.toArray();
for each (var item:Object in listChkBox.selectedItems)
{
CheckBox(listChkBox.itemToItemRenderer(item)).selected = true;
}
}
private function resetAll():void
{
listChkBox.selectedItems = listData.toArray();
for each (var item:Object in listChkBox.selectedItems)
{
CheckBox(listChkBox.itemToItemRenderer(item)).selected = false;
}
}
]]>
</mx:Script>
<mx:List width="100%" height="100%" id="listChkBox" labelField="name" allowMultipleSelection="true"
dataProvider="{listData}" selectionColor="#FFFFFF" >
<mx:itemRenderer>
<mx:Component>
<mx:CheckBox >
</mx:CheckBox>
</mx:Component>
</mx:itemRenderer>
</mx:List>
<mx:HBox width="100%" backgroundColor="#E2DEDE" paddingBottom="2" paddingLeft="2" paddingTop="2" paddingRight="2" borderStyle="solid">
<mx:Button label="All" id="btnAll" click="selectAll()" />
<mx:Button label="None" click="resetAll()"/>
</mx:HBox>
</mx:VBox>
The simple solution is to use typed objects in the list of data you are presenting and then take advantage of databinding and the binding utils to capture changes to the underlying data property on the item renderer. Override the 'set data' function in the item renderer to do whatever you need when some property in the object gets changed to reflect the 'select all/de select all' state.