I have a Flex ActionScript Application, I need to draw a simple rectangle in stage. I am using
firstapp.mxml and another Class called Book.as;
here is the complete code which i have done.
firstapp.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute">
<mx:Script>
<![CDATA[
import com.books.Book;
import flash.display.*;
var n:Book = new Book;
//n.var1 = "Another String";
addChild(n);
]]>
</mx:Script>
</mx:Application>
Book.as
package com.books
{
import flash.display.*;
public class Book extends Sprite
{
public var var1:String = "Test Var";
public var var2:Number = 1000;
public function Book()
{
var b = new Sprite;
b.graphics.beginFill(0xFF0000, 1);
b.graphics.drawRect(0, 0, 500, 200);
b.graphics.endFill();
addChild(b);
}
}
}
I'm new in Flex, So please help me to fix this. I want to show the rectangle.
Since you're trying to add this to a flex component, you probably need to wrap Book in a UIComponent instance:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute">
<mx:Script>
<![CDATA[
import com.books.Book;
import flash.display.*;
var n:UIComponent = new UIComponent;
n.addChild(new Book);
addChild(n);
]]>
</mx:Script>
</mx:Application>
Another way of doing this would be to instead make Book inherit UIComponent, like so:
package com.books
{
import flash.display.*;
public class Book extends UIComponent
{
public var var1:String = "Test Var";
public var var2:Number = 1000;
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
graphics.beginFill(0xff0000, 1);
graphics.drawRect(0, 0, 500, 200);
graphics.endfill();
}
}
}
Then you can add Book directly to your application, like so:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:books="com.books.*"
layout="absolute">
<books:Book />
</mx:Application>
Additionally, I suggest you read up on the Flex component architecture. There's some pretty good documentation from Adobe on the subject, but you should be aware that the information is specific to Flex 3 (I noticed you're using Flex 3, hence the link). Even while a lot of the information may still be applicable to Flex 4 (the component lifecycle for instance) there are differences, especially in terms of skinning.
USE var n:Book = new Book(); instead of var n:Book = new Book;
macke showed you good way. But if you want just to show something quickly, change
addChild(b);
to
rawChildren.addChild(b);
Edit: Some clarifications: application is UIComponent, therefore its addChild method needs UIComponent. You want to add Sprite. This can be done with rawChildren.addChild method from application. rawChildren is useful to get Sprites work with UIComponents, but you have to manage sprites yourself (sizes and layout).
Related
I am working on a flex web project where a lot of the functionality is modular and the SWFs are loaded with SWFLoader. I've recently created a module which has tooltips on some elements and I was getting a runtime error #1009 when hovering over these elements to see the tooltip. If, instead of loading the SWF with SWFLoader at runtime, I instantiate it in the application directly, the tooltips work fine. Does anyone know why this is?
I'm using Flex SDK 4.5.1 because one of the libs I have to use doesn't work with later versions.
I've isolated the issue into a small example. Here's the code:
main 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="955" minHeight="600"
backgroundColor="#000000"
creationComplete="onComplete(event);">
<fx:Script>
<![CDATA[
import mx.controls.SWFLoader;
import mx.events.FlexEvent;
private function onComplete(event:FlexEvent):void {
// Comment this block out to try without loading external swf
var swfLoader:SWFLoader = new SWFLoader();
swfLoader.addEventListener(Event.COMPLETE, swfLoadComplete);
swfLoader.load("ExternalSWF.swf");
// Uncomment this block to try without loading external swf ... Notice the tooltips suddenly work..
/*var externalSwf:ExternalSWF = new ExternalSWF();
this.addElement(externalSwf);*/
}
private function swfLoadComplete(event:Event):void {
var externalSwf:ExternalSWF = (event.target as SWFLoader).content as ExternalSWF;
this.addElement(externalSwf);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
ExternalSWF class (in flash builder 4.7, this is set to compile as a module):
package
{
import spark.components.Button;
import spark.components.VGroup;
[Frame(factoryClass="ExternalSWF")]
public class ExternalSWF extends VGroup
{
public function ExternalSWF()
{
super();
var btn:Button = new Button();
btn.label = "mouse over this";
btn.toolTip = "moused over";
this.addElement(btn);
}
}
}
Thanks, Zeus. That set me on the correct path and I was able to solve my problem.
Here's one solution:
main mxml AS code:
private var _info:IModuleInfo;
private function onComplete(event:FlexEvent):void {
_info = ModuleManager.getModule("ExternalSWF.swf");
_info.addEventListener(ModuleEvent.READY, modEventHandler);
_info.load(null, null, null, moduleFactory);
}
private function modEventHandler(event:ModuleEvent):void {
var externalSwf:ExternalSWF = _info.factory.create() as ExternalSWF;
this.addElement(externalSwf);
}
ExternalSWF
package
{
import mx.controls.Button;
import spark.modules.Module;
public class ExternalSWF extends Module
{
public function ExternalSWF()
{
super();
var btn:Button = new Button();
btn.label = "mouse over this";
btn.toolTip = "moused over";
this.addElement(btn);
}
}
}
I have a flex application and a papervision BasicView. I would like to add a new flex UIComponent (such as a button) from within the papervision class. I have posted the full example code below. It works but I would like to be able to accomplish my goal without the "(this.parent.parent as Group).addElement(button);" line.
<!--Application 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="50" minHeight="50"
creationComplete="Init()" applicationComplete="Start()">
<fx:Script>
<![CDATA[
import mx.core.UIComponent;
import spark.components.Button;
public var start:QuickStart;
public function Init():void
{
start = new QuickStart();
var uicomp:UIComponent = new UIComponent();
addElement( uicomp );
uicomp.addChild( start );
}
public function Start():void
{
start.GoTime();
}
]]>
</fx:Script>
</s:Application>
//QuickStart.as
package{
import org.papervision3d.view.BasicView;
public class QuickStart extends BasicView
{
public function QuickStart()
{
super(500, 500, true, true);
}
public function GoTime():void
{
var button:Button = new Button;
//this is the offending line
(this.parent.parent as Group).addElement(button);
}
}
}
The version I have does work so please excuse any minor typos.
Logically you would dispatch an event inside your BasicView, listen for it in your main application, and create the button from up there. In a prefect OOP world, every class should be a black box sending events :)
I need to dynamically bind properties of components created at runtime. In this particular case please assume I need to use bindProperty.
I don't quite understand why the following simplistic test is failing (see code). When I click the button, the label text does not change.
I realize that there are simpler ways to go about this particular example using traditional non-dynamic binding, but I need to understand it in terms of using bindProperty.
Can someone please help me understand what I'm missing?
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:ns1="Tools.*" minWidth="684" minHeight="484" xmlns:ns2="*" creationComplete="Init();">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.binding.utils.*;
public var Available:ArrayCollection=new ArrayCollection();
public function get Value():String {
return (Available.getItemAt(0).toString());
}
public function Init():void {
Available.addItemAt('Before', 0);
BindingUtils.bindProperty(Lab, 'text', this, 'Value');
}
public function Test():void {
Available.setItemAt('After', 0);
}
]]>
</mx:Script>
<mx:Label x="142" y="51" id="Lab"/>
<mx:Button x="142" y="157" label="Button" click="Test();"/>
</mx:WindowedApplication>
Thanks in advance.
As mentioned by Glenn, you need to add [Bindable] tag on Value.
Also, you haven't defined a setter for the property. Data binding is invoked only when the corresponding setter is called. The flow is something like: you call the setter - Flex updates the data by calling the getter.
[Bindable]
public function get value():String {
return (Available.getItemAt(0).toString());
}
public function set value(v:String):void {
Available.setItemAt(v, 0);
}
public function init():void {
Available.addItemAt('Before', 0);
BindingUtils.bindProperty(Lab, 'text', this, 'Value');
}
public function iest():void {
value = "After";
}
Note that I've changed names of functions and properties to lowercase as per the normal convention. InitialCaps are used only for class names.
I never use the BindingUtils, but my first guess is that you're missing the [Bindable] tag on "Value".
I'm having trouble to resize my custom UIComponent that wrap flash.media.Video object (The reason I choose this way is because mx.control.VideoDisplay doesn't support streaming playback that available in flash.media.Video that is attachNetStream()). Once I create a 320x240 Video size and remove it from its parent, I can't replace it with another one, bigger or smaller.
Here's my code (this one only capture Camera not NetStream).
package media
{
import flash.media.Camera;
import flash.media.Video;
import mx.controls.VideoDisplay;
import mx.core.UIComponent;
public class VideoUI extends UIComponent
{
private var video:Video;
public function VideoUI(width:int, height:int)
{
super();
video = new Video(width, height);
var cam:Camera = Camera.getCamera();
video.attachCamera(cam);
addChild(video);
}
}
}
The other part,
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import media.VideoUI;
private function addVideoOutput():void
{
// initial video size
var video:VideoUI = new VideoUI(160,120);
HBoxVideo.addChild(video);
}
protected function resizeVideo(event:MouseEvent):void
{
var videoList:Array = HBoxVideo.getChildren();
for (var i:int = 0; i < videoList.length; i++)
{
var video:VideoUI = videoList.pop();
HBoxVideo.removeChild(video);
// new size that produce the previous size :(
video = new VideoUI(320, 240);
HBoxVideo.addChild(video);
}
}
]]>
</mx:Script>
<mx:Button click="addVideoOutput()" x="10" y="265" label="add"/>
<mx:HBox x="10" y="10" width="100%" id="HBoxVideo">
</mx:HBox>
<mx:Button x="58" y="265" label="resize" click="resizeVideo(event)" id="resizeButton"/>
</mx:Application>
Thank you very much.
By default, new instances of the Video class are 320 pixels wide by 240 pixels high. You will need access to your video in the VideoUI Class so that you can change the width and height.
As follows:
Change all appearances of your video variable in VideoUI.as to
_video
and apply a getter.
New Video UI Class
package media
{
import flash.media.Camera;
import flash.media.Video;
import mx.core.UIComponent;
public class VideoUI extends UIComponent
{
private var _video:Video;
public function VideoUI(width:int, height:int)
{
super();
_video = new Video(width, height);
var cam:Camera = Camera.getCamera();
_video.attachCamera(cam);
addChild(_video);
}
public function get video():Video{
return _video;
}
}
}
Replace in your main mxml file
video = new VideoUI(320, 240);
with
video.video.width=320;
video.video.height=240;
Note: You should rename your VideoUI instance to videoui or the sorts. It is a little confusing. You can also move this to your VideoUI Class or make a method. The choice is yours.
I am having a problem with binding values in my ActionScript components. I basically want to set the value of a a variable in my component to a value in the model, and have the component variable automatically update when the model value is updated. I think that I just don't fully understand how data binding works in Flex - this is not a problem when using MXML components, but, when using ActionScript classes, the binding does not work.
This is the code I'm using, where the values are not binding:
package
{
public class Type1Lists extends TwoLists
{
public function Type1Lists()
{
super();
super.availableEntities = super.composite.availableType1Entities;
super.selectedEntities = super.composite.selectedType1Entities;
}
}
}
package
{
public class Type2Lists extends TwoLists
{
public function Type2Lists()
{
super();
super.availableEntities = super.composite.availableType2Entities;
super.selectedEntities = super.composite.selectedType2Entities;
}
}
}
/* TwoLists.mxml */
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public var __model:ModelLocator = ModelLocator.getInstance();
public var composite:Composite =
__model.selectedComposite;
[Bindable]
public var availableEntities:ArrayCollection;
[Bindable]
public var selectedEntities:ArrayCollection;
]]>
</mx:Script>
<mx:List id="availableEntitiesList" dataProvider="{availableEntities}" />
<mx:List id="selectedEntitiesList" dataProvider="{selectedEntities}" />
</mx:HBox>
To use binding by code you should use mx.binding.utils.*
Take a look and the BindingUtils.bindProperty and bindSetter methods.
Also, be careful with manual databinding, it could lead you to memory leaks.
To avoid them, save the ChangeWatcher returned by bindProperty and bindSetter and call watcher's unwatch method when is no more used (i.e, in the dipose or destructor method)
You need to add the [Bindable] tag either to the class itself (making all properties bindable) or the properties you want to be [Bindable]. Marking properties or objects as [Bindable] in your MXML is not sufficient.
To fix this, I simply converted the classes to MXML components, and added a private variable for my ModelLocator.
/* Type1Lists.mxml */
<?xml version="1.0" encoding="utf-8"?>
<TwoLists xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="*"
availableEntities="{__model.selectedComposite.availableType1Entities}"
selectedEntities="{__model.selectedComposite.selectedType1Entities}">
<mx:Script>
<![CDATA[
import model.ModelLocator;
[Bindable]
private var __model:ModelLocator = ModelLocator.getInstance();
</mx:Script>
</TwoLists>
/* Type2Lists.mxml */
<?xml version="1.0" encoding="utf-8"?>
<TwoLists xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="*"
availableEntities="{__model.selectedComposite.availableType2Entities}"
selectedEntities="{__model.selectedComposite.selectedType2Entities}">
<mx:Script>
<![CDATA[
import model.ModelLocator;
[Bindable]
private var __model:ModelLocator = ModelLocator.getInstance();
</mx:Script>
</TwoLists>