How to connect signal from a different class? - c++

// splashscreen.h
class SplashScreen : public QMainWindow
{
Q_OBJECT
public:
explicit SplashScreen(QWidget *parent = nullptr);
~SplashScreen();
QTimer *mtimer;
public slots:
void update();
private:
Ui_SplashScreen *ui;
};
// app.h
#include "splashscreen.h"
class App: public QMainWindow
{
Q_OBJECT
public:
App(QWidget *parent = nullptr);
~App();
SplashScreen s;
private:
Ui::AppClass ui;
};
// app.cpp
App::App(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
QGraphicsOpacityEffect* eff = new QGraphicsOpacityEffect();
s.centralWidget()->setGraphicsEffect(eff);
QPropertyAnimation* a = new QPropertyAnimation(eff, "opacity");
a->setDuration(2000);
a->setStartValue(0);
a->setEndValue(1);
a->start(QPropertyAnimation::DeleteWhenStopped);
s.show();
connect(a, &QAbstractAnimation::finished, this, [this]
{
auto *timer = new QTimer();
this->s.mtimer = timer;
QObject::connect(timer, SIGNAL(timeout()), this->s, SLOT(update()));
timer->start(100);
});
}
I'm getting an error at this line: QObject::connect(timer, SIGNAL(timeout()), this->s, SLOT(update()));
no instance of overloaded function "QObject::connect" matches the argument list
I think it's mismatching the class signal, as this passed to the lambda refers to App not SplashScreen.
When i try to pass s (SplashScreen) to the lambda:
connect(a, &QAbstractAnimation::finished, this, [s]
{ ... }
I get an error: App::s is not a variable.
I'm confused, what is the proper way to connect in this case?

In App class, s is an instance, not a pointer to an instance. Function connect needs pointer, not reference.
Use these syntax should help:
QObject::connect(timer, &QTimer::timeout, &s, &SplashScreen::update);

Use these syntax:
QObject::connect(timer, &QTimer::timeout, this, &SplashScreen::update);

Related

A warning message "No matching signal for" when executing my application

When executing my application some warning messages appear:
QMetaObject::connectSlotsByName: No matching signal for on_actionUndo_triggered(),
QMetaObject::connectSlotsByName: No matching signal for on_actionRedo_triggered()
I have implemented the rule void on_objectName_signalName(signalParameters); to the signal and slot that I have created and I don't know why that messages appear, note that the signal and slot work fine.
Declaration:
class Widget : public QWidget {
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
QAction *actionUndo;
QAction *actionRedo;
private slots:
void on_actionUndo_triggered();
void on_actionRedo_triggered();
};
Definition:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
ui->setupUi(this);
QVBoxLayout *layout = new QVBoxLayout(this);
QMenuBar *menuBar = new QMenuBar();
QMenu *editMenu = new QMenu("&Edit");
menuBar->addMenu(editMenu);
this->actionUndo = new QAction("&Undo", editMenu);
this->actionUndo->setShortcut(QKeySequence::Undo);
QObject::connect(this->actionUndo, SIGNAL(triggered()), this, SLOT(on_actionUndo_triggered()));
this->actionRedo = new QAction("&Redo", editMenu);
this->actionRedo->setShortcut(QKeySequence::Redo);
QObject::connect(this->actionRedo, SIGNAL(triggered()), this, SLOT(on_actionRedo_triggered()));
editMenu->addAction(this->actionUndo);
editMenu->addAction(this->actionRedo);
this->layout()->setMenuBar(menuBar);
}
Widget::~Widget() {
delete ui;
}
void Widget::on_actionUndo_triggered() {
}
void Widget::on_actionRedo_triggered() {
}
The warning arises because within the function setupUi calls the function connectSlotsByName.
void setupUi(QWidget *Widget)
{
[...]
QMetaObject::connectSlotsByName(Widget);
}
According to the documentation:
void QMetaObject::connectSlotsByName(QObject * object)
Searches recursively for all child objects of the given object, and
connects matching signals from them to slots of object that follow the
following form:
void on_<object name>_<signal name>(<signal parameters>);
Then this function looks for objects actionUndo and actionRedo and does not find them because they are not created, a simple solution is to create them before setupUi and pass a name with setObjectName:
actionUndo = new QAction("&Undo", this);
actionUndo->setObjectName("actionUndo");
actionRedo = new QAction("&Redo", this);
actionRedo->setObjectName("actionRedo");
ui->setupUi(this);
With this configuration you will no longer need to make the connections, ie you do not need to implement the next line.
QObject::connect(this->actionUndo, SIGNAL(triggered()), this, SLOT(on_actionUndo_triggered()));
QObject::connect(this->actionRedo, SIGNAL(triggered()), this, SLOT(on_actionRedo_triggered()));
complete code:
.h
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_actionUndo_triggered();
void on_actionRedo_triggered();
private:
Ui::Widget *ui;
QAction *actionUndo;
QAction *actionRedo;
};
.cpp
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
actionUndo = new QAction("&Undo", this);
actionUndo->setObjectName("actionUndo");
actionUndo->setShortcut(QKeySequence::Undo);
actionRedo = new QAction("&Redo", this);
actionRedo->setObjectName("actionRedo");
actionRedo->setShortcut(QKeySequence::Redo);
ui->setupUi(this);
setLayout(new QVBoxLayout);
QMenuBar *menuBar = new QMenuBar(this);
QMenu *editMenu = new QMenu("&Edit");
menuBar->addMenu(editMenu);
editMenu->addAction(actionUndo);
editMenu->addAction(actionRedo);
layout()->setMenuBar(menuBar);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_actionUndo_triggered()
{
qDebug()<<"undo";
}
void Widget::on_actionRedo_triggered()
{
qDebug()<<"redo";
}

QTimer won't start when passing a variable

I have a QTimer object that kicks off a function every second. The timer runs correctly if I do the following
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
// Set a Qtimer to update the OSD display every 1 second
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(print()));
timer->start(1000);
}
void MainWindow::print()
{
printf("hello world\n");
}
But I want to pass a variable to print(). But when I do this, I never see my print statement.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
// Set a Qtimer to update the OSD display every 1 second
QTimer *timer = new QTimer(this);
int val = 42;
// Now pass val to print()
connect(timer, SIGNAL(timeout()), this, SLOT(print(val)));
timer->start(1000);
}
void MainWindow::print(int val)
{
// I never see my print statement
printf("hello world, val=%d\n", val);
}
header.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void print(int val);
Why does this not work? What can I do to pass a variable into print() using QTimer?
connect(timer, SIGNAL(timeout()), this, SLOT(print(val)));
Qt signal/slot connections don't work that way. The text within the SIGNAL() and SLOT() macros has to be the signature of the signal/slot method, verbatim; you can't put variables or other non-method-signature text there.
If you look at your program's stdout while it runs, you'll see an error message printed by connect() telling you that it can't find any slot-method named print(val).
If you want to provide a separate value for your slot, you could either make val a member-variable of your class, and have print() look at the member variable instead of an argument, or you could use an intermediary slot, like this:
public slots:
void print(int val);
void print42() {print(val);}
... and then connect your signal to SLOT(print42()) instead.

Qt5 won't send timeout signal

I'm new to QT5, and I'm having a very strange problem.
I want to use QTimer to read coordinate from serial device every 0.5 second, but the QTimer won't send timeout signal.
My .h:
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
Ui::MainWindow *ui;
};
My .cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer myTimer(this);
myTimer.setInterval(500);
myTimer.setSingleShot(false);
connect(&myTimer, SIGNAL(timeout()), this, SLOT(test()));
myTimer.start();
}
void MainWindow::test() {
qDebug() << "Time out";
}
MainWindow::~MainWindow()
{
delete ui;
}
After I started the program, not a single "Time out" shows up...
I added the following codes after "myTimer.start()":
QTime t = QTime::currentTime().addMSecs(550);
while (QTime::currentTime() < t) {
qDebug() << myTimer.remainingTime();
}
And I found that after the remaining time of "myTimer" reduced to 0, it won't refill the remaining time and start once again, it remains at 0.
Q_OBJECT is already added
Anyone got an idea?
Thank you very much!
The problem is here:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer myTimer(this);
myTimer.setInterval(500);
myTimer.setSingleShot(false);
connect(&myTimer, SIGNAL(timeout()), this, SLOT(test()));
myTimer.start();
}
In the constructor you declared myTimer automatically, so it will be destroyed as soon as constructor returns. This way, by the time when you expect timeout event, myTimer does not exist anymore and thus it cannot send any signals!
The solution is straightforward: myTimer should exist all the time MainWindow object lives, so declare it in the class, not in it's constructor, and allocate it dynamically:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
QTimer *myTimer; // <--- pointer declaration.
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Allocating actual QTimer object:
myTimer = new QTimer(this);
// Calling methods by object pointer:
myTimer->setInterval(500);
myTimer->setSingleShot(false);
connect(myTimer, SIGNAL(timeout()), this, SLOT(test()));
myTimer->start();
}
MainWindow::~MainWindow()
{
// Don't forget to delete after usage.
delete myTimer;
delete ui;
}
myTimer is local.
Make it a class member and use it. It will work.

start qtimer from another class faces segmentation fault

I'm facing a problem using QTimer. The program closes with a segmentation fault in run time and when I exclude the "timer" from code, it runs properly. Here's the code:
Class A : public QObject, public QGraphicsPixmapItem{
Q_OBJECT
public:
A(QPixmap pic){
this->setPixmap(pic);
}
void start(){
timer = new QTimer();
timer->start(1000);
connect(timer, SIGNAL(timeout()), this, SLOT(moveObject()));
}
public slots:
void moveObject(){
moveTimer = new QTimer();
moveTimer->start(20);
connect(moveTimer, SIGNAL(timeout()), this, SLOT(changePosition()));
}
void changePosition(){
//a couple of things are done here
}
private:
QTimer *timer;
QTimer *moveTimer;
}
Class B : QGraphicsView{
Q_OBJECT
public:
B(QWidget *parent = 0) : QGraphicsView(parent){
a = new A(QPixmap("a.png"));
void go(){
a->start();
}
private:
A *a;
}
P.S. I delete moveTimer in changePosition as long as the object stops moving and recall moveObject so that it can move towards the next target.

How to connect a signal from a thread to a slot?

What I simply want to do is connect a signal inside a thread to a slot in the main thread to handle UI changes.
This is basically the current state of my thread, nothing fancy but it's just for testing purposes atm:
// synchronizer.h
class Synchronizer : public QObject
{
Q_OBJECT
public:
Synchronizer();
signals:
void newConnection(std::wstring id);
private:
QTimer timer;
private slots:
void synchronize();
}
// synchronizer.cpp
Synchronizer::Synchronizer()
{
connect(&timer, SIGNAL(timeout()), this, SLOT(synchronize()));
timer.start();
}
void Synchronizer::synchronize()
{
emit newConnection(L"test");
}
And here's how my MainWindow looks:
// mainwindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Synchronizer synchronizer;
private slots:
void addConnection(std::wstring id);
}
// mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&synchronizer, SIGNAL(newConnection(std::wstring)),
this, SLOT(addConnection(std::wstring)));
QThread *thread = new QThread;
// The problems starts here?
synchronizer.moveToThread(thread);
thread->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::addConnection(std::wstring id)
{
// Add a new connection to QListWidget
ui->connectionList(QString::fromStdWString(id));
}
If I remove there lines:
synchronizer.moveToThread(thread);
thread->start();
everything seems to work as expected, that is a new item is added every second to a QListWidget but as soon as I move the synchronizer object to thread it simply stops working. I'd presume it has something to do with the connect context but I'm not really sure how something like this should be achieved as I'm quite new to Qt.
It seems that the in this case was simply the fact that I am using std::wstring as an argument in the signal without registering the type first and after adding the following line qRegisterMetaType<std::wstring>("std::wstring"); to the code, everything worked as expected.
If I would have read the output console more carefully I would have solved the problem without too much hassle as it was clearly stated that:
QObject::connect: Cannot queue arguments of type 'std::wstring'
So simply speaking, read the compiler output and don't be stupid like me :)