Creating custom qml objects instances with Qt.createQmlObject() - qt

I've got a custom QML object called Target.qml. I would like to create dynamic instances of this object using Qt.createQmlObject().
It works when using builtin qml objects like Image:
var newTarget = Qt.createQmlObject('import Qt 4.7; Image {source: "widgets/SlideSwitchImages/knob.png"; }', parent);
But fails when using any custom object types like:
var newTarget = Qt.createQmlObject('import Qt 4.7; Target {}', parent);
If however I use my custom Target type statically in QML everything works. Is this a known limitation, any workarounds?

If you just need an arbitrary number of Target instances it would be better to use Component.
Component {
id: targetFactory
Target {}
}
var newTarget = targetFactory.createObject(parent, properties)
However if you want to stick to the Qt.createQmlObject call I guess you have the Target component in a different directory and you're just missing out some import statement. The string parameter must be the content of a QML file that works on its own in the same directory as the one calling it.
E.g.
var newTarget = Qt.createQmlObject('import QtQuick 1.0; import "../Targets"; Target {}', parent);
BTW: The Qt 4.7 imports are deprecated because they don't allow additional versions of QtQuick.

From the docs:
There are two ways to create objects dynamically from JavaScript. You can either call Qt.createComponent() to dynamically create a Component object, or use Qt.createQmlObject() to create an item from a string of QML. Creating a component is better if you have an existing component defined in a .qml file, and you want to dynamically create instances of that component. Otherwise, creating an item from a string of QML is useful when the item QML itself is generated at runtime.
I understand this to mean that createQmlObject will only work if you've defined the item type at runtime and that the application is therefore aware of the existence of it.
createComponent seems to perform the same function but for item types pre-defined in .qml files, as in your case.

Related

How can I load a list of defines into QML?

Here is the the thing, I have a header file with a list of defines, defining string constants. I'm doing my interface with QML. I was wondering if there is any way to import those defines so that I can reference from QML.

access mxml component from external actionscript file

i'm trying to access an mxml component from my external as file. e.g
main.mxml:<br>
<code>[mx:text id="myText" />]</code>
file.as:<br>
<code>var mainM:main = new main();
mainM.text.visible = true;</code>
I get the following error:
[TypeError: Error #1009: Cannot access a property or method of a null object reference]
Any suggestions on how to approach it better.
The ID of your component instance becomes a member of your application and can easy be accessed like so
import mx.core.Application;
mx.core.Application.application.myText.visible = true;
An additional answer is that when you create a new Flex component (new myFlexComponent()), the child UI components are not created until a CREATION_COMPLETE call is invoked, indicating the component is fully created. In the case of application, there is only one, and its automatically created by the framework, and referenced by (Application.application) as stated above.
For example, if your variable was a simple class variable (e.g. myDate:Date), you could access it via the above syntax

Getting handles to dynamically-generated Flex components

I have a Flex application which references a separate MXML file as a template for a custom component. I create instances of the component dynamically several times in my program, but I need to get a handle that will allow me to modify that instance of the component as desired.
I pass specific information to this component on instantiation using bindable public variables in the component's MXML file. I add it to my main program using addChild().
I want to update the component's progressbar as necessary and I want to remove it from the box to which I addChild'd it.
What's the easiest/best way to get a variable that will give me predictable access to each component so I can easily manipulate the components as necessary? Some research suggests creationComplete, but I decided it was faster to just ask than to go through lots of different experiments and come up blank.
Thanks for all the help. : )
Can you not just keep a list of your components in an array? Presumably you have an object reference when you create them and call addChild() on their parent. Why not just put them in an array at the same time?
var list_of_controls:Array = new Array();
var new_Object:<yourType>;
new_Object = new <yourType>();
parent.addChild(new_Object);
list_of_controls.push(new_Object);
then you can get at them...
var my_Object:<yourType>;
for each (my_Object in list_of_controls)
{
// do something
}
You would have to make sure you dispose of them properly when you re done because the reference in your array would keep them in existence until cleared.
If you decide that you want to use getChildren() instead - which you could - take the time to read the documentation because I think it returns a new array with each call.
I hope that helps.

Create instances of flex custom component by passing in type

In my flex app there are a few custom components. I want to create instance of these components at runtime and assign them properties by reading in a config file.
I know how to read xml and instantiate components, however my question is about being able
to get the type of the component from the xml attribute and then creating an instance of that type.
My xml looks like this:
You can instantiate an arbitrary named type through ActionScript's "reflection API":
var clazz:Class = Class(getDefinitionByName("class.from.your.xml.file.Name"));
var component:Object = new clazz();
http://livedocs.adobe.com/flex/3/langref/flash/utils/package.html#getDefinitionByName()
If you get an error about the type not existing, this is because it isn't linked from elsewhere in your application and the compiler only adds classes that are referenced. You can work around this using the following compiler arg:
includes class [...]
Links one or more classes to the resulting application SWF file, whether or not those classes are required at compile time.
http://livedocs.adobe.com/flex/3/html/compilers_14.html#157203

Duplicate complex MXML binding in ActionScript

MXML lets you do some really quite powerful data binding such as:
<mx:Button id="myBtn" label="Buy an {itemName}" visible="{itemName!=null}"/>
I've found that the BindingUtils class can bind values to simple properties, but neither of the bindings above do this. Is it possible to do the same in AS3 code, or is Flex silently generating many lines of code from my MXML?
Can anyone duplicate the above in pure AS3, starting from:
var myBtn:Button = new Button();
myBtn.id="myBtn";
???
The way to do it is to use bindSetter. That is also how it is done behind the scenes when the MXML in your example is transformed to ActionScript before being compiled.
// assuming the itemName property is defined on this:
BindingUtils.bindSetter(itemNameChanged, this, ["itemName"]);
// ...
private function itemNameChanged( newValue : String ) : void {
myBtn.label = newValue;
myBtn.visible = newValue != null;
}
...except that the code generated by the MXML to ActionScript conversion is longer as it has to be more general. In this example it would likely have generated two functions, one for each binding expression.
You can also view the auto-generated code that flex makes when it compiles your mxml file, by adding a -keep argument to your compiler settings. You can find your settings by selecting your projects properties and looking at the "Flex Compiler" option, then under "Additional compiler arguments:" add "-keep" to what is already there.
Once done Flex will create a "generated" directory in your source folder and inside you'll find all teh temporary as files that were used during compilation.
I believe flex generates a small anonymous function to deal with this.
You could do similar using a ChangeWatcher. You could probably even make a new anonymous function in the changewatcher call.

Resources