My slot function is not being recognised. "No such slot".
-
I have the following code:
main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "ui_mainwindow.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); void updateTimeLabel(std::string current_time); void updateTime(std::chrono::time_point<std::chrono::high_resolution_clock> start); ~MainWindow(); private slots: void on_startButton_clicked(); void on_stopButton_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <iostream> #include <chrono> #include <iostream> #include <string> #include <fstream> #include <QDebug> #include <QStandardPaths> #include <QTimer> std::string readTimeFromFile() { std::fstream timefile; std::string filepath = "C://Users//Byte//Desktop//timelog.txt"; timefile.open(filepath); if(!(timefile.is_open())) { qDebug() << "File not opening"; } std::string thetime; std::getline(timefile, thetime); timefile.close(); return thetime; } void MainWindow::updateTimeLabel(std::string current_time) { int seconds = stoi(current_time); std::string formattedTime; int minutes = seconds / 60; int hours = minutes / 60; seconds %= 60; minutes %= 60; formattedTime += std::to_string(hours); formattedTime += ":"; formattedTime += std::to_string(minutes); formattedTime += ":"; formattedTime += std::to_string(seconds); QString timeToDisplay = QString::fromStdString(formattedTime); ui->timeLabel->setText(timeToDisplay); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); auto current_time = readTimeFromFile(); updateTimeLabel(current_time); } MainWindow::~MainWindow() { delete ui; } void MainWindow::updateTime(std::chrono::time_point<std::chrono::high_resolution_clock> start) { auto elapsed = std::chrono::system_clock::now() - start; auto secondsElapsed = std::chrono::duration_cast<std::chrono::seconds>(elapsed).count(); std::string current_time = readTimeFromFile(); int temp = stoi(current_time); auto new_time = secondsElapsed += temp; updateTimeLabel(std::to_string(new_time)); } void MainWindow::on_startButton_clicked() { auto start = std::chrono::system_clock::now(); // calculate time elapsed, add to file time, update time QTimer *myTimer = new QTimer(this); connect(myTimer, SIGNAL(timeout()), this, SLOT(updateTime(start))); // problem here, connect is not recognising my slot myTimer->start(); } void MainWindow::on_stopButton_clicked() { // write to file, close file }
For some reason I constantly get the error: "QObject::connect: No such slot MainWindow::updateTime(start) in ..\testProg\mainwindow.cpp:78
QObject::connect: (receiver name: 'MainWindow')"The problem is with the QTimer object in the startButton_clicked() function. Part of me thinks that I am using the SIGNAL() part completely wrong as I'm passing a variable and some of the examples I've seen just pass a type? How exactly do I pass an argument to the function and how exactly can I get it to recognize my slot function? Thanks for any help.
-
@bytebaron said in My slot function is not being recognised. "No such slot".:
updateTime(std::chrono::time_pointstd::chrono::high_resolution_clock)
This is your slot, not updateTime(start).
Please use the new signal/slot syntax - then you a) don't have to specify the arguments (only if you've overloaded signals or slots) and b) will get a compiler instead a runtime warning when something doesn't match./edit: and why are you using the std stuff instead QElapsedTimer + QString - we're a Qt forum :)
-
@bytebaron
Once you have resolved from @Christian-Ehrlicher 's post:
Inon_startButton_clicked()
, are you aware that yourQTimer *myTimer = new QTimer(this);
leaks?
-
@christian-ehrlicher said in My slot function is not being recognised. "No such slot".:
@bytebaron said in My slot function is not being recognised. "No such slot".:
updateTime(std::chrono::time_pointstd::chrono::high_resolution_clock)
This is your slot, not updateTime(start).
Please use the new signal/slot syntax - then you a) don't have to specify the arguments (only if you've overloaded signals or slots) and b) will get a compiler instead a runtime warning when something doesn't match./edit: and why are you using the std stuff instead QElapsedTimer + QString - we're a Qt forum :)
I'm not sure where the newest syntax is, I'm a qt/c++ newb. Is it something similar to this:
connect(myTimer, &QTimer::timeout, updateTime());
I'm looking to try and pass the start variable to the function if I can. Also I'm new to QT so I'm just getting used to the library bit by bit atm but I hope to do away with the std stuff :)
-
@jonb said in My slot function is not being recognised. "No such slot".:
@bytebaron
Once you have resolved from @Christian-Ehrlicher 's post:
Inon_startButton_clicked()
, are you aware that yourQTimer *myTimer = new QTimer(this);
leaks?A memory leak? How so?
-
@bytebaron said in My slot function is not being recognised. "No such slot".:
I'm not sure where the newest syntax is, I'm a qt/c++ newb. Is it something similar to this:
connect(myTimer, &QTimer::timeout, updateTime());
I'm looking to try and pass the start variable to the function if I can.
See https://doc.qt.io/qt-5/signalsandslots-syntaxes.html, especially the "Making Connections to Lambda Expressions" section.
A memory leak? How so?
Every time you click the start button, you create a new QTimer object. The old one is left in memory, undeleted.
-
@jksh said in My slot function is not being recognised. "No such slot".:
@bytebaron said in My slot function is not being recognised. "No such slot".:
I'm not sure where the newest syntax is, I'm a qt/c++ newb. Is it something similar to this:
connect(myTimer, &QTimer::timeout, updateTime());
I'm looking to try and pass the start variable to the function if I can.
See https://doc.qt.io/qt-5/signalsandslots-syntaxes.html, especially the "Making Connections to Lambda Expressions" section.
A memory leak? How so?
Every time you click the start button, you create a new QTimer object. The old one is left in memory, undeleted.
I took your advice but I'm unable to get it working still. From what I've researched, the slot is attached to the QTimer object(???) so all of MainWindow's elements objects/widgets go out of scope(???) so I am unable to access the label again in my slot function updateLabel(). Also, to fix the leak issue, is it worth creating the QTimer once in the MainWindow constructor or perhaps making it a smart pointer? I made a seperate barebones project to try and understand things and not get cluttered. My code is like so right now:
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QTimer> #include <chrono> #include <QString> #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void updateLabel(std::chrono::time_point<std::chrono::high_resolution_clock> start) { auto elapsed = std::chrono::system_clock::now() - start; auto secondsElapsed = std::chrono::duration_cast<std::chrono::seconds>(elapsed).count(); std::string theSeconds = std::to_string(secondsElapsed); QString timeToDisplay = QString::fromStdString(theSeconds); ui->testLabel->setText(timeToDisplay); } void MainWindow::on_pushButton_clicked() { auto start = std::chrono::system_clock::now(); QTimer *myTimer = new QTimer(this); connect(myTimer, &QTimer::timeout, [=] { emit updateLabel(start);}); // problem here, connect is not recognising my slot myTimer->start(); }
main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT signals: void updateLabel(std::chrono::time_point<std::chrono::high_resolution_clock> start); public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_pushButton_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
-
Also, to fix the leak issue, is it worth creating the QTimer once in the MainWindow constructor
Yes, or maybe the simplest all round is just to have a member variable
QTimer myTimer
inMainWindow
. Since that's not a pointer and not usingnew
it never needsdelete
ing.
-
@bytebaron said in My slot function is not being recognised. "No such slot".:
connect(myTimer, &QTimer::timeout, [=] {
Try capturing "this"
connect(myTimer, &QTimer::timeout, [=, this] {....
and see if it then accepts your slot.
-
Hi,
While it's not strictly necessary with the new connection syntax, it's mandatory to declare your slots properly in your header for the old to work (as well as for QML). Note that even if not strictly necessary, it's good to properly separate standard functions and slots so it makes their intent clear.
-
@bytebaron said in My slot function is not being recognised. "No such slot".:
From what I've researched, the slot is attached to the QTimer object(???)
The QTimer object emits the
QTimer::timeout()
signal when the time is up.You want to implement a slot function that should be called when the time is up.
You connect the signal to the slot. Then, when the time is up, the QTimer object emits the
QTimer::timeout()
signal; when Qt detects this signal, it runs your slot.so all of MainWindow's elements objects/widgets go out of scope(???) so I am unable to access the label again.
The term "go out of scope" refers to what happens when you reach the end of a function block. For example:
{ auto elapsed = std::chrono::system_clock::now() - start; auto secondsElapsed = std::chrono::duration_cast<std::chrono::seconds>(elapsed).count(); std::string theSeconds = std::to_string(secondsElapsed); QString timeToDisplay = QString::fromStdString(theSeconds); ui->testLabel->setText(timeToDisplay); // The end of block is here }
Local variables get destroyed when they go out of scope. Member variables do not. This means the MainWindow's elements do not go out of scope.
Also, to fix the leak issue, is it worth creating the QTimer once in the MainWindow constructor
Yes.
or perhaps making it a smart pointer?
A smart pointer will not help you here.
I made a seperate barebones project to try and understand things and not get cluttered.
This is a good practice.
signals: void updateLabel(std::chrono::time_point<std::chrono::high_resolution_clock> start);
...
connect(myTimer, &QTimer::timeout, [=] { emit updateLabel(start);});
You have now created an
updateLabel
signal. Your code says, "When theQTimer::timeout()
signal gets emitted, emit theupdateLabel(std::chrono::time_point<std::chrono::high_resolution_clock>)
signal".However, this new signal is not connected to any slot, so nothing will happen when it is emitted.
I presume you want this:
// NOTE: You don't need a separate updateLabel() function! connect(myTimer, &QTimer::timeout, [=] { auto elapsed = std::chrono::system_clock::now() - start; auto secondsElapsed = std::chrono::duration_cast<std::chrono::seconds>(elapsed).count(); std::string theSeconds = std::to_string(secondsElapsed); QString timeToDisplay = QString::fromStdString(theSeconds); ui->testLabel->setText(timeToDisplay); });
But your life will be much simpler if you use QElapsedTimer instead of doing the manual calculations: https://doc.qt.io/qt-5/qelapsedtimer.html
void updateLabel(std::chrono::time_point<std::chrono::high_resolution_clock> start) { auto elapsed = ...
Note 1: Here, you have defined a standalone function.
void updateLabel(...)
is not the same asvoid MainWindow::updateLabel(...)
! Since this is not a member function ofMainWindow
, it cannot access the MainWindow's internal variables.Note 2: In mainwindow.h, you defined
MainWindow::updateLabel(...)
as a signal. However, in mainwindow.cpp, you tried to implement it as a slot.