Reputation: 2123
I'm writing a program that requires the user to be very flexible in manipulating data on a given object. I figured I would use a property browser of some kind; Qtilities' ObjectDynamicPropertyBrowser
caught my eye.
However, I need to be able to add my own data types. The documentation is not clear on how to do so.
How can I allow my own data types to be represented in Qtilities' property browser widgets?
Also, more about my needs:
Q_OBJECT
s.Q_DECLARE_METATYPE
is okay.Upvotes: 0
Views: 602
Reputation: 98425
The browser you refer to depends on the QObject
property system. So, unless your classes are QObjects, it won't work - but don't despair, Qt 5.5 to the rescue (read on). The browser seems to use a QTreeView
and provides an adapter model that exposes the QObject
property system. So, it leverages Qt's type and delegate system.
In Qt 5.5, there is a general purpose property system, known as gadgets, that can be used on any class, as long as there is a QMetaObject
describing that class. By adding the Q_GADGET
macro to a class deriving from the subject class, and describing the properties using Q_PROPERTY
macro, you can leverage moc
and the gadget system to access your unmodified types' properties.
The only reason you'd do that is to require minimal changes to the ObjectPropertyBrowser
system. You don't want the ObjectDynamicPropertyBrowser
, since it works on dynamic properties, and your objects don't have any. They have static properties, given through Q_PROPERTY
macros and code generated by moc.
So, you'll proceed as you would for implementing your own type support for QVariant
and views in general. You also need Qt 5.5, since you need gadget support for it to work. A solution for Qt 5.4 and below requires a different approach and might be less cumbersome to implement in another way.
See this answer for a reference on using gadget property system for object serialization, it's fundamentally what the property browser would do, sans the serialization proper of course.
There are three steps. First, you need to address simple custom types that don't have a structure, but represent a single value (such as a date, or time, or geographic position, etc.), or a collection of simple values (such as a matrix).
Ensure that QVariant
can carry the simple types. Add the Q_DECLARE_METATYPE
macro right after the type's definition in an interface (header file).
Implement delegates for the types. For types with table structure, such as a matrix, you can leverage QTableView
and provide an adaptor model that exposes the type's contents as a table model.
Secondly, you get to your complex types that have internal structure:
Create a wrapper class that derives from the complex type, declares all properties using Q_PROPERTY
, and has the Q_GADGET
macro (not Q_OBJECT
since they are not QObjects). Such class should not have any members of its own. Its only methods should be optional property accessors. The Q_GADGET
macro adds the static (class) member staticMetaObject
.
The underlying type can be static_cast
to the wrapper class if needed, but that's normally not necessary.
At this point, any class that you wrote a wrapper for is accessible to the QMetaProperty
system directly, without casting! You'd use the wrapper's staticMetaObject
for its static metaobject, but the QMetaProperty
readOnGadget
and writeOnGadget
will take the pointers to the base class directly.
Thirdly, since ObjectPropertyBrowser
most likely doesn't implement the support for gadgets in Qt 5.5, as that's quite new, you'll have to modify it to provide such support. The changes will be minimal and have to do with using QMetaProperty::readOnGadget
and QMetaProperty::writeOnGadget
instead of QMetaProperty::read
and QMetaProperty::write
. See the serialization answer for comparison between the two.
Upvotes: 1