I'm not sure if something like this is possible, but I am attempting to dynamically generate a GUI based on properties that have been registered into Qt's property system. My assumption is that since I have registered a property using Q_PROPERTY() in this fashion:
Q_PROPERTY(propertyType propertyName WRITE setPropertyName READ getPropertyName NOTIFY propertynameSignal)
I should be able to retrieve the signature of the write or read functions for connection using the connect() function. The goal of this is to have a dialog connected to this object for modifying properties, but without having to hand write all of it. Is this possible, am going about it the wrong way, or should I just hardcode the dialog?
EDIT 1: I'll share some of the code (stripped down) I have which will hopefully make it more obvious as to what I'm trying to do:
Class declaration for particular class:
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(bool someBool READ getBool WRITE setBool)
public:
bool someBool;
bool getBool();
void setBool(bool);
}
QDialog subclass that points to this Object:
void MyDialog::generateUI()
{
const QMetaObject* metaObject = _MyObjectPtr->metaObject();
for (int i = 0; i < metaObject->propertyCount(); ++i)
{
QMetaProperty property = metaObject->property(i);
if (!strcmp(property.typeName(), "bool")
{
QCheckBox* checkBox = new QCheckBox(this);
bool state = metaObject->property(property->name()).toBool();
checkBox->setCheckState((state) ? Qt::Checked : Qt::Unchecked);
// Add checkBox to QDialog layout widgets here
}
}
}
Forgive all the My* renamings, but I need to keep my actual class/member names private.
I can confirm that the object pointed to by MyObjectPtr is being read from properly, because the starting values reflect values that I expect when I change them around. The trouble is connecting this back to that object. I can change the values inside the checkbox GUI-side, but the values aren't being sent to the actual object pointed to by _MyObjectPtr.
To retrieve the signature of QObject's methods (signals, slots, etc.) you can use meta object (QMetaObject
) information. For example the following code (taken from Qt documentation) extracts all methods' signatures of the object:
const QMetaObject* metaObject = obj->metaObject();
QStringList methods;
for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
methods << QString::fromLatin1(metaObject->method(i).signature());
To check whether the method is a slot or a signal, you can use QMetaMethod::methodType()
function. For signature use QMetaMethod::signature()
(refer to the example above).
UPDATE After @HD_Mouse updated the question with additional information about his idea to created dynamic GUI based on an object's properties, I came up with the following code that could solve the problem:
Add member variable that will store the mapping between GUI component and corresponding property index:
class MyDialog : public QDialog
{
[..]
private:
/// Mapping between widget and the corresponding property index.
QMap<QObject *, int> m_propertyMap;
};
When a GUI component created (check box), connect its changing signal to the special slot that will handle the corresponding property update.
void MyDialog::generateUI()
{
const QMetaObject* metaObject = _MyObjectPtr->metaObject();
for (int i = 0; i < metaObject->propertyCount(); ++i)
{
QMetaProperty property = metaObject->property(i);
if (!strcmp(property.typeName(), "bool")
{
QCheckBox* checkBox = new QCheckBox(this);
bool state = metaObject->property(property->name()).toBool();
checkBox->setCheckState((state) ? Qt::Checked : Qt::Unchecked);
// Add checkBox to QDialog layout widgets here
// Store the property and widget mapping.
connect(checkBox, SIGNAL(stateChanged(int)),
this, SLOT(onCheckBoxChanged(int)));
m_propertyMap[checkBox] = i;
}
}
}
When a check box state changed, find the corresponding property (use mapping) and update it according to the check box state:
void MyDialog::onCheckBoxChanged(int state)
{
QObject *checkBox = sender();
QMetaObject* metaObject = _MyObjectPtr->metaObject();
int propertyIndex = m_propertyMap.value(checkBox);
QMetaProperty property = metaObject->property(i);
// Update the property
_MyObjectPtr->setProperty(property.name(), bool(state == Qt::Checked));
}