Dynami c присваивание переменных Q_Property - PullRequest
0 голосов
/ 10 февраля 2020

Итак, вот ситуация

QQmlApplicationEngine* engine;
QQmlContext* ctxt;

class Fruit: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString type MEMBER m_type NOTIFY fruitChanged)

private:
    QString m_type;
public:
    virtual void initFruit() = 0;

    void startEating(){
        initFruit();
        ctxt->setContextProperty("fruit", this);
        engine->load(QUrl(QLatin1String("qrc:/qml/main.qml"))); 

       app.exec();
       engine->quit();
       engine->deleteLater();
    }

    void setType(QString fruit){
        m_type = fruit;
        emit fruitChanged();
    }
signals:
    fruitChanged();
};

class Apple:public Fruit{
public:
    explicit Appl(QObject *parent = nullptr);

    void initFruit(){
        Slice slice = new Slice();    // some other class
        ctxt->setContextProperty("slice", slice);
    }
};

class Banana:public Fruit{
public:
    explicit Banana(QObject *parent = nullptr);

    void initFruit(){
        Peel peel = new Peel();      // some other class
        ctxt->setContextProperty("peel", peel);
    }
};

class Peel: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString color MEMBER m_peelColor NOTIFY peelChanged)

private:
    QString m_peelColor;
signals:
    void peelChanged();
public:
    void someFunction(QString peelColor){
        m_peelColor = peelColor;
        emit peelChanged();
    }
}

class Slice: public QObject
{
    Q_OBJECT
    Q_PROPERTY(int number MEMBER m_slices NOTIFY sliceChanged)

private:
    QString m_slices;
signals:
    void sliceChanged();
public:
    void someFunction(QString slices){
        m_slices = slices;
        emit sliceChanged();
    }
}

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    Fruit *fruit;

    if (argv[1] == "Apple"){
        fruit = new Apple();
    }
    else if (argv[1] == "Banana"){
        fruit = new Banana();
    }

    engine = new QQmlApplicationEngine();
    ctxt = engine->rootContext();

    fruit->setType(argv[1].toString());
    fruit->startEating();
}

Затем в main.qml

...
Rectangle{
     Text {
        text: {    // I want to remove this if else statement
            if(fruit.type == "Apple")
                slice.number
            else if(fruit.type == "Banana") 
                peel.color
        }
    }
}

Вы можете представить, насколько большим может быть мое утверждение if-else в main.qml при увеличении количество фруктов. Поэтому мне интересно, есть ли другой способ обработки такого сценария, где я могу как-то просто присвоить тексту в qml одно значение, и оно динамически загружает правильное внутреннее свойство.

1 Ответ

1 голос
/ 11 февраля 2020

Вместо регистрации новых типов данных в методе initFruit и использования глобальных переменных лучше создать класс провайдера:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include <cstring>

class Fruit: public QObject
{
    Q_OBJECT
public:
    virtual Q_INVOKABLE QString name() = 0;
};
class Apple: public Fruit{
public:
    QString name(){
        return "apple";
    }
};
class Banana: public Fruit{
public:
    QString name(){
        return "banana";
    }
};
class FruitProvider: public QObject{
    Q_OBJECT
    Q_PROPERTY(Fruit* fruit READ fruit WRITE setFruit NOTIFY fruitChanged)
public:
    FruitProvider(QObject *parent=nullptr):QObject(parent){}
    Fruit* fruit() const{
        return m_fruit.get();
    }
public slots:
    void setFruit(Fruit* fruit){
        m_fruit.reset(fruit);
        emit fruitChanged();
    }
Q_SIGNALS:
    void fruitChanged();
private:
    QScopedPointer<Fruit> m_fruit;
};

int main(int argc, char *argv[]){
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    FruitProvider provider;
    if(argc < 1){
        return -1;
    }
    if (std::strcmp(argv[1], "Apple") == 0){
        provider.setFruit(new Apple());
    }
    else if (std::strcmp(argv[1], "Banana") == 0){
        provider.setFruit(new Banana());
    }
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("provider", &provider);
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}
#include "main.moc"
Text{
    text: provider.fruit.name()
}

Обновление:

Как я указывал в комментариях, идея исключения if-elseif-else заключается в стандартизации доступа к свойствам, в случае с Fruit вы можете использовать провайдера. В случае свойств «число» и «цвет» вы можете создать универсальное свойство c, которое обновляется каждый раз, когда изменяются другие свойства, и использовать это свойство для доступа к информации в QML.

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include <cstring>

class Peel: public QObject{
    Q_OBJECT
    Q_PROPERTY(QString color MEMBER m_peelColor NOTIFY peelChanged)
private:
    QString m_peelColor;
signals:
    void peelChanged();
public:
    void someFunction(QString peelColor){
        m_peelColor = peelColor;
        emit peelChanged();
    }
};
class Slice: public QObject{
    Q_OBJECT
    Q_PROPERTY(int number MEMBER m_slices NOTIFY sliceChanged)
private:
    int m_slices;
signals:
    void sliceChanged();
public:
    void someFunction(int slices){
        m_slices = slices;
        emit sliceChanged();
    }
};
class Fruit: public QObject{
    Q_OBJECT
    Q_PROPERTY(QVariant common MEMBER m_common NOTIFY commonChanged)
public:
    void startEating(){
        initFruit();
    }
    QVariant common() const{
        return m_common;
    }
Q_SIGNALS:
    void commonChanged();
protected:
    virtual void  initFruit() = 0;
    void setCommon(QVariant common){
        m_common = common;
        emit commonChanged();
    }
private:
    QVariant m_common;
};
class Apple: public Fruit{
public:
    void initFruit(){
        slice.reset(new Slice());
        slice->someFunction(100);

        setCommon(slice->property("number"));
        connect(slice.get(), &Slice::sliceChanged, [this](){
            setCommon(slice->property("number"));
        });
    }
private:
    QScopedPointer<Slice> slice;
};
class Banana: public Fruit{
public:
    void initFruit(){
        peel.reset(new Peel());
        peel->someFunction("red");
        setCommon(peel->property("color"));
        connect(peel.get(), &Peel::peelChanged, [this](){
            setCommon(peel->property("color"));
        });
    }
private:
    QScopedPointer<Peel> peel;
};
class FruitProvider: public QObject{
    Q_OBJECT
    Q_PROPERTY(Fruit* fruit READ fruit WRITE setFruit NOTIFY fruitChanged)
public:
    Fruit* fruit() const{
        return m_fruit.get();
    }
public slots:
    void setFruit(Fruit* fruit){
        m_fruit.reset(fruit);
        emit fruitChanged();
    }
Q_SIGNALS:
    void fruitChanged();
private:
    QScopedPointer<Fruit> m_fruit;
};

int main(int argc, char *argv[]){
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    FruitProvider provider;
    if(argc < 1){
        return -1;
    }
    if (std::strcmp(argv[1], "Apple") == 0){
        provider.setFruit(new Apple());
    }
    else if (std::strcmp(argv[1], "Banana") == 0){
        provider.setFruit(new Banana());
    }

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("provider", &provider);
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    provider.fruit()->startEating();

    return app.exec();
}
#include "main.moc"
Text{
    text: provider.fruit.common
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...