Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Developer
simon_hain
Posts: 16,282
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
Accepted Solution

Access a QVariant (of a custom class) in QML

As a follow up to http://supportforums.blackberry.com/t5/Cascades-Development/Use-a-custom-class-in-a-qml-signal/td-p/...

 

I receive a signal with a complex datatype i defined in c++, OutgoingInputs.

When i use console.log("received "+outgoingInputs) in QML i get this:

Debug: received QVariant(OutgoingInputs*)

The c++ class has several properties published using Q_PROPERTY, but i cannot use them on the qvariant.

In c++ i would call convert on the qvariant, but how do i do that in QML?

 

----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Developer
kylefowler
Posts: 526
Registered: ‎05-17-2009
My Device: 9900

Re: Access a QVariant (of a custom class) in QML

You shouldnt have to do anything. Once the variable is available in QML you should just be able to use the . accessor of the property. item.property1

Like all of my posts
Developer
simon_hain
Posts: 16,282
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport

Re: Access a QVariant (of a custom class) in QML

Good to know, but it does not seem to.

 

I am trying it with my DataServiceError class:

class DataServiceError: public QObject {
	Q_OBJECT
	Q_PROPERTY(QString errorMessage READ getErrorMessage)
	Q_PROPERTY(QString errorType READ getErrorType)
public:
QString getErrorMessage() const;
void setErrorMessage(QString errorMessage);
QString getErrorType() const;
void setErrorType(QString errorType);
//...

 In c++ i create an object and emit a signal with it:

DataServiceError* error = new DataServiceError();
error->setErrorMessage("error message");
error->setErrorType("error type");
emit signalWithError(somestring, error, someotherstring)

In QML i receive the signal and can access somestring and someotherstring.

The error is logged as QVariant(DataServiceError*)

console.log("values: " + somestring+ " " + error + " " + someotherstring)

results in:

Debug: onErrorSignal values: somestringValue QVariant(DataServiceError*) someotherstringValue

 Now i am trying to access the properties of the error:

console.log("error values: " + error.errorMessage + " " + error.errorType)

 This results in:

Debug: error values: undefined undefined

 

 

 

----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Developer
kylefowler
Posts: 526
Registered: ‎05-17-2009
My Device: 9900

Re: Access a QVariant (of a custom class) in QML

One think you could try just for the heck of it is make one of the getter methods be Q_INVOKABLE and call the method directly instead of trying to access the property. Also, do you know if error itself is defined? Ive always felt like Ive seen a console error that says that its an undefined property, not just undefined value. Could put a breakpoint in the getter too to see if its trying to do the right thing.

Like all of my posts
Developer
simon_hain
Posts: 16,282
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport

Re: Access a QVariant (of a custom class) in QML

Good ideas Kyle, i have tried them today.
First, i have wrapped the console.log with a try/catch, and also changed the name of the parameter.


The parameter is called dsError and i still get QVariant(DataServiceError*) when i log it.

I made getErrorMessage() Q_INVOKABLE.

Here is the other debug code:

try {
     console.log("error property values: " + dsError.errorMessage + " " + dsError.errorType)
} catch (error) {
  onsole.log("error on property: " + error)
}
try {
  console.log("error invokable: " + dsError.getErrorMessage)
} catch (error) {
   console.log("error on invokable: " + error)
}

 output is the same as before, all undefined, the try/catch is not triggered:

 

Debug: error property values: undefined undefined
Debug: error invokable: undefined

 

 

----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Developer
markwilcox
Posts: 51
Registered: ‎11-23-2012
My Device: BB10 Dev Alpha

Re: Access a QVariant (of a custom class) in QML

This is really just an educated guess but I think the problem may be that your QVariant only holds a pointer to the class and not the class itself. Since in JavaScript we don't deal with pointers and thus don't have a dereference -> and just a . operator (which is basically equivalent of the C++ one) you're trying to access properties of the pointer and it doesn't have any.

 

Does that make sense?

 

Almost everything in Qt is passed by value or reference and not by pointer. Internally Qt implements shared memory with copy-on-write semantics to make that work without massive memory and copying overheads.

 

Developer
simon_hain
Posts: 16,282
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport

Re: Access a QVariant (of a custom class) in QML

I can access pointers just fine if i use them with setContextProperty, they seem to be automatically dereferenced.

And how would i pass a reference in a signal? Wouldn't the object created in the c++ method be deleted when the method finishes?

----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Developer
markwilcox
Posts: 51
Registered: ‎11-23-2012
My Device: BB10 Dev Alpha

Re: Access a QVariant (of a custom class) in QML

[ Edited ]

The only pointer QML recognises out of the box is a QObject pointer.  <I think> QObject subclass properties can only be accessed from QML if the type has been registered with the declarative engine - did you do that already?  Maybe that's what you're missing?

 

The magic where QML automatically creates JavaScript lists and objects you can access parts of only works for QVariantLists and QVariantMaps.

 

Did you read this:

http://doc.qt.digia.com/qt/qtbinding.html#exchanging-data-between-qml-and-c

 

A reference is really just a const pointer to const that uses a more convenient syntax, there are no scope issues with using them when you don't want to pass ownership.  Traditional C++ best practice says you should always use references when you're not passing ownership.  However, Qt is a bit evil looking to traditional C++ programmers, until you get used to it, then it's fantastic - their shared memory implementation has reference counting so you can pass and return things like QStrings by value and they don't go out of scope - they get shallow copied and the reference count is incremented.  This does not automatically apply to all Qt classes though, so check the docs for whatever you are using.

 

As such, passing references around in signals is common and sometimes things even get passed by value. When signals are queued rather than direct, Qt makes a copy of the arguments anyway.

 

I noted in your original error that the parameter was getting passed as a QVariant of pointer type, rather than a QObject pointer, so that's why I suspected a dereferencing problem.

Developer
simon_hain
Posts: 16,282
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport

Re: Access a QVariant (of a custom class) in QML

I am using qmlRegisterType to register the class like this:

qmlRegisterType<DataServiceError>("com.isec7.materials", 1, 0, "DataServiceError");

All classes subclass QObject, of course.

 

Maybe it helps if i describe my usecase.

I get some UI definitions from a webservice. After parsing the webservice reply i hand the results over to QML, where i build the UI from it.

As far as i understood c++ i have to create all the objects with "new", as the webservice method asynchronically passes the signal and then ends, thus causing other objects to get out of scope.

(If i use references, would i have to implement the copy constructors in all the classes? and use the metatype macro?)

----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Developer
markwilcox
Posts: 51
Registered: ‎11-23-2012
My Device: BB10 Dev Alpha

Re: Access a QVariant (of a custom class) in QML

So I guess from your enormous number of posts here that your background is in Java rather than C++? :smileyhappy:

 

If you don't create objects with new then they are created on the stack - this is generally not a good thing for all but the smallest of classes.  Using new creates them on the heap.  Qt breaks this basic rule with several of its basic types (e.g. QString, QByteArray) by allocating and managing heap memory within them.

 

C++ dynamically generates a shallow copy constructor for you, so if you don't write one then you can still pass by value but e.g. a pointer member inside your class would only get it's value copied and not the data that points to.

 

This is probably not the best place for C++ tutorials though. :smileyhappy:  What sort of data do you get back from your web service?  JSON or XML?  There are already some decent examples around for passing that kind of data into QML.