View Full Version : obtaining subobjects from a createObject call
TOP-Proto
11-16-2010, 05:26 PM
Well i dont know where to begin with this so i will try and be as comprehensive as i can.
I have begun writing my own settings page and i have everything worked out for completing this but im having a hard time understanding something with flash.
in GFxUDKFrontEnd_Settings we have this
/**
* Sets up the list's dataProvider using the data pulled from
* DefaultUI.ini.
*/
function UpdateListDataProvider()
{
local byte i;
local string DefaultValue;
local int DefaultIndex;
local GFxObject RendererDataProvider;
local GFxObject DataProvider;
local GFxObject TempObj;
DataProvider = Outer.CreateArray();
for (i = 0; i < SettingsList.Length; i++)
{
// Create a AS object to hold the data for SettingsList[i].
TempObj = CreateObject("Object");
// Parse SettingsList[i] into TempObj.
TempObj.SetString("label", Caps(SettingsList[i].FriendlyName));
TempObj.SetString("control", "stepper"); //SettingsList[i].OptionType);
RendererDataProvider = Outer.CreateArray();
PopulateOptionDataProviderForIndex(i, RendererDataProvider, DefaultValue, DefaultIndex);
TempObj.SetBool("bUpdateFromUnreal", true);
TempObj.SetObject("dataProvider", RendererDataProvider);
// Set a default index for the option stepper.
TempObj.SetFloat("optIndex", DefaultIndex);
TempObj.SetBool("bNumericCombo", SettingsList[i].bNumericCombo);
TempObj.SetBool("bEditableCombo", SettingsList[i].bEditableCombo);
TempObj.SetFloat("editBoxMaxLength", SettingsList[i].EditBoxMaxLength);
DataProvider.SetElementObject(i, TempObj);
}
ListMC.SetObject("dataProvider", DataProvider);
ListDataProvider = ListMC.GetObject("dataProvider");
}
What i am having a problem understanding is how this is working.
firstly i see that dataprovder is just an array created and tempobj is an actionscript object to hold data. but then i get thrown when it starts setting stuff in setstring.
where the heck did contol and stepper come from for example, and the setbool bupdatefromunreal??
I took a copy of the settings section menu_item_settings from the UDK_Settings.fla file and modified it to add a label box and remove the textbox and stepper control. All i would like to do is assign the label value to the label as it should be and a value to my new label box i have added.
from looking in the flash file it appears to be doing this
{label:"Test1" ,control:"stepper"}
im so totally confused as to how this thing works its turning into a nightmare to add a simple label of my own to set a value.
Any chance someone can shed some light on this issue??
Nate Mitchell
11-18-2010, 12:12 PM
Hey Proto,
Let's see if we can't clear up some of your confusion:
where the heck did contol and stepper come from for example, and the setbool bupdatefromunreal??
SetString takes 2 parameters: an ActionScript member name (type String) and a string that the member should be set to (type String). In this case, "control" is the member name and we're setting it to "control". Why? So that the ActionScript class for the component (MultiControlItemRenderer, found in UDKGame/Flash/ActionScript/com/scaleform/udk/controls/) knows which internal control to display (either OptionStepper / TextInput, since both are included in the symbol) and how to update that component (since the data for an OptionStepper is different for a TextInput) using the data we provide here. The initial application of the data occurs in MultiControlItemRenderer's draw() method. If you look in that ActionScript method, you'll see all of the member properties we're setting in UpdateDataProvider() being used.
ActionScript for your components is a requirement of CLIK. You'll likely need to create new ActionScript classes/logic as you build new components or extend existing ones.
I took a copy of the settings section menu_item_settings... and modified it ... All i would like to do is assign the label value to the label as it should be and a value to my new label box i have added.
You cannot simply duplicate a Flash component, change it, and expect to see anything change in your UI. You have to actually tell Flash to use that component via the Flash Editor (inspectable properties) or ActionScript.
Modifications to the Settings view should be made in the udk_assets.fla because the udk_settings.fla simply imports the "settings" symbol from the udk_assets.fla's library (ie. it doesn't actually contain the view). It is setup this way for a few reasons: republishing one swf republishes all the views, symbols are shared across all the views, etc...
As such, you should be duplicating the "menu_item_settings" symbol from udk_assets.fla and changing the inspectable properties for the appropriate list in udk_assets.fla (which can be accomplished via the Component Inspector window in Flash Studio) if you want the list to display your duplicated renderer instead of "menu_item_settings".
Once you've duplicated the symbol and updated the inspectables for the Settings list to use your new renderer, you'll probably want to create a new ActionScript class for your renderer and assign it to the library symbol (see Properties for the symbol). You could extend MultiControlItemRenderer and override its methods to remove the logic for the OptionStepper / TextInput or you could extend the standard CLIK ListItemRenderer and start fresh.
...im so totally confused as to how this thing works its turning into a nightmare to add a simple label of my own to set a value
There's a lot going on in that UpdateDataProvider() function that would be totally unnecessary for what you're trying to achieve. The core of your function might look something like this:
...
// Create a AS object to hold the data for SettingsList[i].
TempObj = CreateObject("Object");
// Set the data.label1 property to "MyFirstLabel"
TempObj.SetString("label1", "MyFirstLabel");
// Set the data.label2 property to "MySecondLabel"
TempObj.SetString("label2", "MySecondLabel");
// Add this new data object to the dataProvider.
DataProvider.SetElementObject(i, TempObj);
...
Don't get discouraged! You're trying to modify one of the most complex parts of the UDK UI. Do you have any experience with Flash, ActionScript, or the CLIK components? If not, I would suggest taking a step backward and begin by perusing the demos, samples, tutorials, and documentation found in this forum, the UDK, and on the UDN.
For example, it might be beneficial to create a small, simple spike with a CLIK ScrollingList that uses a custom ListItemRenderer with two labels. Once you have that working properly in GFxPlayer, you can move it into UDK and populate the data via UnrealScript.
Once you have the basic concepts in place, building complex UIs will be much less daunting for you. Good luck!
Nate
Scaleform Engineering
TOP-Proto
11-18-2010, 01:57 PM
ok well thanks for the help nate - i have really got to grips with this stuff and i kinda rage posted above and didnt articulate what i wanted.
i have my own ***assets file and am using the shared linking. while im developing my menus im borrowing from udk assets (in my own folder) and working with it. i have created my own actionscript files too - custom dropdown box and used some code to allow cursors to show on top of popups such as the dropdown menu.
I will part answer my own question here using what you said above (i think i knew i had to do it this way but just hoped it would be less of a headache.
i will use the scrollinglist and my own custom listitemrenderer.
i think where i was getting lost was having to open the multirenderer then list then base classes to read and understand where the heck it got label from... makes sense that every listitemrender comes with one label as the purpose of the list is to be a list of items.
Thank you very much for taking the time to reply to me on this, i really appreciate the above and beyond support for scaleform.
TOP-Proto
11-18-2010, 07:41 PM
ok i have programmed my own as function. this is what i have got so far.
class com.scaleform.TA.controls.TAListItemRenderer extends gfx.controls.ListItemRenderer {
private var _labelValue:String;
public var textValue:TextField;
public function TAListItemRenderer()
{
super();
}
/**
* The ActionScript-only label parameter that sets the text directly, and assumes localization has been handled externally.
*/
public function get labelValue():String { return _labelValue; }
public function set labelValue(value:String):Void {
trace("Updating labelValue to " + value);
_labelValue = value;
// When the label changes, if autoSize is true, and there is a textField, we want to resize the component to fit the label.
// The only exception is when the label is set during initialization.
if (initialized) {
if (textValue != null) { textValue.text = _labelValue; } // Set the text first
if (autoSize != "none") { sizeIsInvalid = true; }
updateAfterStateChange();
}
}
/**
* Set the list data relevant to the itemRenderer. Each time the item changes, or is redrawn by the {@code owner}, the itemRenderer is updated using this method.
* @param index The index of the data the itemRenderer represents.
* @param label The calculated label the itemRenderer should display.
* @param valuelabel The value the itemrenderer should display on the right hand side
* @param selected The selected state of the itemRenderer.
*/
public function setListData(index:Number, label:String, valuelabel:String, selected:Boolean):Void
{
this.index = index;
if (label == null)
{
this.label = "Empty";
}
else
{
this.label = label;
//Set the value label too.
if(this.labelValue.length != 0)
{
this.labelValue = "Not Empty";
}
else
{
this.labelValue = "Empty";
}
}
state = "up";
this.selected = selected;
}
}
now i believe apart from the code to make it "look" correct when resize happens (updateAfterStateChange()) the code is all but done.
Theres one last thing thats eluding me though.
firstly my setup.
i am using ListItemRenderer from the CLIK components and i have added a new Layer and called my layer textValue and on that layer i have added a textbox and called it textField (exactly the same as the textfield on the TextField layer).
What i am unsure about is how i get to "talk" to my textfield object into the actionscript.
I believe my problem line is public var textValue:TextField;
and maybe i just need to assign textValue to the object somehow maybe in the constructor. Would appreciate a nudge in the right direction as i think im so close to having this done!!.
Thanks guys.
Matt Doyle
11-19-2010, 11:16 AM
I'm not sure I follow. Did you replace the label text field of the list item renderer? Or is is still there? If it is still there, does it still have an instance name of textField?
And your new text field (textValue) also has an instance name of textField? You shouldn't have two text fields with the same instance name in the same scope at the same time. That could cause problems. Layer names have absolutely nothing to do with anything important. They are purely for your reference. I would give your new text field an instance name of textValue - this is done in the properties panel. It's instance name should match the variable declaration.
You can also add textValue as an inspectable, so it can be set from the component inspector in Flash.
[InspectableList("textValue")] at the top of your class, before the class declaration.
and...
[Inspectable(defaultValue="")] just above the variable declaration for textValue.
TOP-Proto
11-19-2010, 02:08 PM
brill i figured out its actually working - but it doesnt take effect untill i scroll the list, meaning i just need to look at the draw function i think?? will get back with the rest of my code in place :)
TOP-Proto
11-19-2010, 03:22 PM
ok my main problem was using setListData threw me and my assignment to labelValue wasnt ever getting assigned and it took me a while to figure out i needed to use setData.
As a result it was confusing me when i expected it to be assigned in code - even when i set the variables in setListData!!
theres probably a second dataprovider for setListData i havnt found yet.
In my flash file i added
import flash.external.ExternalInterface;
list.dataProvider = [{label:"item1", valuelabel:"1"}, {label:"item2", valuelabel:"2"}, {label:"item3", valuelabel:"3"} ];
[InspectableList("textValue")]
class com.scaleform.TA.controls.TAListItemRenderer extends gfx.controls.ListItemRenderer
{
private var _labelValue:String;
[Inspectable(defaultValue="")]
public var textValue:TextField;
public function TAListItemRenderer()
{
super();
textValue = textValue;
}
/**
* The ActionScript-only label parameter that sets the text directly, and assumes localization has been handled externally.
*/
public function get labelValue():String
{
return _labelValue;
}
public function set labelValue(value:String):Void
{
_labelValue = value;
// When the label changes, if autoSize is true, and there is a textField, we want to resize the component to fit the label.
// The only exception is when the label is set during initialization.
if (initialized)
{
if (this.textValue != null)
{
this.textValue.text = _labelValue;
}
// Set the text first
if (autoSize != "none")
{
sizeIsInvalid = true;
}
updateAfterStateChange();
}
}
// This method allows us to set our valuelabel using dataProvider = [{label:"item1", valuelabel:"1"}, {label:"item2", valuelabel:"2"}, {label:"item3", valuelabel:"3"} ];
public function setData(data:Object):Void
{
this.data = data;
if (data.valuelabel == null)
{
this.labelValue = "Empty";
}
else
{
this.labelValue = data.valuelabel;
}
super.setData(Object);
}
// This method is fired after the state has changed to allow the component to ensure the state is up-to-date. For instance, updating the contraints in Button.
private function updateAfterStateChange():Void
{
// Redraw should only happen AFTER the initialization.
if (!initialized)
{
return;
}
validateNow();// Ensure that the width/height is up to date.
if (textField != null && _label != null)
{
textField.text = _label;
}
if (textValue != null && _labelValue != null)
{
textValue.text = _labelValue;
}
if (constraints != null)
{
constraints.update(width,height);
}
dispatchEvent({type:"stateChange", state:state});
}
}
and it now works fantastic. This means that i should now be able to revisit my code in uscript and assign to my custom control using
TempObj = CreateObject("Object");
TempObj.SetString("label", "item1");
TempObj.SetString("labelValue", "1"); //notice this is different from valuelabel as its set though uscript into AS using a method call not a dataprovider = call.
DataProvider.SetElementObject(index, TempObj);
Powered by vBulletin® Version 4.2.0 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.