Например, у меня есть enum из сторонней библиотеки:
namespace Lib {
enum class Foo {
Bar,
Baz
};
};
Я попытался использовать следующую оболочку
namespace Qml {
Q_NAMESPACE
using Foo = Lib::Foo;
Q_ENUMS(Foo)
}
с qmlRegisterUncreatableMetaObject
, но у меня это не работает.
Могу ли я зарегистрировать один в Meta Object System
для использования в QML
, но без дубликатов, например:
class QmlObject {
Q_GADGET
public:
enum Foo {
Bar = Lib::Bar,
Baz = Lib::Baz
};
Q_ENUM(Foo)
};
Версия Qt
это 5.15.2
. Спасибо.
Вероятно, это не лучший ответ, но вы можете объявить свое перечисление в QObject
, и оно будет зарегистрировано, когда вы зарегистрируете QObject
:
#include <QObject>
class QmlObject : public QObject {
Q_OBJECT
public:
QmlObject(QObject* parent = nullptr) : QObject(parent) { }
enum Foo {
Bar = Lib::Bar,
Baz = Lib::Baz
};
Q_ENUMS(Foo)
};
qmlRegisterType<QmlObject>("MyApp", 1, 0, "QmlObject");
Но чтобы использовать стороннюю библиотеку, вам нужно использовать static_cast
для перемещения ваших перечислений из QmlObject::Foo
в Lib::Foo
, например.
Lib::Foo libFoo = static_cast<Lib::Foo>(qmlFoo);
Мы делаем то же самое сейчас, но я хочу остановить это. Это не ответ.
Альтернативой QObject может быть не создаваемый QObject, такой как singleton, или, возможно, в QGadget?
Использование одноэлементной оболочки для каждого отдельного перечисления звучит как переплата.
Вы просто помещаете все свои перечисления в 1 синглтон. Подобно одноэлементному объекту Qt. github.com/qt/qtbase/blob/dev/src/corelib/global/qnamespace.h
Я спрашиваю об огромном количестве сторонних перечислений, которые могут измениться. Я не хочу их дублировать.
Это интересная проблема. Решение может быть не связано с тем, что вы делаете с moc, так как это сужает область действия и на самом деле может быть неразрешимым. Следовательно, ваш вопрос StackOverflow есть решение этой проблемы. Но, в более общем смысле, управление, возможно, каждым изменяющимся набором перечислений от вашего поставщика. Что ж, вы можете (1) взаимодействовать с поставщиком и запрашивать, как они предлагают перечисления, чтобы вы могли лучше автоматизировать их сопоставления с Qt, или (2) создавать сценарий импорта самостоятельно (например, python для сканирования заголовков или инструмент документации (такой как qdoc), чтобы реконструировать его из комментариев).
Я нашел решение, используя библиотеку magic_enum (минимум v0.8.1, см. ограничения ) и небольшую модификацию в реализации qmlRegisterType:
#include <QtQml/qqmlprivate.h>
#include <QtCore/private/qmetaobjectbuilder_p.h>
#include <magic_enum.hpp>
template<class T, class ... En>
int qmlRegisterTypeWithEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
QML_GETTYPENAMES
//! register our enums here
QMetaObjectBuilder builder(&T::staticMetaObject);
([](QMetaObjectBuilder & builder)
{
QMetaEnumBuilder enumBuilder {
builder.addEnumerator(QByteArray::fromStdString(std::string{magic_enum::enum_type_name<En>()}))
};
enumBuilder.setIsScoped(magic_enum::is_scoped_enum_v<En>);
constexpr auto entries = magic_enum::enum_entries<En>();
for (const auto & pair : entries) {
enumBuilder.addKey(QByteArray::fromStdString(std::string{pair.second}), static_cast<int>(pair.first));
}
}(builder), ...);
//! ***************************
QQmlPrivate::RegisterType type = {
0,
qRegisterNormalizedMetaType<T *>(pointerName.constData()),
qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
sizeof(T), QQmlPrivate::createInto<T>,
QString(),
uri, versionMajor, versionMinor, qmlName, builder.toMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
nullptr, nullptr,
nullptr,
0
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
Теперь для стороннего перечисления
namespace Lib {
enum class Foo {
Bar = 2,
Baz = 4
};
};
и целевой класс Qt
namespace SomeQml {
class QmlItem : public QObject
{
Q_OBJECT
using Foo = Lib::Foo; // its important use without namespace in declaration
Q_PROPERTY(Foo prop MEMBER m_val NOTIFY propChanged)
...
Q_INVOKABLE handleFoo(Foo v);
...
};
}
просто вызовите и используйте на стороне QML как QmlItem.Bar
или QmlItem.Baz
как целое число:
qmlRegisterTypeWithEnums<QmlItem, Lib::Foo>("my.pack", 1, 0, "QmlItem");
Согласно kdab.com/new-qt-5-8-meta-object-support-namespaces вы должны использовать Q_ENUM_NS, и вы можете изменить
Qml
вLib
в своем коде-оболочке и пропуститьusing
, но с этим я не могу сделать это работает либо