connect QPushButton via lambda - qt

I am trying to connect QPushButton to lambda expression:
QPushButton* loadTextFileButton = new QPushButton("load");
connect(loadTextFileButton, &QPushButton::clicked, [](){
qDebug()<<"clicked";
});
Compiler gives me an errors like: No matching function to call "MyClass::connect(..."
What I am doing wrong?

The connect function, which is part of Qt's signal and slots mechanism is Qt's extension to C++.
The connect function is actually a static function of QObject, so you can use it from anywhere, by simply including QObject: -
#include <QObject>
...
QObject::connect(itemPtr1, SIGNAL(someFunction()), itemPtr2, SLOT(someOtherFunction());
The objects itemPtr1 and itemPtr2 are pointers to instances of classes that are derived from QObject and support signals and slots.
In order for a class to use the signal and slot mechanism, it must inherit from QObject and declare the Q_OBJECT macro:-
class MyClass : public QObject
{
Q_OBJECT // the Q_OBJECT macro, which must be present for signals and slots
public:
MyClass(QObject* parent);
signals:
public slots:
private:
void StandardFunction();
};
As this class inherits QObject, it now has direct access to the connect function, allowing calling connect directly:-
QPushButton* loadTextFileButton = new QPushButton("load");
connect(loadTextFileButton, &QPushButton::clicked, []()
{
qDebug()<<"clicked";
});
Finally, Qt 5 introduced a new syntax for signals and slots: -
connect(loadTextFileButton, &QPushButton::clicked, this, &MyClass::StandardFunction);
You may have noticed that the advantage here is that the signal can be connected to a function that is not declared as a slot. In addition, using this syntax provides compile time error checking.

Related

How to catch a signal emitted from derived c++ class in QML?

My model is in C++ and front end is QML. The model consist of an interface class which contain other components. In simplied form (proof of concept stage) This interface class is pure virtual class called Base which is derived from QObject. I have a Derived class derived from Base
I am emitting signal in the derived class when data changes. My problem is how to catch this signal and process in QML?
derived.obj:-1: error: LNK2019: unresolved external symbol "public: void __thiscall Derived::somethingChanged(void)" (?somethingChanged#Derived##QAEXXZ) referenced in function "public: virtual void __thiscall Derived::doSomething(void)" (?doSomething#Derived##UAEXXZ)
My Base.h class is:
#include <QObject>
class Base : public QObject
{
Q_OBJECT
public:
explicit Base(QObject *parent = 0);
~Base();
virtual void doSomething() = 0;
signals:
public slots:
};
Derived.h is
#include "base.h"
class Derived : public Base
{
Q_OBJECT
public:
Derived();
~Derived();
virtual void doSomething();
signals:
void somethingChanged();
};
Derived.cpp is
#include "derived.h"
#include <QDebug>
Derived::Derived()
{
}
Derived::~Derived()
{
}
void Derived::doSomething()
{
qDebug() << "doSomething() called in Derived";
emit somethingChanged(); // this doesn't compile!
}
Connections {
target: What? // what should I put here,
onSomethingChanged: console.log("The application data changed!")
}
Again the problem is what do I put for target property? The model will only expose the interface class to qml which is the Base class but the signal is actually emitted in derived class. Should the signal be also virtual by any chance? How should I receive this signal in QML?
The MOC is the one who implements the function (your signal) void somethingChanged();.
An example could look like this in the moc_XYZ.cpp file.
// SIGNAL 13
void Derived::doSomething()
{
QMetaObject::activate(this, &staticMetaObject, 13, Q_NULLPTR);
}
So how do you make the MOC happy?
Add Q_OBJECT in your derived.h
In order to create interfaces to be used in Qt I have found two cases:
Based on QObject
This is the most easy form, and you are in the right way. Just create a class based on QObject with abstract methods and declare signals. Derived classes must not declare the signals again, just emit them when needed.
This is your case. MOC generator need to know that Base interface has an signal and it can be emitted. Just declare signals in Base instead derived classes.
Pure virtual class (extra info)
Sometimes you need to derive from any QObject-based class (e.g. QAbstractListModel) but it need to implement some interfaces too. C++ allows multiple inheritance, but Qt doesn't like classes that derive from two or more QObject-based classes.
So you should create a plain pure virtual class, and declare signals as any other unimplemented method.
// Base
class Base
{
public:
Base();
virtual ~Base();
virtual void doSomething() = 0;
signals:
virtual void somethingChanged() = 0;
};
Now, derive from Base and declare the signal again:
// Derived
class Derived : public QObject, public Base
{
Q_OBJECT
public:
explicit Derived(QObject *parent = 0);
~Derived();
//Implmetations of Base methods
public:
void doSomething();
//Declaration of Base signals
signals:
void somethingChanged();
}

Qt and "No such slot" error

I wrote the class and add a slot:
class graphShow : public QObject {
Q_OBJECT
public:
graphShow(){}
public slots:
void upd(QGraphicsScene &S);
};
Implementation of graphShow::upd is here:
void graphShow::upd(QGraphicsScene &S) {
QGraphicsTextItem* pTextItem = S.addText("Test");
pTextItem->setFlags(QGraphicsItem::ItemIsMovable);
}
Connection:
graphShow gr;
QPushButton* p1 = new QPushButton("Show");
/*...*/
QObject::connect(p1,SIGNAL(clicked()),&gr,SLOT(upd(&scene);));
During compiling I have no errors but when program starts I see this message:
Object::connect: No such slot graphShow::upd(&scene); in main.cpp:93
What am I doing wrong?
You need to set up connection in the following way:
QObject::connect(p1, SIGNAL(clicked()), &gr, SLOT(upd(QGraphicsScene &)));
However this also may not wark, because Qt docs state:
The signature of a signal must match the signature of the receiving
slot. (In fact a slot may have a shorter signature than the signal it
receives because it can ignore extra arguments.)
By the way, you doing it wrong. You could not connect signal without arguments to slot with argument. For your case you should use QSignalMapper.

Unable to connect signal to slot in another class

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.

javaScriptWindowObjectCleared signal is not invoked while html page loaded in qwebview

I am new to QT. I have been trying to see the bridge between javascript and Qt Class.
What I did:
1) I have a button and connected clicked signal to on_pushButton_clicked, also I have qwebview instance.
In on_pushButton_clicked:
...
QUrl url = QUrl::fromLocalFile("C:\\whoami\\sd\\index.html");
QObject::connect(ui->webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
this, SLOT(addJSObject()));
ui->webView->page()->mainFrame()->load(QUrl(url));
....
and in addJSObject,
void MainWindow::addJSObject()
{
qDebug () <<"Inside addJSObject";
ui->webView->page()->mainFrame()->addToJavaScriptWindowObject(QString("mBridge"), m_bridge);
qDebug () <<"Nooo. I m not invoked..";
}
Problem:
It compiles without error, and html file is displayed in the qwebview, but addJSObject callback is not invoked.
Could someone help me in order to resolve this issue?.. I must have done some silly mistake. :(.
Make sure, that your MainWindow: 1) inherits QObject 2) has Q_OBJECT macro 3) has a slot addJSObject().
For example mainwindow.h:
class MainWindow : public QObject
{
Q_OBJECT
public:
MainWindow();
private slots:
void addJSObject();
};
If this is correct, you should be able to connect to addJSObject() without static QObject::connect(). Just use connect() when referring to this as signal target object.
One way to just check, that your signalling works is to try using QTimer timeout signal:
QTimer::singleShot(5000, this, SLOT(addJSObject()));

SIGSEGV with QMainWindow singleton

The application I am writting as unique instantiation of some classes which have to be accessible easily. For that i use singletons.
For exemple my Core is defined as :
class Core : public QObject
{
Q_OBJECT
public:
Core();
~Core();
static Core& getCore()
{
static Core mycore;
return mycore;
}
(...)
};
and it works just great. However I tried to do the same with my MainWindow class, which interits from QMainWindow. I need that in order to access methods such as geometry() from other objects
However Core works great, MainWindow makes error when clossing the programe. The main window destructor is called and executed apparently once ( debug using qDebug() ) but i still have a SIGSEGV signal. What's happening? How to solve it?
Here is the code of MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow& getUi()
{
static MainWindow myUi;
return myUi;
}
public slots:
void refreshImage();
private:
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&appCore(), SIGNAL(refreshed()), this, SLOT(refreshImage()));
}
MainWindow::~MainWindow()
{
delete ui;
}
And the main code
QApplication app(argc, argv);
try
{
appCore().setDevice(MDMA::Kinect);
appUi().show();
return app.exec();
} catch(MDMA::exn e) {
(...)
}
where appCore and appUi are macros for Core::getCore and MainWindow::getUi()
This crash probably results from your QApplication being destroyed before the MainWindow.
If you cannot pass your MainWindow via other ways to the code where it is needed (e.g. as argument or via QObjecg::parent()), you could employ a technique similar to what QApplication does with it's instance method (a non-owning global reference):
Construct your MainWindow as an ordinary local variable on the stack, after the QApplication. Then set a global pointer (maybe better a QPointer; e.g. a static member of MainWindow), which you initially initialize to 0, to this in the constructor of MainWindow. You can also check if it was already initialized here to enforce the uniqueness. Via a public accessor method (instance?) for the global pointer, you can access the class from everywhere while ensuring destruction before QApplication.
If you want to make singletone, try to use general technics, for example, as described here:
http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern
Hope, lot of questions will dissappear after reading all of that article.
As for me, there is nice and simple realization of singletone.
Good luck!

Resources