Qt QML-CPP expose class as Q_PROPERTY [duplicate] - qt

This question already has an answer here:
Use custom class as Q_PROPERTY
(1 answer)
Closed 5 months ago.
Is it possible to expose class as Q_PROPERTY?
(I know how to expose native variables.)
In my case, I want to handle chunk of data that change at the same time, and I want to render it at the same frame.
Is it possible?

Generally speaking, yes you can. As long as your custom class uses the Q_OBJECT or Q_GADGET macros, you can use Q_PROPERTY on this custom type.
For better understanding, have a look on this documentation: https://wiki.qt.io/How_to_Use_a_Custom_Class_in_C%2B%2B_Model_and_QML_View

Let's say you are implementing wrappers for QDir and QFileInfo and that you have implemented both Dir and FileInfo as QObjects. Then to return the FileInfo in a method your code would look like this:
FileInfo* Dir::fileInfo(const QString& fileName) const {
FileInfo* fileInfo = new FileInfo(fileName);
QQmlEngine::setObjectOwnership(fileInfo, QQmlEngine::JavaScriptOwnership);
return fileInfo;
}
What the above code snippet is doing is creating a new FileInfo QObject but if the reference count of this QObject falls to 0 then we're allowing the QML/JS engine privilege to garbage collect it when it needs to be. The code snippet doesn't show the qmlRegisterType (or their QML_ELEMENT equivalent) that you would need to register both FileInfo and Dir classes properly, but, I am assuming that you already know how to do this. Because it is a QObject the app can take a copy of this object and can inspect (i.e. reflection) all of its properties and methods at runtime. Intellisense is possible.
The above pattern would be similar to a property as well. I would probably do something like:
FileInfo* Dir::defaultFileInfo() {
if (!m_FileInfo) {
m_FileInfo = new FileInfo(this);
QQmlEngine::setObjectOwnership(m_FileInfo, QQmlEngine::CppOwnership);
}
return m_FileInfo;
}
The above code snippet indicates that the parent class will control the creation and destruction of the request object and that there will be at most one instance created and subsequent access to the property will return the same instance.
As to Q_GADGET. Technically, I would only return a Q_GADGET where you know the entire lifecycle of the object, for instance, in a signal where you want to conveniently provide access to your class and methods. The advantage of this is there is no delegation to the QML/JS engine of your object, nor is there any type register or memory management. This is useful for exposing structures, but, the caveat, is that access to this class is limited to the duration of the signal handler and there is no access allowed beyond this. It is up to the app to copy out any values it needs from the class.

Related

Is it possible to move a object that was created dynamically into a qthread?

It's a general question about qthreads, I know how to use the movethread() function but that was for object that was not created dynamically.
The user will create the object on a GUI application by selecting add button. A remove button will also be available if the user would like to remove that object that was created. The user should be able to select the object from the listview. I've already created examples of a custom listview using qstyleditemdelegate, I know how to move the list into a model. I'm worried about the threads.
What I would like to do is allow the user to create an object of a certain class dynamically. Each object with then be moved into qthread. Should I keep looking? Any tips, tricks or hints?
Can I create a function that moves the object into a thread?
Pseudo Code:
void MoveThisObject(MyCustomObject Object)
{
QThread* thread = new QThread;
Object->moveToThread(thread);
/****setup connections****/
thread->start();
}
I'm still writing down what I'll need, I haven't really created the actual application.
You can move a QObject (as long as it's not a QWidget, of course) to a different thread regardless of whether it was created dynamically or not. Most QObjects in most applications are created dynamically anyway, or else it would be difficult for them to be polymorphic.

C#/ASP.NET MVC 4 Instantiate Object Derived From Interface In Factory Method

Currently have a Factory class that features a GetSelector function, which returns a concrete implementation of ISelector. I have several different classes that implement ISelector and based on a setting I would like to receive the appropriate ISelector back.
public interface ISelector
{
string GetValue(string Params);
}
public class XmlSelector : ISelector
{
public string GetValue(string Params)
{
// open XML file and get value
}
}
public static class SelectorFactory
{
public static ISelector GetSelector()
{
return new XmlSelector(); // Needs changing to look at settings
}
}
My question is what is the best way to store the setting? I am aware of using AppSettings etc. but I'm not sure whether I want to have to store strings in the web.config and perform a switch on it - just seems to be really tightly coupled in that if a new implementation of ISelector is made, then the Factory would need to be changed. Is there any way of perhaps storing an assembly name and instantiating based on that?
Thanks,
Chris
It is hard to say, because I don't know the architecture of your particular project, but at a first glance what I would do is if the objects associated with ISelector can be decoupled from your web application, I would put these objects in a class library along with the factory. Your factory will need to be changed if you implement a new ISelector, but if you can decouple the whole ISelector family from your actual web application the depth of the refactoring you will have to do will be minimal compared to a monolithic architecture.
Personally, I tend to avoid AppSettings, web.config settings and the like for mission-critical design questions. Using the web.config as an example, I have seen applications where architectural data is stored for ease of configurability. The problem is that after compilation your web.config can be changed (that is the purpose of it after all) and if the implementation of your classes depends on very specific values being chosen, you are running a risk of a crash when someone inadvertently modifies the wrong value.
Like I said all this depends entirely on your application architecture, but my reflex would be to split out the components that could be subject to future modification into a class library. Loose coupling is your friend ;).
Instead of doing it in AppSettings, I think a better approach will be to create a separate XML file, which will only hold the mappings and from that file you can iterate through the mappings and return correct instance in GetSelector().

Flex: Variable accessible for all .mxml files

Im using Oracle, BlazeDS, Java & Flex. I have an ArrayCollection containing data from a small database table. This table won't be the subject of much change. I want to use this ArrayCollection accross different mxml files to fill e.g. ComboBoxes etc.
The reason for asking, is that doing a database call for each time a fill a ComboBox etc is slow and seems unnecessary. I tried doing this once in the "main" .mxml file, but then the variable wasn't accessible where i needed it.
What is the best approach for accomplishing this task? What is the best way of making a variable accesible across .mxml files? :)
[Bindable] public static var yourArrayCollection:ArrayCollection
That should make it visible anywhere but using static variables is normally not a good idea.
You could also implement a singleton instance to persist a variable if you do not want to make it static and need to reference other functions etc - but I think the static variable should do fine.
If this is a larger application, I'd recommend looking at Parsley: http://www.spicefactory.org/parsley/. With Parsley, you could add the array collection to the context and simply inject it whenever you need to reference it. The array collection should be populated during application startup and can be updated as needed.
There basically are two ways. The singleton way, and the static class way. A singleton is a class that is only instanciated once, through a mechanism described here, for instance. A static class is a bit different from a regular class : you will not instanciate it, first of all.
For more information about how implement a singleton in ActionScript 3 : here.
For more information about static classes and variables : here.
You can just make it public member of some class and import that class in all MXML-based classes:
public class DBWrapper {
[Bindable]
public var ItemList:ArrayCollection;
}
I usually make it a static member of a Globals class
public class Globals {
[Bindable] public var iCollection:ArrayCollection;
}
It can be accessed from anywhere in the program (provided you have assigned a valid ArrayCollection to it first)
combobox.dataProvider=Globals.iCollection;

Copying an instance of a class

Ok, ObjectUtil.copy is a good technique for copying Objects. But after having a lot of problems using it to copy other classes, I guess it is not the solution I'm after.
How would you approach the copying/cloning of instances of a class that you've defined? Maybe defining a function withing the class to copy it?
It is cool that most variables are passed by reference in flex, but sometimes is annoying not having control over this (sorry, I'm too used to plain C).
Thanks!
UPDATE:
To be more precise, as I can't make the ObjectUtil.copy() work with a custom class is... is there a way to copy, by using serialization, a custom class? Did you use successfully a ByteArray copy with a custom class?
Thanks for all the replies.
If you determine that implementing a clone interface is not the correct approach in your situation, I suggest looking at the ByteArray object. I haven't used it myself, but it appears to give you all the control you should need over individual bytes. You can reading and writing from and to any object.
Senocular does a quick overview of it here.
function clone(source:Object):* {
var copier:ByteArray = new ByteArray();
copier.writeObject(source);
copier.position = 0;
return(copier.readObject());
}
Good luck!
ObjectUtil.copy uses ByteArray internally to create a copy. In order for the copy to be successful, ByteArray requires that the flash player will be aware of you custom class. You do that by registering your class using the global registerClassAlias method.
For example:
//one time globally to the application.
registerClassAlias(getQualifiedClassName(CustomClass), CustomClass);
//then
var c1:CustomClass = new CustomClass();
c1.name = "customClass";
var c2:CustomClass = ObjectUtil.copy(c1);
trace(ObjectUtil.toString(c1))
trace(ObjectUtil.toString(c2))
If you have control over the whole class hierarchy, I recommend implementing a clone() interface in every class. It's tedious, but will pay off as complexity increases.
(Forgive me if the syntax is a bit off, it's been a while)
// define a "cloneable" interface
public interface ICloneable {
function clone() : Object;
}
For every class, implement the method...
public class MyClass1 implements ICloneable {
...
public function clone() : Object {
var copy:MyClass1 = new MyClass1();
// copy member variables... if it is a user-defined object,
// make sure you call its clone() function as well.
return copy;
}
}
To create a copy of the object, simply invoke the clone() function.
var copy:MyClass1 = original.clone();
As a side note, both Java and .NET seem to have adopted the clone methods on their base Object classes. I know of no analogous method for ActionScript's Object class.
Two common idioms:
a clone method
a copy constructor
Both of these let you define what exactly making a copy means--you may want some things copied shallowly and others deeply.

Extending Flex FileReference class to contain another property

I want to extend the FileReference class of Flex to contain a custom property. I want to do this because AS3 doesn't let me pass arguments to functions through event listeners, which makes me feel sad, so I need this property to exist on the event target, so I can access it.
I also want to be able to cast extant FileReference objects to this class without any fuss. I have:
var fr:SmxFR = e.target as SmxFR
and I want that to work; right now it just returns null.
A blank, newly instantiated SmxFR object has the extended property in place, but all of its inherited properties and objects return Error: Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.
This is the class I am using, SmxFR.as:
package
{
import flash.net.FileReference;
public class SmxFR extends FileReference
{
public var housenum:String = "";
public function SmxFR()
{
super();
}
}
}
Kept it as straightforward as I could, really. Can someone please help me figure this out? Thanks.
Edit:
Per request, this is the instantiation which results in the aforementioned error in all inherited objects:
var fr:SmxFR = new SmxFR();
I get living handle property from that, and all other (that is, inherited) properties throw Error #2037.
So, maybe what I want to do is going to require overriding FileReferenceList? If the original objects must be instantiated to SxmFR, that's what I'll have to do, since I'm using FRL to allow the user to select multiple files at once. Are you guys sure there is no way to fast from a FileReference to my class?
You can totally pass objects via event listeners, it's just done in a specific way. I'd learn to do it correctly, rather than trying to extend a core library which could cause you problems later if you make a small mistake.
My solution: instead of extending FileReference, extend Event and add your properties to that.
var myEvent:MyExtendedEvent = new MyExtendedEvent();
myEvent.myCustomProperty = myValue;
dispatchEvent(myEvent);
Then in your handler you just write:
function myEventHandler(e:MyExtendedEvent):void {
trace(e.myCustomProperty);
}
Much more painless to go down this road! The added benefit is that if any other Flash Developer anywhere ever looks at your code they're not going to get hit in the face with a non-standard customized FileReference. :)
When e.target is instantiate as FileReference you can't cast it to SmxFR because it's not in the line of inheritance. In the other way you can a SmxFR Object to FileRefernce.
Extending FileReferenceList is not going to be helpful. FileReferenceList.browse() method creates an array of FileReference object when user selects multiple files - that happens internally (may be in its private methods) and you cannot change that behavior and force it to create SxmFR objects instead. Use custom events as Myk suggested.
This article talks about Sound objects, but may be that's applicable to FileReference objects too. May be you cannot reuse them. Post the code where you use the SmxFr class and get the said error.

Resources