I basically just want to use multiple derived classes to change a member variable of a base class and to forward that value to qml using qproperty, but for some reason it's not working
car.h
#include <QObject>
class Car : public QObject{
Q_OBJECT
Q_PROPERTY(int seats MEMBER m_seats NOTIFY updateSeats)
public:
explicit Car(QObject *parent = 0);
~Car();
int m_seats;
Q_INVOKABLE void test();
signals:
void updateSeats();
};
car.cpp
#include "car.h"
Car::Car(QObject *parent) :
QObject(parent),
m_seats(0)
{
}
Car::test(){
m_seats = 5;
emit updateSeats();
}
Car::~Car(){}
toyota.h
#include "car.h"
class Toyota : public Car{
Q_OBJECT
public:
explicit Toyota(QObject *parent = 0);
~Toyota();
void foundCar();
};
toyota.cpp
#include "toyota.h"
Toyota::Toyota(QObject *parent)
{
}
Toyota::foundCar(){
m_seats = 4;
emit updateSeats();
}
Toyota::~Toyota(){}
Now, after invoking the foundCar function in class Toyota, if I do
console.log(car.seats) in qml I get 0, but I expect it to be 4 because I am modifying it in the derived class.
However if I call car.test() from qml and then I print car.seats, the value is 5. I am confused why this is the case. In qml I want car.seats to be 4. What am I missing?
Toyota object is derived class object Toyota of base Car not an object of Car you are modifying derived class object member Toyota::m_seats and that won't have any effect on direct base Car object .. and because Q_PROPERTY is defined only in base class Car .. the only value QML would see is base class object .. and specifically the object you set in setContextProperty ... the code you omitted after the post edit.
From previous edits in your post, you seem to set the setContextProperty in your engine as Car object .. its in this object where you need to modify member that is a Q_PROPERTY.
I am referring to your code:
Car::startGui(){
QQmlApplicationEngine engine;
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("car", this)
// start engine, which works properly
}
Related
I basically just want to use multiple derived classes to change a member variable of a base class and to forward that value to qml using qproperty, but emitting the signal isn't working and I am not able to make the signal static
car.h
#include <QObject>
class Car : public QObject{
Q_OBJECT
Q_PROPERTY(int seats MEMBER m_seats NOTIFY updateSeats)
public:
explicit Car(QObject *parent = 0);
~Car();
static int m_seats;
signals:
void updateSeats();
};
car.cpp
#include "car.h"
Car::Car(QObject *parent) :
QObject(parent)
{
}
int Car::m_seats = 0;
Car::~Car(){}
toyota.h
#include "car.h"
class Toyota : public Car{
Q_OBJECT
public:
explicit Toyota(QObject *parent = 0);
~Toyota();
Q_INVOKABLE void foundCar();
};
toyota.cpp
#include "toyota.h"
Toyota::Toyota(QObject *parent)
{
}
Toyota::foundCar(){
m_seats = 4;
emit updateSeats(); // This isn't working
}
Toyota::~Toyota(){}
main.cpp
#include <QGuiApplication>
#include "car.h"
#include "toyota.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Car car = new Car();
Toyota ty = new Toyota();
QQmlApplicationEngine engine;
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("car", car);
ctxt->setContextProperty("toyota", ty);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
app.exec();
engine.quit();
}
In qml when I print car.seats after invoking the foundCar function
main.qml
toyota.foundCar()
console.log(car.seats)
the output is still 0. The reason the signal being emitted is not updating is probably because it is from a different object (Toyota). So how can I emit the signal of the base class from the derived class?
Your toyota and car properties are two separate ones.
You have to read the seats property from toyota:
main.qml
toyota.foundCar()
console.log(toyota.seats) //<--- here
Update after comment:
Ok, that's a different approach, but in that case I would set the car property to the toyota pointer:
main.cpp
Car car = new Toyota();
ctxt->setContextProperty("car", ty);
ctxt->setContextProperty("toyota", ty);
This probably can be fitted in a overarching class (something like car_manager or car_store) in which you have a list of available cars and a function to select one car as the current, then you update the generic car or current property of that overarching class.
I say this because you will get nasty code when you want to work from the root context and furthermore, root properties don't signal that they are changed
this is the problem given to me
create a project called datamanager and its base class should be QWidget
add a new class called controller inherited from QObject
and 2 slots called sensordatarecived and startdatacollection in controller
add another class called commonreader class inherited from QObject
define 2 signals called readingStarted() and readCompleted() in commonreader class
add a slot called sendData()
declare a virtual function called monitor() in the commonreader class
add 5 new sensor classes which inherit from the commonreader class
in all of the above classes reimplement the common Monitor() function
using QTimer object implement emit readingStarted() from the monitor() function of each of the 5 classes defined
implement the sendData() slot
emit signal called readcompleted inside the send dataslot()
create the object of each of the above sensor classes in the constructor of the controller
call monitor() function of the method sensor objectfrom startDataCollection()
connect readComplete() signal of each object to sensordatarecieved() of the controller.
these are the steps i have to follow for a project.i am stuck in the 14 th step and i need help.
//controller.h
class controler : public QObject
{
Q_OBJECT
public:
explicit controler(QObject *parent = nullptr);
signals:
public slots:
void sensorDataRecived();
void startDataCollection();
};
//controller.cpp
#include "controler.h"
#include <QDebug>
#include "heart_1_sensor.h"
#include "eye_2_sensor.h"
#include "brain_3_sensor.h"
#include "ear_5_sensor.h"
#include "head_4_sensor.h"
#include "commonreaderclass.h"
controler::controler(QObject *parent) : QObject(parent)
{
commonReaderClass *h1=new heart_1_Sensor;
commonReaderClass *e2=new eye_2_Sensor;
commonReaderClass *b3=new brain_3_sensor;
commonReaderClass *e5=new ear_5_sensor;
commonReaderClass *h4=new head_4_sensor;
}
void controler::sensorDataRecived()
{
qDebug()<<Q_FUNC_INFO<<endl;
}
void controler::startDataCollection()
{
}
//commonreaderclass.h
#ifndef COMMONREADERCLASS_H
#define COMMONREADERCLASS_H
#include <QObject>
class commonReaderClass : public QObject
{
Q_OBJECT
public:
explicit commonReaderClass(QObject *parent = nullptr);
virtual void monitor();
signals:
void readingStarted();
void readCompleted();
public slots:
void sendData();
};
#endif // COMMONREADERCLASS_H
//commonreaderclass.cpp
#include "commonreaderclass.h"
#include <QDebug>
#include <QTimer>
commonReaderClass::commonReaderClass(QObject *parent) : QObject(parent)
{
}
void commonReaderClass::sendData()
{
qDebug()<<"sending data has started"<<endl;
emit readCompleted();
}
//sensor1.h
#ifndef HEART_1_SENSOR_H
#define HEART_1_SENSOR_H
#include "commonreaderclass.h"
class heart_1_Sensor:public commonReaderClass
{
public:
heart_1_Sensor();
virtual void monitor();
};
#endif // HEART_1_SENSOR_H
//sensor 1.cpp
#include "heart_1_sensor.h"
#include <QDebug>
#include <QTimer>
heart_1_Sensor::heart_1_Sensor()
{
}
void heart_1_Sensor::monitor()
{
qDebug()<<"monitoring the heart"<<endl;
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(sendData()));
timer->start(2000);
emit readingStarted();
}
//and another 4 sensors of the same implementation
I agree with #molbdnilo that you should make h1, e2, ... members of the class, instead of local variables in the constructor. But in this case, there is one more consideration: the lifetime of QObject instances is special, because the parent/children relationship between them so the children can be automatically destroyed when the parent is destroyed. I recommend you this book (paper printed versions also available). Specially chapter 2 about classes and chapter 8 about QObject and other important Qt classes. This book is a curriculum, you should follow it from start to end, and also read other books.
controller.h
class Controller : public QObject
{
Q_OBJECT
public:
explicit Controller(QObject *parent = nullptr);
~Controller(); // the destructor
// ... more public members
signals:
// ...
public slots:
// ...
private:
commonReaderClass *m_h1;
commonReaderClass *m_e2;
// ...
};
I've renamed variables h1 to m_h1 and e2 to m_e2, following a common convention for member variable names, and the Controller class name starting with uppercase is another common naming convention.
controller.cpp (the classic C++ way)
Controller::Controller(QObject *parent) : QObject(parent)
{
m_h1 = new heart_1_Sensor;
m_e2 = new eye_2_Sensor;
// ...
}
Controller::~Controller()
{
delete m_h1;
delete m_e2;
// ...
}
controller.cpp (the Qt way)
Controller::Controller(QObject *parent) : QObject(parent)
{
m_h1 = new heart_1_Sensor(this);
m_e2 = new eye_2_Sensor(this);
// ...
}
Controller::~Controller()
{ }
The second version of controller.cpp is generally preferred when writing Qt based programs. You should remember that in C++ every pointer initialized with a new operation should have a corresponding delete operation. There is not automatic "garbage collection" in C++, but QObject provides a fairly comfortable mechanism to automatically delete children objects, so the destructor in this second version may be empty or you can omit entirely.
In the main.cppi'm creating a singleton type of a class to use it in qml with the following function:
qmlRegisterSingletonType<DataloopWrapper>("com.xpto.connector", 1, 0, "DataloopWrapper",&DataloopWrapper::qmlInstance);
a bit down on the main.cpp i call a function of another object where i want to call a function from that singleton
maybe something like this qmlTranslator.loadLanguage(lang, DataloopWrapper::qmlInstance); is possible?
I'm declaring QmlTranslatorclass the following way:
#ifndef QMLTRANSLATOR_H
#define QMLTRANSLATOR_H
#include <QObject>
#include <QTranslator>
#include <QQmlEngine>
#include <QGuiApplication>
class QmlTranslator : public QObject
{
Q_OBJECT
public:
QmlTranslator(QQmlEngine *engine, QGuiApplication *app);
Q_INVOKABLE void selectLanguage(QString language);
void InstallTranslator();
void loadLanguage(QString language, QObject*(QQmlEngine*,QJSEngine*) objDataloop);
virtual ~QmlTranslator();
signals:
void languageChanged();
private:
QTranslator *_translator;
QQmlEngine *_engine;
QGuiApplication *_app;
};
#endif // QMLTRANSLATOR_H
I'm not finding a way to pass DataloopWrapper::qmlInstanceas argument. At least it gives error in void loadLanguage(QString language, QObject*(QQmlEngine*,QJSEngine*) objDataloop);on the qmlTranslator definition.
From a public: Members of DataloopWrapperi have the defenition of qmlInstance, it's this:
class DataloopWrapper : public QObject, public something::DataloopCBHandler,
public something::DataloopTransferCBHandler
{
Q_OBJECT
public:
explicit DataloopWrapper(QObject *parent = nullptr);
virtual ~DataloopWrapper();
static QObject *qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
return new DataloopWrapper;
}
DataloopWrapper::qmlInstance is a function, that you need to call in order to get a pointer to a QObject.
For for any function you want to pass this object, you need to make it accept a pointer to a QObject (type QObject*), and don't forget to call DataloopWrapper::qmlInstance.
Translated into code:
class QmlTranslator : public QObject
{
...
void loadLanguage(QString language, QObject* objDataloop);
...
};
...
qmlTranslator.loadLanguage(lang, DataloopWrapper::qmlInstance(aQMLEngineObjectPointer, aQJSEnginePointer));
I've created base class - MainWindow. In this class I create object of another class "SecondWindow". By using object of SecondWindow I want to use function() method that is defined in base class. How can I do this?
I've tried to transfer my base class as a parameter to SecondWindow object but that wasn't working (probably becouse in MainWindow I have included "secondWindow.h" and in SecondWindow I tried to include "mainwindow.h" header files). Is there way to simply use functions/variables of base class?
mainwindow.h
#include<QMainWindow>
#include "secondwindow.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
SecondWindow *secondWindow;
void function();
}
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow()
{
secondWindow = new secondWindow();
function();
}
void MainWindow::function()
{
qDebug()<<"yes";
}
secondwindow.h
class SecondWindow : public QMainWindow
{
Q_OBJECT
public:
SecondWindow();
}
secondwindow.cpp
#include "secondwindow.h"
SecondWindow::SecondWindow()
{
//here I want to use function();
}
You would want to inherit your MainWindow class, which would then inherit QMainWindow()
So in secondwindow.h you would change
class SecondWindow : public QMainWindow
{
Q_OBJECT
public:
SecondWindow();
};
to
#include "mainwindow.h"
class SecondWindow : public MainWindow
{
Q_OBJECT
public:
SecondWindow();
};
And you will then be able to use function() in secondwindow.cpp
Also, you have another issue at hand and it's that your mainwindow uses a pointer to second window, but you will then have a circular dependence issue. (You need SecondWindow in order to compile MainWindow, however, you want SecondWindow to be able to use function()).
To resolve this, you need to forward-declare SecondWindow in your MainWindow class.
In mainwindow.h remove #include "secondwindow.h" and replace it with class SecondWindow;
I have difficulties in understanding how to pass parent object to child.
In Qt, I have a MainWindow class and a DoSomething() function. Then I created a Job object within MainWindow and tried to call DoSomething within Job's DoItNow() function. But I just don't know how to do it.
MainWindow.h
class Job;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
int value;
void DoSomething();
private:
Job *job;
}
MainWindow.cpp
#include "mainwindow.h"
#include "job.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
job = new Job(this); // passing this pointer to child
}
void MainWindow::DoSomething() { // do something }
Job.h
class Job : public QObject
{
Q_OBJECT
private:
void DoItNow();
public:
explicit CDMcommand(QObject *parent = 0);
}
Job.cpp
#include "job.h"
#include "mainwindow.h"
Job::Job(QObject *parent) : QObject(parent)
{
// some setups
parent->value = 0; // this is not working
}
void Job::DoItNow()
{
parent->DoSomething(); // What is the pointer to MainWindow instance?
}
How to access non-static public register in *parent?
How to pass *parent to function in job instance?
Maybe I missunderstand the question, but I think you are a bit confused about inheritance. Your Job is a child class of QObject and MainWindow indirectly inherits also form QObject, but there is no direct relation between MainWindow and Job. I am not too familiar with Qts signal and slot mechanism, which is probably the way to go here, but maybe I can offer you a different solution:
Job::Job(QObject *parent) : QObject(parent)
{
// some setups
parent->value = 0; // this is not working
}
This is not working, because QObject has no member called value. If you can live with Jobs constructor not taking a QObject* as parameter, then just declare a
MainWindow* parentWindow;
as a private member in Job and change the constructor to
Job::Job(MainWindow *parentWindow) : QObject(parentWindow)
{
// some setups
parentWindow->value = 0; // this will work now
}
then also
void Job::DoItNow()
{
parentWindow->DoSomething();
}
will work without problems.
How can I call the Qt 'parent' object method from the 'child'
object method?
The safe and simple way to do it:
void Job::DoItNow()
{
// first evaluate the pointer: is that of type we expect?
MainWindow* pMainWindow = qobject_cast<MainWindow*>(parent());
if (pMainWindow)
pMainWindow->DoSomething(); // MainWindow::DoSomething must be exposed to class Job
}
But of course making two classes dependent on each other too much is a violation of OOP principles: these two objects become tightly coupled now. And there is already a good suggestion in comments: use an explicit signal-slot mechanism for that or providing the interface to interact between decoupled objects.