2

我有几个QObject类,它们可能具有QList存储QObject派生类列表的属性:

class Object : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<AnotherQObject*> otherObjects READ otherObjects)
public:
    QList<AnotherQObject*> otherObjects() const;
}

QList<AnotherObject*>当然已经在Q_DECLARE_METATYPEand注册了qRegisterMetaType()

现在我想用 Qt 的元对象系统来读取这个属性。在我想阅读列表的时候,我只关心(并且知道)列表包含指向对象的指针,这些指针是从 派生的QObject,而不是确切的类型。

当我将属性转换QVariantQList<QObject *>列表时为空。

QObject *object = getObjectFromSomeWhere();
const char* propertyName = getPropertyNameFromSomeWhere(); // "otherObjects"

QVariant list = object->property(name);
QList<QObject *> objectList = list.value<QList<QObject *> >(); // empty

QList<AnotherQObject*> anotherObjectList = 
    static_cast<Object*>(object)->otherObjects() // not empty

是否可以访问此列表?您还有其他建议吗?

编辑:虽然我发布了我的解决方案,但我仍然喜欢评论:-)

4

2 回答 2

3

如果您使用的是 Qt 5.2 或更高版本,则有一个 QSequentialIterable 类,它允许您执行此操作而无需额外模板、修改宏和额外注册的开销。

http://qt-project.org/doc/qt-5/qsequentialiterable.html

如果您将 aQList<T*>存储在 a 中QVariant,其中 T 派生自QObject,则可以从变体中获取一个QSequentialIterable实例,这允许您将列表中的每个项目作为 a 进行迭代QVariant。然后,您可以简单地将每个项目的值获取为 a QObject*,并随时添加到 a QList<QObject*>(但请确保您测试了该类型派生自 的假设QObject):

QList<QObject*> qobjectList;
if (variant.canConvert(QMetaType::QVariantList)) {
    QSequentialIterable iterable = variant.value<QSequentialIterable>();
    foreach (const QVariant& item, iterable) {
        QObject* object = item.value<QObject*>();
        if (object) { qobjectList.append(object); }
    }
}
于 2014-10-14T02:20:12.303 回答
2

我想我很简单地解决了这个问题。我创建了一个模板类,它可以将QVariant包含 a 的 a转换QList<TemplateParameter *>QList<QObject *>.

我还有一个单例,它存储一个QMap<int, Converter *>,它映射QVariant::userType()到相应的转换器。

这允许我注册每个类,我想将其存储在属性中,如下所示:

VariantToObjectListConverter::instance()->registerConverter<AnotherQObject>();

然后我可以转换 unknown QVariants

QVariant list = object->property("otherObjects");
QList<QObject *> objects = VariantToObjectListConverter::instance()->convert(variant);

这是必要的代码:

class ConverterBase
{
public:
    virtual ~ConverterBase() {}
    virtual QList<QObject *> convert(const QVariant &variant) const = 0;
};

template<class Object>
class Converter : public ConverterBase
{
public:
    QList<QObject *> convert(const QVariant &variant) const
    {
        QList<Object *> list = variant.value<QList<Object *> >();
        QList<QObject *> result;
        Q_FOREACH(Object *object, list) result.append(object);
        return result;
    }
};

class VariantToObjectListConverter
{
public:
    Q_GLOBAL_STATIC(VariantToObjectListConverter, instance)

    ~VariantToObjectListConverter()
    {
        QHashIterator<int, ConverterBase *> i(m_converters);
        while (i.hasNext()) {
            i.next();
            delete i.value();
        }
    }

    template<class Object>
    void registerConverter()
    {
        QVariant v = QVariant::fromValue<QList<Object *> >(QList<Object *>());
        m_converters.insert(v.userType(), new Converter<Object>());
    }

    QList<QObject *> convert(const QVariant &variant) const
    {
        ConverterBase *converter = m_converters.value(variant.userType());
        if (!converter)
            return QList<QObject *>();

        return converter->convert(variant);
    }

private:
    QHash<int, ConverterBase *> m_converters;

    VariantToObjectListConverter() {}
};

我现在可以添加一个宏,它调用registerConverter(),Q_DECLARE_METATYPEqRegisterMetaType(), 这样用户只需调用

REGISTER_TYPE(TypeName)
于 2013-01-30T11:16:38.770 回答