I am writing a class that extends mx.core.UIComponent. In the constructor of this class, I would like to add a Button (spark.components.Button). However, creating a new Button object (such as var b:Button = new Button();) and then doing this.addChild(b) doesn't work -- no button is appearing. Is there any reason why a Button object can't be added as a child?
Edit: Just to add, when I print out the children, it says that the Button object is a child, but the Button doesn't show up.
You need to add the button in the createChildren method not in the constructor.
protected var button:Button;
override protected function createChildren():void {
super.createChildren();
button = new Button();
addChild(button);
}
Depending on what you are trying to do you may also need to implement the measure and updateDisplayList methods.
Using UIComponent directly, you aren't getting the layout of the child handled for you; you would need to set the position and size of your child components manually (see docs).
Consider using a Group (or Canvas, if you're still on MX components) to handle child layout. You can still add rendering in updateDisplayList, just make sure you call super.updateDisplayList() as well.
You need to read up on the differences between ActionScript components and Flex components. When using a Flex component, you must use container.addElement( element ), not container.addChild( child ). As far as I am aware, the only classes with this functionality descend from Group (at least in the Spark framework, the one I am most familiar with). So extending UIComponent will not allow you to add a Button, although a UIComponent can be added to a Flex container (which I do not believe a normal Sprite can do)
Related
The class javax.swing.JComponent is a direct subclass of javax.awt.Container, which provides methods to add child components. While this makes sense for some components, like JTable or JTree, it doesn't seem to make sense for JLabel, for example. As far as I could tell from simple experiments, children of a JLabel are ignored.
Is there a good reason that all JComponent subclasses are also subclasses of Container, or is it just a relic of the days of overzealous subclassing?
Why is JComponent a subclass of Container?
You can add child components to any component. You may get different behaviour than you would if you add components to a panel, but it can be done. For most components, other than a JPanel, a null layout is used.
While this makes sense for some components, like JTable or JTree,
Why do you say this. A JTable is just a component. The normal display of a JTable does not have any child components. When you edit a cell, the editor component is added to the table and the table will manage the size/location of the component.
it doesn't seem to make sense for JLabel, for example. As far as I could tell from simple experiments, children of a JLabel are ignored.
Since the layout is null you need to manage the size/location of any component you add to the label.
Or, you can set the layout manager of the JLabel. Note the actual size of the label will not include the children, but you can position the children on the label using the layout manager.
I'm working on a UI project that requires that the automatic resizing buttons (based on label length) have a focus indicator graphic for keyboard or controller focus. This graphic must obviously scale with the parent as you would imagine.
This causes a problem; the parent clip is 9sliced, and that slicing doesn't fall through to the child Sprites/MovieClips of this clip. The focus indicator needs to be an accessible property because it has to be capable of being turned on or off.
Currently the only solution I can image is an extremely programmatical reimplementation of scale9Grid where I split the focus indicator into 9 and alter the 9 parts' properties any time the parent width/height/scaleX/scaleY is changed. This would also mean turning all 9 parts on and off when that button is focused
Is there any better way than that?
I recommend you create some wrapper class AppButton (or may be you already have one since you have some resizing by label functionality) with method setSkin(skin:MovieClip) (where skin is your MovieClip from the library) and overridden setters for width and height, so you can implement here skin resizing logic in method arrange() that called each time width or height are changed.
Skin can be complex - with other movie clips in children (focus border in your case), so don't use scale9Grid for the hole skin, but set sizes directly to the children with set scale9grid them as well, so your arrange method can be like that:
private function arrange():void
{
var child:DisplayObject;
for(var i:int = 0; i < numChildren; i++)
{
child = getChildAt(i);
child.width = width;
child.height = height;
}
}
It's also worth to make one skin format for button skins in project, so you can use one wrapper for all buttons.
Later you can add more features to this AppButton - switching view states on mouse events, setting text label, animating skins and so.
This approach work for me for many years, we have base ToggleButton and LabelButton extends ToggleButton classes, and extends them in every project with custom skin parsing and arranging.
This problem seems very simple to me, but I've been unable to fix it, or find an answer anywhere.
This is in a class constructor for a class called block, block_maker is the object that called the constructor, an instance of level.
this.bitmap = new Bitmap(this.bitmap_data);
this.addChild(this.bitmap);
this.block_maker.stage_foreground.addChild(this);
In level, stage_foreground is added to the stage, but nothing appears. trace(stage_foreground.numChildren); shows the correct count of children, and var temp = (this.stage_foreground.getChildAt(0)); trace(temp.numChildren); correctly but the children OF the children don't actually show up, the stage just stays blank.
When I change the above code to
this.bitmap = new Bitmap(this.bitmap_data);
this.block_maker.stage_foreground.addChild(this.bitmap);
the blocks appear on the stage, as children of level_instance.stage_foreground, but with this method, the bitmaps aren't appropriately positioned, as they have no position data. I can simply give this.bitmap x and y positions, and it works, but I am curious as to why it won't work when just adding the bitmap as a child to the block and then adding that as a child to stage_foreground.
I've tried replacing this.bitmap with a number of other object classes, such as a temporary MovieClip I made, or a Shape, but nothing shows up, so I know it has nothing to do with it being a Bitmap.
As you stated
This is in a class constructor for a class called block, block_maker
is the object that called the constructor, an instance of level.
this.bitmap = new Bitmap(this.bitmap_data);
this.addChild(this.bitmap);
this.block_maker.stage_foreground.addChild(this);
The level class needs to to extend a display object for it to show up.
In other words
"this"
has to be a display object or extend it in some form.
The reason this doesn't work.
this.block_maker.stage_foreground.addChild(this);
and this does
this.block_maker.stage_foreground.addChild(this.bitmap);
Is because "this" is not a display object but "this.bitmap" is.
The DisplayObject class is the base class for all objects that can be placed on the display list.
First of all, even though it's not neccesary, I'd suggest to make a classname start with a capital letter, and vars always start with a lower-case letter. It's a common 'rule' in AS3 that's mainly to avoid confusion.
The problem most likely lies within you use of this; what you're doing is adding this into this. It seems to me it's not a proper way of coding.
Also, since all of the other attempts didn't work; have you tried to make the var you want ot add a public static var?
I'm building a game of which the interface is one of the first items to load on screen. Sound button, pause and all the bits -
During the game - all manor of things are dynamically added and removed to the stage. Therefore my interface goes behind my game scene.
How do I ensure the movieclip always stays on top?
Can I override the addChild of my Document Class and every time a new child is added, I restack the interface to the top?
You can use setChildIndex to rearrange objects that are already contained within a MovieClip or Sprite. For example, if you have an object called container, which contains a redBall, blueBall and many other ball objects, you can use the following to make sure redBall is behind everything else:
container.setChildIndex(redBall, 0);
Equally you can make sure that blueBall will be displayed infront of everything else using:
container.setChildIndex(blueBall, container.numChildren-1);
addChildAt will sort you out for adding children straight into their correct position, and setChildIndex will allow you to re-position objects already placed. Hope that helps.
debu
Look into addChildAt, it allows you to specify the index that the new object should be added too.
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/DisplayObjectContainer.html#addChildAt%28%29
A good strategy is to keep all interface elements in one parent Sprite/MovieClip, and all game assets in another. (With the interface one on top)
With your guys suggestion I made this, apparently, if you addChild an object already on the screen, it's simply reindex'd to the top. Does this look ok?
private var topLevelChildrenArray:Array = [];
public function addTopLevelChild(child:DisplayObject):DisplayObject
{
topLevelChildrenArray.push(child)
return this.addChildAt( child, this.numChildren - 1 );
}
override public function addChild(child:DisplayObject):DisplayObject
{
this.addChildAt(child, this.numChildren);
for each(var topChild:DisplayObject in topLevelChildrenArray)
{
super.addChild(topChild);
}
return child
}
I inherited a custom component from TextField. The component needs to know when any of its styles got changed at runtime via setStyle. How would I do that? It's probably obvious but I couldn't find an event or appropriate method to override.
If you want the text field to play nicely with containers and other components in Flex you may want to wrap it in a UIComponent, or have the subclass implement the IUIComponent and IStyleClient or ISimpleStyleClient interfaces (which UIComponent implements). If you do the component will work with Flex' style system and every time a style changes a method calledstyleChanged` will be called:
public function styleChanged(styleProp:String):void
See http://livedocs.adobe.com/flex/3/langref/mx/core/UIComponent.html#styleChanged()
styleChanged () method
public function styleChanged(styleProp:String):void
Detects changes to style properties. When any style property is set, Flex calls the styleChanged() method, passing to it the name of the style being set.
This is an advanced method that you might override when creating a subclass of UIComponent. When you create a custom component, you can override the styleChanged() method to check the style name passed to it, and handle the change accordingly. This lets you override the default behavior of an existing style, or add your own custom style properties.
If you handle the style property, your override of the styleChanged() method should call the invalidateDisplayList() method to cause Flex to execute the component's updateDisplayList() method at the next screen update.
Parameters styleProp:String — The name of the style property, or null if all styles for this component have changed.