Here is my .h file:
#ifndef FDR_TCPSOCKET_H
#define FDR_TCPSOCKET_H
#include <QObject>
#include <QTcpSocket>
class FDR_TCPSocket : public QObject{
Q_OBJECT
public:
QTcpSocket* _socket;
FDR_TCPSocket(QObject* parent = Q_NULLPTR){
// Create the socket object.
_socket = new QTcpSocket(parent);
// Add events to the socket.
addEvents();
}
void addEvents(){
_socket->connect(_socket, &QTcpSocket::connected, [=]{
emit Connected();
});
}
signals:
void Connected();
public slots:
// ...
};
#endif // FDR_TCPSOCKET_H
And here is my QML:
import com.fedartech.qmlsockets 1.0
...
FDR_TCPSocket{
onConnected: { ... } <<<========== GIVES ERROR
}
But it gives this error:
Cannot assign to non-existent property "onConnected"
(BTW here is the register:)
qmlRegisterType<FDR_TCPSocket>("com.fedartech.qmlsockets", 1, 0, "FDR_TCPSocket");
Why is this happening? I really don't know.
Thanks for your helps!
Oh my god... Simple answer.
I changed the Connected() signal to the connected(). (first letter lowercased)
Now it works...
Related
I am setting up a resource manager class for my application. to manage all state of resources, i need to emmit a Signal from constructor if it don't succeed to catch resource.
In fact i want to emit signal from constructor of QObject Derived Class that registered for qml via qmlRegisterType.
this is code i have tested on Linux runnng MySql and Qt 5.12.2. but the emit signal doesn't work.
myresoureces.cpp ---- my Class that manage resources
MyResource::MyResource(QObject *parent) : QObject(parent)
{
if(!openResource()) {
// qDebug() << "Check Permission of FileSystem For Example.";
emit openResourceFailed("Check Permission of FileSystem For Example.");
}
}
bool MyResource::openResource()
{
// on situation opening resource failed
return false;
}
main.qml ---- usage of it in qml
// ...
import My.Company.Core 1.0
// ...
MyResource {
onOpenResourceFailed: {
msgDialog.title = "Open Resource Failed!"
msgDialog.text = error
msgDialog.open()
}
}
MessageDialog {
id: msgDialog
}
// ...
main.cpp ---- where i register the class
qmlRegisterType<MyResource>("My.Company.Core", 1, 0, "MyResource");
I expect the Message Dialog to be opened but nothing happened.
The signals will invoke the methods that are connected at the time of the signal emission, in your case in the constructor is not connected to any slot so the data will be lost, a possible solution is to use a QTimer::singleShot(0, ...) to be emitted a moment after the creation:
MyResource::MyResource(QObject *parent=nullptr) : QObject(parent){
if(!openResource()) {
QTimer::singleShot(0, this, [this](){
emit openResourceFailed("Check Permission of FileSystem For Example.");
});
}
}
Another alternative solution is to use QQmlParserStatus as an interface and emit the signal in the componentComplete() method:
*.h
#ifndef MYRESOURCE_H
#define MYRESOURCE_H
#include <QObject>
#include <QQmlParserStatus>
class MyResource: public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
public:
MyResource(QObject *parent=nullptr);
void classBegin();
void componentComplete();
signals:
void openResourceFailed(const QString & error);
private:
bool openResource();
};
#endif // MYRESOURCE_H
*.cpp
#include "myresource.h"
MyResource::MyResource(QObject *parent) : QObject(parent){}
void MyResource::classBegin(){}
void MyResource::componentComplete(){
if(!openResource()) {
emit openResourceFailed("Check Permission of FileSystem For Example.");
}
}
bool MyResource::openResource(){
// on situation opening resource failed
return false;
}
I want to connect some object's signals derived from an interface class.
The connection is done in QWidget::listenToAnimal(AnimalInterface*).
This does not work because qt_metacall is not a member of 'AnimalInterface' and static assertion failed: No Q_OBJECT in the class with the signal.
Of course AnimalInterface does not have the Q_OBJECT macro and does not inherit QObject because it is an interface...
I want to connect through the interface class because I do not want to manually retype the same code for Cat and for Dog.
Is it possible to connect the signal the way I want to? Perhaps with templates? Is this perhaps a lambda-specific problem?
header:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class AnimalInterface{
public:
virtual ~AnimalInterface();
virtual void makeSound() = 0;
/*signals*/
virtual void madeSound() = 0;
};
Q_DECLARE_INTERFACE(AnimalInterface,"interface")
class Dog : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Cat : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Widget : public QWidget
{
Q_OBJECT
Cat *cat_;
Dog *dog_;
public:
Widget(QWidget *parent = 0);
~Widget();
void listenToAnimal(AnimalInterface *animal);
};
#endif // WIDGET_H
cpp:
#include "widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
dog_ = new Dog;
cat_ = new Cat;
listenToAnimal(dog_);
listenToAnimal(cat_);
dog_->makeSound();
cat_->makeSound();
}
void Widget::listenToAnimal(AnimalInterface *animal)
{
connect(animal, &AnimalInterface::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
Widget::~Widget()
{
}
void Cat::makeSound()
{
qDebug()<<"Cat says miaow";
emit madeSound();
}
void Dog::makeSound()
{
qDebug()<<"Dog says wuff";
emit madeSound();
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Since you know the derived type at compile type, you can connect to the proper, statically-known QObject-derived type. No need for dynamic casting or anything of the sort. You just don't want the listenToAnimal method to be available for non-AnimalInterface-inheriting types, though, even if it they have a compatible madeSound method:
C++11
#include <type_traits>
template< class T,
typename =
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value>::type >
void listenToAnimal(T * animal) {
connect(animal, &T::madeSound, this, []{ qDebug() << "animal made sound"; });
}
C++03
template <class T>
void listenToAnimal(T * animal) {
Q_UNUSED(static_cast<AnimalInterface*>(animal));
connect(animal, &T::madeSound, this, &Widget::onAnimalMadeSound);
}
You can then use it without having to spell out the type - it's already known to the compiler:
listenToAnimal(dog_);
listenToAnimal(cat_);
If the derived type is not known at compile time, you have to dynamically cast to QObject and connect by name, not by method pointer. It will assert at runtime if you've passed in a wrong type - after all, it's not enough for it to be an instance of AnimalInterface, it also needs to be a QObject instance.
void listenToAnimal(AnimalInterface * animal) {
auto object = dynamic_cast<QObject*>(animal);
Q_ASSERT(object);
connect(object, SIGNAL(madeSound()), this, SLOT(onAnimalMadeSound()));
}
The fact that the type AnimalInterface has a virtual madeSound method is somewhat relevant - it guarantees that the derived class implements the method with such a signature. It doesn't guarantee that the method is a signal, though. So you should probably rethink your design and ask yourself: "What do I gain by using a static type system when I can't really use it for static type checking"?
Most likely you should make any methods that would nominally accept the AnimalInterface*, be parametrized and take a pointer to the concrete class. Modern code generators and linkers will deduplicate such code if type erasure leads to identical machine code.
Found a solution with templates. Did not work the first time I tried, obviously did something wrong first. Here it goes...
Just replace the corresponding parts from the example in the question (and remove definition of listenToAnimal from the source file):
header:
template<class T>
void listenToAnimal(AnimalInterface *animal)
{
T *animal_derivate = dynamic_cast<T*>(animal);
if (animal_derivate){
connect(animal_derivate, &T::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
}
cpp:
listenToAnimal<Dog>(dog_);
listenToAnimal<Cat>(cat_);
Update:
After trying Kuba Ober's answer, it seems like this is working best now:
template<typename T>
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value,void>::type
listenToAnimal(T *animal)
{
connect(animal, &T::madeSound, this, [](){ qDebug()<<"animal made sound"; });
}
However, the one point still not working is how to connect if I create an animal like AnimalInterface *bird = new Bird, because it throws the same error that the base class does not have the signal.
For example here is my code
QScopedPointer<QTimer> timer2(new QTimer);
But I want to define
QScopedPointer<QTimer> timer2;
in mainwindow.h and create an instance
timer2(new QTimer);
in the mainwindow.cpp
How?
Try the following:
// mainwindow.h
class MainWindow : public QMainWindow
{
private:
QScopedPointer<QTimer> timer2;
};
If you want to create the instance in the constructor, use the following:
// mainwindow.cpp
MainWindow::MainWindow()
:timer2(new QTimer)
{
}
Alternately, if you want to create the instance in some arbitrary member function of MainWindow, use this:
// mainwindow.cpp
void MainWindow::someFunction()
{
timer2.reset(new QTimer);
}
It's also worth reviewing initialization lists in C++ and the documentation for QScopedPointer.
Use method reset of QScopedPointer
timer2.reset(new QTimer());
What you're doing amounts to a premature pessimization. You're creating members of a MainWindow class separately and individually on the heap, when you should be simply putting them into the class as members:
// interface
#include <QMainWindow>
#include <QTimer>
class MainWindow : public QMainWindow {
Q_OBJECT
QTimer m_timer;
public:
MainWindow(QWidget * parent = 0, Qt::WindowFlags flags = 0);
};
// implementation
MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags flags) :
QMainWindow(parent, flags),
m_timer()
{
...
}
Of course, you would ordinarily not want to expose all the details of the MainWindow's implementation in the interface (header) file. Thus you would leverage the PIMPL idiom:
// interface
#include <QMainWindow>
class MainWindowPrivate;
class MainWindow : public QMainWindow {
Q_OBJECT
Q_DECLARE_PRIVATE(MainWindow)
QScopedPointer<MainWindowPrivate> const d_ptr;
public:
MainWindow(QWidget * parent = 0, Qt::WindowFlags flags = 0);
}
// implementation
#include "MainWindow.h"
#include <QTimer>
class MainWindowPrivate {
public:
QTimer timer;
}
MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags flags) :
QMainWindow(parent, flags),
d_ptr(new(MainWindowPrivate())
{
Q_D(MainWindow);
d->timer.start( ... );
...
}
I want to display an error message whenever my independent thread encounters the word "alert1" in a specific .txt file. But I get the above error inside the monitorForAlerts() inside mythread.cpp file. The line expectedly executes if I were to place it inside dialog.cpp. So I guess this is due to non-inheritance of this object. Can you please advise me how to solve this error for the given code?
Here is the code:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtCore>
#include "mythread.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
private:
Ui::Dialog *ui;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
};
#endif // DIALOG_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
#include <QDebug>
#include <QFile>
#include <Windows.h>
#include <QMessageBox>
#include <QTimer>
#define ALERTS_MESSAGE_STORAGE_PATH "E:\\QT1\\simpleGUIThread2\\simpleGUIThread2\\usbAlert.txt"
#define TIMER_VALUE 500
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
QString name;
void monitorForAlerts();
int exec();
public slots:
signals:
void testSignal(QString message);
public slots:
};
#endif // MYTHREAD_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_pushButton_clicked()
{
ui->label->show();
}
void Dialog::on_pushButton_2_clicked()
{
ui->label->hide();
}
mythread.cpp
#include "mythread.h"
#include "dialog.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
exec();
}
int MyThread::exec()
{
while(1)
{
monitorForAlerts();
emit(testSignal("hello world!!"));
sleep(1);
}
}
void MyThread::monitorForAlerts()
{
QString response = ALERTS_MESSAGE_STORAGE_PATH;
QFile resp(response);
resp.open(QIODevice::WriteOnly);
resp.close();
QFile resp1(response);
char buf[121];
char buf1[] = "alert1";
char buf2[] = "alert2";
resp1.open(QIODevice::ReadOnly);
while(resp1.size() == 0)
{
Sleep(3000);
}
qint64 lineLength = resp1.readLine(buf, sizeof(buf));
resp1.close();
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
}
if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
}
main.cpp
#include "dialog.h"
#include <QApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
w.show();
return a.exec();
}
LATEST UPDATE*********************************************************************
Hi Zlatomir,
I choose to take your 1st advice. I have created a signal that the thread will emit and connect it to a slot for QDialog. Please let me know if my understanding is correct, because I do not know where to implement the connect(), since the signal is declared in mythread.h and the slot in dialog.h. The connection type argument for connect is Qt::QueuedConnection, so that gui elements from another thread different than main-thread.
are NOT created. Is this statement correct? and where do I place this?
connect( mThread, SIGNAL(alertSignal(QString)), this, SLOT(alertSlot(QString)), Qt::QueuedConnection);
mythread.h
//....
signals:
void alertSignal(QString message);
//....
dialog.h
//....
public slots:
void alertSlot(QString message);
//....
mythread.cpp
//....
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
emit(alertSignal("alert1"));
}
else if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
emit(alertSignal("alert2"));
}
dialog.cpp
void Dialog::alertSlot(QString message)
{
if(strcmp(message, "alert1"))
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
else if(strcmp(message, "alert2"))
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
Now if this were correct, how do i implement the connect() and in which file?
The first argument is the problem, in your case this is not a good argument, because there this is a pointer to a MyThread instance, and MyThread is not a QWidget (is not derived from QWidget).
To solve this you can show the QMessageBox::critical from a slot in mainwindow (the Dialog class in your code, there you pass the instance of main-window that is a QWidget) and connect that slot with a signal that you emit from your thread, make sure that the connection type argument for connect is Qt::QueuedConnection, so that you don't try to create gui elements from another thread different than main-thread.
Another option would be to validate the data before you start the second thread and to tell
the user that he needs to provide the right files.
LE: Also check the QThread's documentation for the recommended way to use the class, now it's recommended not to derive from QThread.
LE2 - answer to the update
That connect can be made where ever you can have the two instances that you want to connect, in your case main.cpp is a good place to connect those (don't forget to fully qualify the name for connect: QObject::connect):
//...
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
QObject::connect( &mThread1, SIGNAL(alertSignal(QString)), &w, SLOT(alertSlot(QString)), Qt::QueuedConnection);
w.show();
//...
I have something like that:
Prueba.h
#include <QObject>
class Prueba:public QObject
{
Q_OBJECT
private:
bool waiting;
public:
Prueba();
void test();
void fin();
signals:
void comenzo();
};
Prueba.cpp
#include "prueba.h"
#include <QDebug>
Prueba::Prueba()
{
waiting=true;
}
void Prueba::test()
{
qDebug()<<"Comenzando";
emit(comenzo());
while(waiting) {
qDebug()<<"Esperando";
}
qDebug()<<"Termino";
}
void Prueba::fin()
{
waiting=false;
}
Principal.h
#include <QObject>
#include "prueba.h"
class Principal:public QObject
{
Q_OBJECT
private:
Prueba * prueba;
public:
Principal();
private slots:
void processSignal();
};
Principal.cpp
#include <QDebug>
Principal::Principal()
{
prueba=new Prueba();
connect(prueba,SIGNAL(comenzo()),SLOT(processSignal()));
prueba->test();
}
void Principal::processSignal()
{
for(int i=0;i<1000;i++) {
qDebug()<<"Algo";
}
prueba->fin();
}
When I call prueba->test(), and it emit the signal "comenzo", Principal::proccessSignal is completely executed, and never enters to the cycle "while(waiting)". What I need to do for that the code inside the loop is executed?
My guess is your signal connection. By default Qt will execute your signal as a direct call to the slot the objects are in the same thread as you can see here:
QMetaObject::Connection QObject::connect(
const QObject * sender, const char * signal,
const char * method, Qt::ConnectionType type = Qt::AutoConnection) const
See Qt::ConnectionType here http://qt-project.org/doc/qt-5.0/qtcore/qt.html#ConnectionType-enum
So if you use
Qt::QueuedConnection
in your signal connection
connect(prueba,SIGNAL(comenzo()),SLOT(processSignal()), Qt::QueuedConnection);
It should work as expected. See
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.