I have a QVector of pointers to type X, whose items, i.e. X's own QProcesses. These processes can terminate at arbitrary time. Now, I have constructed signal-slot connection inside class X when a process ends. However, I want to propagate it to the handler class which has a QVector of X* as a member. What is an elegant way for doing this?
You can connect a signal to a signal, hiding the source signal being an implementation detail:
class MyInterface : public QObject {
Q_OBJECT
...
QProcess m_process;
public:
Q_SIGNAL void processEnded();
MyInterface(QObject * parent = 0) : QObject(parent) {
connect(&QProcess, &QProcess::finished, this, &MyInterface::processEnded);
...
}
};
The handler class can listen to these signals and do something with them.
class Handler : public QObject {
Q_OBJECT
QVector<MyInterface*> m_ifaces; // owned by QObject, not by the vector
void addInterface(MyInterface* ifc) {
ifc->setParent(this);
connect(ifc, &MyInterface::processEnded, this, [this, ifc]{
processEnded(ifc);
});
m_ifaces.append(ifc);
}
void processEnded(MyInterface* ifc) {
// handle the ending of a process
...
}
...
};
Related
I have a EmitSignal class like this:
class EmitSignal : public QObject
{
Q_OBJECT
public:
EmitSignal() {
emit emittedSignal();
qDebug() << "Signal emitted";
}
signals:
void emittedSignal();
};
And in ConnectSlot class, it's like this:
class ConnectSlot : public QMainWindow
{
Q_OBJECT
public:
ConnectSlot() {
connect(&emitSignalObject, &EmitSignal::emittedSignal, this, &ConnectSlot::connectToSlot);
}
EmitSignal emitSignalObject;
public slots:
void connectToSlot() {
qDebug() << "Connected";
}
};
As you can see, I tried to connect the signal and slot, but it seems like the slot is not triggered. And the only output I got is: Signal emitted.
Why isn't the slot not connected and how do I do it properly?
Thanks
You are emitting a signal from EmitSignal's constructor. That constructor will run before the body of ConnectSlot's constructor begins execution.
So the signal will be emitted before the connection is made.
You need to change your code so that connections are made before signals get fired.
I have the following class, set in a ContextProperty at the start of the application:
class MyClass : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE MyClassModel getModel() const { return m_myClassModel; }
private:
MyClassModel m_myClassModel;
}
In one of its methods, MyClass fills m_myClassModel with data (coming from a server).
MyClassModel also inherits QObject (because of Q_PROPERTY macros):
class MyClassModel : public QObject
{
Q_OBJECT
// Lots of Q_PROPERTY macros
Q_PROPERTY(int stuff READ stuff WRITE setStuff NOTIFY stuffChanged)
public:
...
signals:
void stuffChanged();
...
}
Then, in a QML file, MyClassModel is used to trigger signals and update graphical elements:
Item
{
anchors.fill: parent
CustomLabel
{
Connections
{
target: myClass.myClassModel()
onStuffChanged: { console.log("signal triggered!") }
}
}
}
Because of Q_INVOKABLE MyClassModel getModel() const { return m_myClassModel; }, I'm getting this error:
error: C2248: 'QObject::QObject' : cannot access private member declared in class 'QObject'
I think I understand the cause of this error, but I am not sure about what I should do to prevent it. I need to have access to MyClassModel from MyClass in order to fill it with data, yet I cannot return it into my QML file.
You are returning MyClassModel from getModel. This means copying the object. Copying MyClassModel involves a call to the implicitly generated copy constructor, which in turn calls copy constructor of base class (QObject). But copy constructor of QObject is private, this is why you get an error. Designers of Qt have decided long time ago that QObject should be non-copyable.
Solution is to return a pointer:
Q_INVOKABLE MyClassModel* getModel() const { return &m_myClassModel; }
I want to make a program in Qt to add points one by one, not all at once. To do that, I need to use QThread, or I can just use QTimer?
it can be done using QTimer and if it is time dependent (like every 1 second) then its the way to go. just create the timer, connect its timeout signal to your slot and it should work like a charm
You need create some class, inherited from QObject:
class QTimer;
class QList;
class Test_Timer : public QObject
{
Q_OBJECT
public:
explicit Test_Timer(QObject *parent = 0);
~Test_Timer();
private:
QList<QPoint> *lst;
QTimer *timer;
public slots:
void addPoint();
};
Ok, now we have timer variable for QTimer events, lst for store QPoint and addPoint() slot for handling your timer event.
At constructor we initialize members of class, connect timer's slot with current class slot and start timer with period 500ms:
Test_Timer::Test_Timer(QObject *parent) : QObject(parent)
{
lst = new QList<QPoint>;
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(addPoint()));
timer->start(500);
}
Slot for adding points may look something like this:
void Test_Timer::addPoint()
{
static int number = 0;
if (lst->size() < 10) {
lst->append(QPoint(0, number++));
qDebug() << lst->size();
} else {
timer->stop();
deleteLater();
}
}
After all don't remember free resources:
Test_Timer::~Test_Timer()
{
lst->clear();
delete lst;
if (timer->isActive())
timer->stop();
delete timer;
}
I think this example will be helpful for you.
class Settings : public QObject
{
Q_OBJECT
public:
Settings();
~Settings();
void setValue(QString key, QVariant value);
// [...]
signals:
void settingsChanged();
// [...]
class ApplicationSettings : public Settings
{
public:
explicit ApplicationSettings();
~ApplicationSettings();
public slots:
void save();
// [...]
Every time I change a value via setvalue(...)in the base class,
I do emit settingsChanged().
In the constructor of ApplicationSettings I say:
connect(this, SIGNAL(settingsChanged()), this, SLOT(save()));
But save() is never called.
As I've been writing this question I noticed that I did not include Q_OBJECT in my derived class. Adding this, the signal was connected correctly. I think this question may still be useful for others, because it was also new for me that the Q_OBJECT-macro of the base class is not "inherited".
I have 2 classes. Class A and Class B. I am emitting a signal from class A which I want the B to recieve.
I am doing it following way
In Listener File
Header File:
Class Listener:public DDSDataReaderListener
{
//Some code
public:
A m_objectSendData;
}
Implementation File:
void Listener::ondataavailable(DDSDataReader *reader)
{
m_objSendData.GetDDSData();
}
In Class A
Header File:
Class A:public QObject
{
Q_OBJECT
public:
void GetDDSData();
signals:
void Signal_Data();
}
.cpp File
A::A(QWidget *parent):QObject(parent)
{
}
void A::GetDDSData()
{
emit Signal_Data();
}
In Class B
Header File:
Class B:public QObject
{
Q_Object
public:
A objGetData;
public slots:
void getData();
}
Implementation File:
B::B(QWidget *parent):QObject(parent)
{
//Some part of code
connect(&objGetData,SIGNAL(Signal_Data()),this,SLOT(getData());
}
void B::getData()
{
//Watever is to be updated
}
I tried debugging. It is going till emit part correctly. However it is not reaching the slot.
Can someone please help me with this.
Thank You.
Without full code, it's quite difficult to identify the exact issue of the problem, so I'll outline a few important points to check.
To ensure you can use the signal and slots mechanism, you should ensure that your class is derived, from QObject or a class already derived from QObject in its hierarchy and your class must contain the Q_OBJECT macro, for example: -
class A : public QObject // derived from QObject
{
Q_OBJECT // your class must have this macro for signals and slots
public:
A();
};
Omitting the macro is probably the most common of mistakes.
To specify a slot, you add it to either the public or private slot section of your class: -
class B : public QObject // derived from QObject
{
Q_OBJECT // your class must have this macro for signals and slots
public:
B();
public slots:
void SlotB(); // slot declared public
private slots:
void SlotBPrivate(); // slot declared private.
};
Once a signal is declared in a class, a slot to receive the signal should match the arguments passed in and when you connect a signal to a slot, you must not add the function argument names.
Therefore: -
connect(&objectA, SIGNAL(SignalA(int in), this, SIGNAL(SlotA(int param)); //will fail due to the argument names
It should be: -
connect(&objectA, SIGNAL(SignalA(int), this, SIGNAL(SlotA(int));
Finally, if you're using Qt 5, you can use the new connection call, which doesn't require you to specify any argument, but instead takes the addresses of slot and signal functions.
connect(&objectA, &A::SignalA, this, &B::SlotA));
Since it references the address of a function, in actuality, the functions don't need to be classed as a slot and will still be called.
Hope that helps.
Actually I believe an answer is given in one of the comments.
One more thing, you didn't show enough code but I suspecting that you program leaves scope of objectA variable and your emitting object is just destroyed before it can emit any signal (objectA is local variable created on stack not on heap). – Marek R 1 hour ago
you allocate your Object on stack, so it gets destroyed as soon as it gets out of scope, together with destroy it gets disconnected from all signals/slots it has connections to.
So that's why you don't see any errors/warning messages because code itself is completely legit. You should new() your object to get it allocated in heap.