I have a FLEX 4 application and I am having some trouble adding UI controls dynamically. Mostly with radio buttons.
Here is an example that demonstrates my problem:
<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"
creationPolicy="all"
>
<fx:Script>
<![CDATA[
import mx.containers.Form;
import mx.containers.Panel;
import mx.controls.Label;
import mx.controls.NumericStepper;
import mx.controls.RadioButton;
private var theChar:String = "B";
protected function btnAdd_clickHandler(event:MouseEvent):void
{
var theForm:Form = new Form();
theForm.label = theChar;
//1. Label
var myLabel:Label = new Label();
myLabel.text = "My Label";
myLabel.width=120;
theForm.addChild(myLabel);
//2. Numeric Stepper
var myNumStepper:NumericStepper = new NumericStepper();
myNumStepper.id = "numPointHigh" + theChar;
myNumStepper.name = "numPointHigh" + theChar;
myNumStepper.minimum = 0;
myNumStepper.maximum = 120;
myNumStepper.width = 50;
myNumStepper.height = 30;
theForm.addChild(myNumStepper);
//3. radio button
var myRadioButton:RadioButton = new RadioButton;
myRadioButton.id = "myRadioButton" + theChar;
myRadioButton.name = "myRadioButton" + theChar;
myRadioButton.label = "my radio button";
myRadioButton.selected = true;
theForm.addChild(myRadioButton);
//4. Panel
var thePanel:Panel = new Panel();
thePanel.width = 300;
thePanel.height = 475;
thePanel.name=theChar;
thePanel.title = "My Profile Panel";
thePanel.setStyle("backgroundColor", "blue");
//add the form to the panel
thePanel.addChild(theForm);
//add the Panel to the list control
myContainer.addChild(thePanel);
}
protected function btnClear_clickHandler(event:MouseEvent):void
{
var numChildren:Number = myContainer.numChildren;
for(var i:Number=numChildren - 1; i > -1; i--){
myContainer.removeChildAt(i);
}
}
]]>
</fx:Script>
<mx:VBox width="100%">
<mx:Panel id="myContainer" />
<mx:Button id="btnAdd" label="Add a panel" click="btnAdd_clickHandler(event)" color="black"/>
<mx:Button id="btnClear" label="Clear" click="btnClear_clickHandler(event)" color="black" />
</mx:VBox>
</s:Application>
^ Run that. Click the "Add a panel" button. Then click "Clear". Then click the "Add a panel" button again. You will see the error:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller. at flash.display::DisplayObjectContainer/getChildIndex() at mx.core::Container/getChildIndex()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\core\Container.as:2833] at mx.containers::Panel/getChildIndex()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\containers\Panel.as:1174] at mx.controls::RadioButtonGroup/breadthOrderCompare()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\controls\RadioButtonGroup.as:600] at mx.controls::RadioButtonGroup/breadthOrderCompare()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\controls\RadioButtonGroup.as:611] at mx.controls::RadioButtonGroup/breadthOrderCompare()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\controls\RadioButtonGroup.as:611开发者_运维知识库] at Array$/_sort() at Array/http://adobe.com/AS3/2006/builtin::sort() at mx.controls::RadioButtonGroup/http://www.adobe.com/2006/flex/mx/internal::addInstance()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\controls\RadioButtonGroup.as:465] at mx.controls::RadioButton/addToGroup()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\controls\RadioButton.as:574] at mx.controls::RadioButton/commitProperties()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\controls\RadioButton.as:514] at mx.core::UIComponent/validateProperties()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\core\UIComponent.as:7772] at mx.managers::LayoutManager/validateProperties()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:572] at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:730] at mx.managers::LayoutManager/doPhasedInstantiationCallback()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:1072]
I do not understand why I cannot re-add the radio button, after the first go at it? It is only happening when I have radio buttons being added to the form/panel.
If you comment out the code for the radio button (comment section #3.) you can re-add the panels easily. Try it, comment this out and you can add, re-add the panel with no problem:
//3. radio button
//var myRadioButton:RadioButton = new RadioButton;
//myRadioButton.id = "myRadioButton" + theChar;
//myRadioButton.name = "myRadioButton" + theChar;
//myRadioButton.label = "my radio button";
//myRadioButton.selected = true;
//theForm.addChild(myRadioButton);
Why is this happening and how do I fix it? Why is this only happening to radio buttons? I can use checkboxes, textinputs, whatever and it doesn't throw exceptions like this...any ideas?
You aren't adding your radio buttons to a radio button group. Start doing that and you should stop seeing errors.
That said, this line is a mystery to me:
myList.addChild(thePanel);
Why are you adding children to a list control? You shouldn't be using a list as a container. It should only focus on displaying items in your DataProvider. A list class has no facility for positioning or laying out elements not in the dataProvider.
Additionally, you don't have parenthesis when creating the new RadioButton:
var myRadioButton:RadioButton = new RadioButton;
In theory that shouldn't make a difference, but it is always my preference to keep the parenthesis in.
Here is working code:
<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"
creationPolicy="all"
>
<fx:Script>
<![CDATA[
import mx.containers.Form;
import mx.containers.Panel;
import mx.controls.Label;
import mx.controls.NumericStepper;
import mx.controls.RadioButton;
import mx.controls.RadioButtonGroup;
import spark.components.RadioButtonGroup;
private var theChar:String = "B";
protected function btnAdd_clickHandler(event:MouseEvent):void
{
var theForm:Form = new Form();
theForm.label = theChar;
//1. Label
var myLabel:Label = new Label();
myLabel.text = "My Label";
myLabel.width=120;
theForm.addChild(myLabel);
//2. Numeric Stepper
var myNumStepper:NumericStepper = new NumericStepper();
myNumStepper.id = "numPointHigh" + theChar;
myNumStepper.name = "numPointHigh" + theChar;
myNumStepper.minimum = 0;
myNumStepper.maximum = 120;
myNumStepper.width = 50;
myNumStepper.height = 30;
theForm.addChild(myNumStepper);
//3. radio button
var radioButtonGroup : mx.controls.RadioButtonGroup = new mx.controls.RadioButtonGroup();
var myRadioButton:RadioButton = new RadioButton();
myRadioButton.id = "myRadioButton" + theChar ;
myRadioButton.name = "myRadioButton" + theChar ;
myRadioButton.group = radioButtonGroup ;
myRadioButton.label = "my radio button";
myRadioButton.selected = true;
theForm.addChild(myRadioButton);
//4. Panel
var thePanel:Panel = new Panel();
thePanel.width = 300;
thePanel.height = 475;
thePanel.name=theChar;
thePanel.title = "My Profile Panel";
thePanel.setStyle("backgroundColor", "blue");
//add the form to the panel
thePanel.addChild(theForm);
//add the Panel to the list control
myList.addChild(thePanel);
}
protected function btnClear_clickHandler(event:MouseEvent):void
{
var numChildren:Number = myList.numChildren;
for(var i:Number=numChildren - 1; i > -1; i--){
myList.removeChildAt(i);
}
}
]]>
</fx:Script>
<mx:VBox width="100%">
<!--<mx:List id="myList" />-->
<mx:VBox id="myList" />
<mx:Button id="btnAdd" label="Add a panel" click="btnAdd_clickHandler(event)" color="black"/>
<mx:Button id="btnClear" label="Clear" click="btnClear_clickHandler(event)" color="black" />
</mx:VBox>
</s:Application>
精彩评论