I'm writing a Flex application using Flash Builder 4 and I'm having a bit of trouble with an AS3 object. Essentially, it is a BorderContainer, with a few buttons and images, and programming logic that determines how these interact with eachother and a database.
What I want to be able to do is configure the layout/style of the inner components using MXML and CSS. I can configure the inherited objects, but not ones that I have defined...
For example, in my MXML. I can modify the (inherited) borderstroke variable of myContainer like so;
<IE:MyContainer>
<IE:borderStroke>
<s:LinearGradientStroke weight="10" rotation="270">
<s:GradientEntry color="0xF655E5"/>
<s:GradientEntry color="0x6600CC"/>
</s:LinearGradientStroke>
</IE:borderStroke>
</IE:MyContainer>
However, I can't edit the nextButton variable (which is of type Button) like this;
<IE:MyContainer>
<IE:nextButton width="100" height="30" left="10%" bottom="10%"/>
</IE:MyContainer>
If I try, I get the compile error "Could not resolve to a component implementation".
What do I need to do to make this work?!
Thanks in advance,
Aidan
EDIT:
Here's the main method of MyContainer (actually named InvestigativeEnvironment).
The call to defineTestInvestigativeEnvironment() is what takes care of setting up the objects and action listeners and such. What I want to do is change the layout and appearance of these visual components in MXML (nextButton, prevButton, toolbox, displayArea). I want to be able to set their height, width, background, x, y, horizontalCenter, etc like I can to a button that I add to a container via MXML.
public class InvestigativeEnvironment extends BorderContainer
{
private var toolbox:Toolbox;
private var bodySystem:BodySystem;
public var nextButton:Button;
public var prevButton:Button;
private var displayArea:Group;
private var image:Image;
private var toolDisplayArea:Group;
public function InvestigativeEnvironment()
{
super();
//create 'Next' button and event listener
nextButton = new Button();
nextButton.addEventListener(MouseEvent.CLICK, nextViewAngle);
nextButton.label = "Next";
this.addElement(nextButton);
//create 'Prev' button and event listener
prevButton = new Button();
prevButton.addEventListener(MouseEvent.CLICK, prevViewAngle);
prevButton.label = "Prev";
this.addElement(prevButton);
//define investigative environment by creating models.
defineTestInvestigativeEnvironment();
//Instantiate the Group that contains the model image and tool overlays
displayArea=new Group();
//Instantiate the image that is used to display the model
image = new Image();
image.source=bodySystem.getImage();
image.horizontalCenter=0;
image.verticalCenter=0;
displayArea.addElement(image);
//add toolOverlayContainer to the display area ABOVE the model image
toolDisplayArea = new Group();
toolDisplayArea.verticalCenter=0;
toolDisplayArea.horizontalCenter=0;
displayArea.addElement(toolDisplayArea);
this.addElement(displayArea);
//add toolbox to display
toolbox = new Toolbox(toolDisplayArea);
toolbox.replaceTools(bodySystem.getToolGroup());
this.addElement(toolbox);
}
I can't understand what is your problem with editing button in particular, sorry for that. But I have a lot of notices about your InvestigativeEnvironment which code you've attached.
First, you haven't follow Flex components livecycle (see here or here). So in your code you should add and configure children in createChildren() method.
But anyway you can't use your container to add children both with MXML and from code. If your adding custom components code will be executed first MXML (in your implementation with adding them in constructor it is so) all the MXML tags just remove all your added content (anyway result will be unpredictable). In other case it will be very hard to control instance's order.
I can suggest you to declare your nextButton etc as skin parts and perform their positioning in skin. This way these internal controls will be a part of border and you can add MXML children without any problem. And you can configure them within partAdded() method.
It turns out that I wasn't quite asking the right question. I wanted to edit the components, but specifically the layout and color type attributes of them.
What I need to do is set the id of the components, and then target them using CSS.
For my nextButton, I add the ID like this;
nextButton.id="nextButton";
Then I can lay it out in the MXML file (or external stylesheet) like this;
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace IE "InvestigativeEnvironment.*";
IE|InvestigativeEnvironment s|Button {
chromeColor: #336666;
}
#nextButton {
bottom: 100;
right: 5;
}
</fx:Style>
Related
I have defined a renderer with some Labels, TextInputs and Buttons and call "setStyle" to set their colors and font when i create it.
If i add the renderer in some normal panels, the style works fine.
If i put it in a TileList object, the style will be lost
code like this:
public class MyRenderer extends UIComponent implements ICellRenderer
{
public function MyRenderer()
{
private var m_label = new Label();
m_label.setStyle("textFormat", someTextFormat);
addChild(m_label);
}
}
var m_tileList:TileList = new TileList();
m_tileList.setStyle("cellRenderer", MyRenderer)
m_tileList.addItem({});//the renderer showed but the "someTextFormat" lose
It's definitely more difficult finding information on how to use the fl.controls components since Adobe came out with CS 6. The information on how to use stules with them is here.
Try something like
StyleManager.setComponentStyle(MyRenderer, "textFormat", someTextFormat);
I've started building a rough game engine framework in Flash Professional and I'm curious how I can create objects in the Flash library that I'm able to drag onto the stage and assign properties that are accessible from AS3.
Example:
I want to create a switch object (e.g. a light switch), so that when the player interactes with it, it triggers something specific in code such as a light in the room turns on.
I understand that Flash has built in UI components that you can define properties within the Flash Professional environment (see image below), and I'm wondering if there's a way to create my own custom style components so that I can essentially have my level file open in flash (.fla) and then drag a switch component from my library, and type in some information such as what light it is controlling, and any other information I want.
(above is an example of the type of parameter control I'm looking for)
I've read a bit about extending the flash UIComponent class but I feel that that's not the right approach because it's overkill for what I want. All I want is to pass some basic parameters from a library stage instance into AS3. I do not want to pass data via the instance name because this seems very messy if I want to have more complex interaction.
Thanks!
I would create a "switch" movie clip and export it to actionscrip, same with a "light" movie clip. The in the main class .as file I would inset them into the stage, using addChild (clips) and then add a click listener to the "switch" movie clip to control the "light".
This can be easily done.
Component(s) are wrong approach in my opinion.
Firstly you would want to setup Actionscript linkage / label your Library item.
In Library Panel.
- Right Click on "yourMC" >> click "Properties".
- In Properties dialog Tick "Export for Action Script"
- Then Name your Class eg "yourMC_Class"
now MC is ready to be referenced in your code.
next you would want to Dynamically add your "yourMC" from library to stage.
which can be done like such.
// first reference library item
var yourMC_ref:yourMC_Class = new yourMC_Class();
// Then load dynamic mc item into var
var your_MC_OBJ = yourMC_ref;
// then add your MC to stage.
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
in a nutshell that's how I add library items to stage.
Obviously thats the basic function / code.
In a project I would have all code in an external class, in which case you would just set vars as public vars
public var yourMC_ref:yourMC_Class = new yourMC_Class();
public var your_MC_OBJ = yourMC_ref;
and the last 3 lines of code into a public function
public function ADD_First_MC()
{
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
}
Now 'your_MC_OBJ' can be used in more complex ways.
eg. to create a light switch there are many options depending on how you need to approch functionality.
eg. Apply a different MC library item to "your_MC_OBJ"
play specific frame within MCs.
However If it was me I would just use mouse function to switch light on or off using addChild removeChild.
eg.
public var LightON = 0;
public var yourMC_ref:yourMC_Class = new yourMC_Class();
public var your_MC_OBJ = yourMC_ref;
then create a public function that handles on / off events
public function LightON_OFF()
{
if(LightON == 1)
{
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
}
if(LightON == 0)
{
this.removeChild(your_MC_OBJ);
}
}
Hope this helps.
So, for what you want, while it may not be the best way to do what you want, I understand it's your experience you are constructing.
Use components, yes...in the following way (the most simple one):
Create a Movie Clip
Right-click it in library
Click on "Component Definitions"
Add a property, set a name, a variable name (var test, for this matter) and a default value
Click OK
Open your movie clip
Open code for the first frame and declare the variable without an initial value (var test:String;)
Trace it's value ( trace( test ); )
Go back to the stage root
Drag and drop the item from library to stage
Test it (Cmd/Ctrl + Enter) (maybe it will print null, dunno why, it ignores the default value sometimes)
Select your component on stage
Open the properties panel (Windows > Properties)
Go to Component Parameters on this panel and change the property value
You should see the value traced on console
And, I think, like this you can use properties from components for what you want, like using a String and getting the controlled mc by its name.
Good luck
I think what people are trying to say is that you can have the whole thing is data driven, and so you can combine the IDE with the data to come up with your final game.
But consider this ... it might be what you want.
If you have, for instance, a BaseSwitch Class:
public Class BaseSwitch extends MovieClip {
private var _lightName:String;
private var _light:Light;
public function get lightName():String {
return lightName;
}
public function set lightName(value:String):void {
if (value != _lightName) {
_lightnName = value;
//Note I don't advocate having children reach into their parents like this,
//but you sound like you don't want the parent involved in the process, so
//this is one way you could do it.
if (parent.hasOwnProperty(lightName) && parent[lightName] is Light) {
_light = parent[lightName];
} else {
trace('Could not find light', _lightName);
}
}
}
//other code to listen for gestures and operate the light
}
Now, when you want a switch to operate a specific light name, create a library instance and set its base class to BaseSwitch. When you close the dialog where you set the base Class, you'll notice that it gives you a dialogue that it couldn't find the Class in the Class path and one will be generated. You're going to replace it with a Class that sets the lightName. Create a new AS3 Class in the root directory with the same name as your library instance. It should look something like this:
public class SpecificSwitch {
public function SpecificSwitch() {
super();
lightName = 'theSwitch';
}
}
Other possible choices involve having the parent Class match up instances of switch with instances of light based on name, so if it finds a light1 and a light1Switch, it either gives a reference to the light to the switch or it simply sets up a mapping in its own event listening system.
I have a UIComponent that sits on top of a grid visually, which is also a UIComponent. The grid and the UIComponent that sits on top are on different branches. The gird has children which are Sprites. When the MousEvent.CLICK is dispatched it goes to the UIComponent on top. What I want it to do is go the element of the grid underneath. Is this possible?
Yes you can,
if your element id is "ui_component"
then in ActionScript you should add two properties
ui_component.mouseEnabled = true;
ui_component.mouseChildren = true;
This will tell your component to pass click event on MovieClip behind it.
I hope this helps.
What I had to do was just make the UIComponent on top top.mousEnabled = false
Another option, if your implementation does not allow for you to disable the mouse events for the top UIComponent, is to manually redispatch the event.
Here's a rather generic example. Attach the following handler for a MouseEvent.CLICK to either the container that holds the other UIComponents or the one on the UIComponent on top:
private function propagateClickEvent(event:MouseEvent):void
{
// find all objects under the click location
var uicOver:Array = getObjectsUnderPoint(new Point(event.stageX, event.stageY));
// filter out what you don't want; in this case, I'm keeping only UIComponents
uicOver = uicOver.filter(isUIComponent);
// resolve skins to parent components
uicOver = uicOver.map(resolveSkinsToParents);
// remove the current item (otherwise this function will exec twice)
if (event.currentTarget != event.target) { // otherwise let the following line do the removal
uicOver.splice(uicOver.indexOf(event.currentTarget),1);
}
// remove the dispatching item (don't want to click it twice)
uicOver.splice(uicOver.indexOf(event.target),1);
// dispatch a click for everything else
for each (var uic:UIComponent in uicOver) {
uic.dispatchEvent(new MouseEvent(MouseEvent.CLICK, false)); // no bubbling!
}
}
// test if array item is a UIComponent
private function isUIComponent(item:*, index:int, arr:Array):Boolean {
return item is UIComponent;
}
// resolve Skins to parent components
private function resolveSkinsToParents(item:*, index:int, arr:Array):* {
if (item is Skin) {
return item.parent;
}
return item;
}
This code would work as follows in MXML:
<s:Group click="propagateClickEvent(event)">
<s:Button click="trace('button1')"/>
<s:Button click="trace('button2')"/>
<s:Button click="trace('button3')"/>
</s:Group>
<!-- trace output on click: "button3", "button1", "button2" -->
This is very generic. I'd recommend using something more specific than UIComponent, otherwise it would probably dispatch more clicks than are necessary. That all depends on what you're actually doing.
Also, the MXML example is rather poor, since, if you knew all your components beforehand you could definitely handle it differently. However, if you had a bunch of components whose positions were determined at runtime, this would approach would make more sense.
I want to rotate a sprite in 3d using AS3. The example below, tells how to do rotate an image using MXML and AS3, however, I want to do it through pure AS3:
Example
thanks
Flex is AS3. Flex compiles down to actionscript. Often, it's just a declarative (as opposed to the imperative) way to get things done.
So the meat of that example is in the code snippets:
private function playEffect(target:Animate, angle:Number):void {
if (!target.isPlaying) {
rotY += angle;
target.play();
}
}
//snip...
<fx:Declarations>
<fx:Number id="rotY">0</fx:Number>
<s:Rotate3D id="fxRotate3DNeg" target="{image}" angleYTo="{rotY}"
autoCenterTransform="true" />
<s:Rotate3D id="fxRotate3DPos" target="{image}" angleYTo="{rotY}"
autoCenterTransform="true" />
</fx:Declarations>
What's doing the work is the "Animate" object in conjunction with the two "Rotate3D" objects. So to get this to work in pure AS3, the only tough thing that's required is linking to the flex libraries. Depending on your IDE, that's pretty easy to do.
From there all you have to do is create the objects you want, imperatively instead of declaratively. So instead of doing things like:
<fx:Number id="rotY">0</fx:Number>
You need to do:
var rotY:Number = 0;
Once you know that, converting from Flex to AS3 and vice versa is pretty straightforward. The translated flex code would look something like the following in ActionScript:
import spark.effects.Rotate3D;
var rotY:Number;
var fxRotate3DNeg:Rotate3D;
var fxRotate3DPos:Rotate3D;
rotY = 0;
fxRotate3DNeg = new Rotate3D(image);; //the constructor sets the "target" property
fxRotate3DNeg.angleYTo = rotY;
fxRotate3DNeg.autoCenterTransform = true;
fxRotate3DPos = new Rotate3D(image);
fxRotate3DPos.angleYTo = rotY;
fxRotate3DPos.autoCenterTransform = true;
Now, that's off the top of my head, glancing at the Rotate3D API and typing in this text editor so I'm sure it's not perfect but it should give you a clear idea on how to move forward. If you need more help, let me know and I could translate more of the example.
I hope that helps,
--gMale
EDIT:
As I look at the code, one other tricky point is that the angleYTo properties are bound to rotY. So to truly get this to work, you have to explicitly set those properties in the playEffect function. As in:
private function playEffect(target:Animate, angle:Number):void {
if (!target.isPlaying) {
rotY += angle;
//manually set properties
fxRotate3DNeg.angleYTo = fxRotate3DPos.angleYTo = rotY;
target.play();
}
}
Alternatively, you could imperatively create the data binding, which is pretty easy to do. Then, the playEffect function would require no modification.
Its like rotating the object as you usually do. However in 3d space you will have to use:
sprite.rotationY
Make sure you are exporting for flash 10 or later since the 3d functionality doesnt exist in earlier versions.
I have to create several vbox-es in a for each loop.
Now I want to do something like this.
formsArray["vb"+counter] = new VBox;
formsArray["vb"+counter].visible = true;
add labels etc.
I can't get this thing to work. Anybody any idea how to create dynamic variable names for my vbox-es?
Thanks
First off, to use an associative array, you need to use an Object and not an Array (perhaps you already are, then never mind).
You can achieve what you want to do the following way:
var vbox:VBox;
var formsArray:Object = new Object();
var counter:int = 0;
for each(<statement>)
{
vbox = new VBox();
formsArray[("vb" + counter.toString())] = vbox;
counter++;
}
The VBox's visible property is true by default, so no need to explicitly set it.
Answer to additional question in comments:
You don't really need to make use of dynamic references to do what you want to do. You'd be best of creating a custom component for this, extending the VBox class, by creating a new MXML class with VBox as the root tag. Something along these lines:
<mx:VBox ... >
<mx:Button ... click="btnClickHandler()"/>
<mx:Script>
<![CDATA[
// Toggles visibility of the VBox
private function btnClickHandler():void
{
visible = !visible;
}
]]>
</mx:Script>
</mx:VBox>
Then you can just instantiate as many of these custom VBox:es as you need. However, making the VBox invisible will make the contained button invisible as well, making it difficult to click it again. :) You probably want to address that. Anyways, I hope this will point you in the right direction.