Reputation: 170
So here is the situation
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();
}
Then in 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
}
}
}
You can imagine how big my if-else statement in main.qml can get as I increase the number of fruits. So I am wondering if there is a different way of handling such a scenario where I can somehow just assign the text in qml one value and it dynamically loads the right back-end property.
Upvotes: 0
Views: 491
Reputation: 243975
Instead of registering new data types in the initFruit method and using global variables it is better to create a provider class:
#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()
}
Update:
As I pointed out in the comments, the idea of eliminating if-elseif-else is to standardize access to properties, in the case of Fruit you can use provider. In the case of the "number" and "color" properties, you can create a generic property that is updated every time the other properties are modified and use that property to access the information in 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
}
Upvotes: 1