PDA

View Full Version : Signals and Slots across different classes (Qt5 Version)



Ion
12th September 2014, 14:01
Currently in a situation where I want to have two classes, one a layout class controlling all the GUI items that are being displayed. Then a second class that contains implementation methods, what I would like to specifically do is press a button that would add 10 to a count number, then use this count number to update a progress bar (just a basic example so i get my head round it).

So currently looking at implementing this I decided to use Qt5 version of signals and slots, below is my current attempt which seems not to be firing off the slot even though i'm not receiving a compiler or runtime error. If anyone has an idea how I should be implementing this that would be great, or a good link to a decent example would be great.

counter.h

#ifndef COUNTER_H
#define COUNTER_H

#include <QObject>

class counter : public QObject
{
Q_OBJECT
public:
explicit counter(QObject *parent = 0);


signals:

public slots:
int count();

private:
static int number;

};

#endif // COUNTER_H


counter.cpp

#include "counter.h"
#include "mainwindow.h"

int counter::number;

counter::counter(QObject *parent) :
QObject(parent)
{
number = 10;
}

int counter::count()
{

number += 10;
//emit countworked;
qDebug() << number;
return number;
}


mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>
#include <QWidget>
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QState>
#include <QStateMachine>
#include <QDebug>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "counter.h"
#include <QDebug>
#include <iostream>
#include <string>
#include <sstream>


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
counter counting;
this->setWindowTitle(QApplication::translate("toplevel", "CCTV"));
//int (counter::*intfunction)();
//int count(10);
//intfunction = &counter::count;
connect(ui->pushButton_2,&QPushButton::clicked,&counting,&counter::count);
//connect(countworked,countworkedvaluechanged(),ui->progressBar,&QProgressBar::valueChanged)
// int *valuechanged = *intfunction;
ui->progressBar->setValue(50);
}

MainWindow::~MainWindow()
{
delete ui;
}


main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}

anda_skoa
12th September 2014, 15:19
Your object "counting" goes out of scope at then end of the MainWindow constructor.

Cheers.
_

d_stranz
13th September 2014, 01:47
Not only that, but slots and signals can't return values (i.e. they are declared as void someFunc()). If you need something passed or returned through a signal / slot mechanism, pass an argument:



// counter.h

signals:
void countIncremented( int newCount );

public slots:
void count();

// counter.cpp

void counter::count()
{
number += 10;
emit countIncremented( number );
qDebug() << number;
}

// MainWindow.cpp

// In the constructor:
counter * counting = new counter( this );
connect(ui->pushButton_2,&QPushButton::clicked, counting, &counter::count );
connect( counting, &counter::countIncremented(), ui->progressBar, &QProgressBar::setValue() );


The other problem is that by declaring counter::number as static, all instances of the counter object will be using the same value. So if you have two push buttons, even if they are connected to different instances of the counter object they will be incrementing the same value. If the value is initialized to zero, on the first click it becomes 10, the second click 20, and so on, regardless of which button gets clicked.

And further, if different instances of push buttons are connected to different instances of counters, and the counters are connected to different instances of progress bars, then the progress bars will be out of sync with the counter value because they are not connected to the same counter instance.

Button1 -> counter 1 -> progress bar 1
Button2 -> counter 2 -> progress bar 2



Start: Number = 0, progress bar values = 0
Click button 1
Counter 1 increments; number = 10
Progress bar 1 increments; value = 10
Progress bar 2 doesn't increment; value = 0
Click button 2
Counter 2 increments; number = 20
Progress bar 2 increments; value = 20
Progress bar 1 doesn't increment; value = 10


Is that what you intend to happen? If not, don't make "number" a static member of counter.

anda_skoa
13th September 2014, 10:12
Not only that, but slots and signals can't return values (i.e. they are declared as void someFunc()).

Well, a slot an return a value because it is also a normal C++ method.
But the return value is only accessible when called as such, not when called through signal/slots.

Cheers,
_

d_stranz
14th September 2014, 01:18
Well, a slot an return a value because it is also a normal C++ method.
But the return value is only accessible when called as such, not when called through signal/slots.


Yes, quite true, but I was thinking only in the signals/slots context. Most times, my normal thinking is, why bother to make something having a return value into a signal or slot when you can't use the value in a connection? In some sense, the return value is like a side effect, which I try to avoid in my code.

Ion
16th September 2014, 09:53
Thanks for replying guys, d_stranz just trying out your code but a little stuck as it's complaining about not being supplied arguements to countincremented.

Yes this is what I wanted to do this is just for testing the new method of signal and slots so that I understand it correctly.

currently getting failure due to no matching function call, (incorrect amount of arguments supplied). As I supposed to give count_incremented a parameter in the connect or am I doing something else wrong (should I be using a lamda function or ?). Also "&QProgressBar::setValue() is also failing with the same thing (no matching function for call, too many arguements)

Code listed below

Counter.h

#ifndef COUNTER_H
#define COUNTER_H

#include <QObject>

class counter : public QObject
{
Q_OBJECT
public:
explicit counter(QObject *parent = 0);

signals:
void Increment_Count(int newcount);

public slots:
void count();


private:
static int number;

};

#endif // COUNTER_H


Counter.cpp

#include "counter.h"
#include "mainwindow.h"

int counter::number;

counter::counter(QObject *parent) :
QObject(parent)
{
number = 10;
}

void counter::count()
{

number += 10;
emit Increment_Count(number);
qDebug() << number;
// return number;
}





mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "counter.h"
#include <QDebug>
#include <iostream>
#include <string>
#include <sstream>


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
counter * counting = new counter(this);
this->setWindowTitle(QApplication::translate("toplevel", "CCTV"));

connect(ui->pushButton_2,&QPushButton::clicked,counting,&counter::count);
connect(counting, &counter::Increment_Count(10), ui->progressBar, &QProgressBar::setValue());
//connect(counting, counting->Increment_Count(), ui->progressBar, &QProgressBar::setValue());
}

MainWindow::~MainWindow()
{
delete ui;
}




Thanks for the help so far so where am I going wrong?Just want to be able to use a signal and slot to change the progressbar via a count variable (should I be using a different method like a signal mapper ?). As I said just want two buttons to control a single instance of count, would like to be able to adjust the number for both which would be nice, but not required as this is just an example so it makes it easier for me to learn. Thanks for your help so far.

anda_skoa
16th September 2014, 11:39
You have a parentheses in your signal parameter of the connect call, it should only be the name of the class + name of the signal.
See the connect of the pusbutton.

Cheers,
_

Ion
16th September 2014, 11:48
Ah thanks didn't see that. Ok implemented that however the same error is also occurring for Setvalue.


C:\mainwindow.cpp:19: error: no matching function for call to 'QProgressBar::setValue()'
connect(counting, &counter::Increment_Count, ui->progressBar, &QProgressBar::setValue());
^

so how am I supposed to correct QProgressbar so that it now works (in the Qt5 version of setting it)?

anda_skoa
16th September 2014, 13:51
Ah thanks didn't see that. Ok implemented that however the same error is also occurring for Setvalue.

Same mistake again. Parentheses.

Cheers,
_

d_stranz
17th September 2014, 03:22
Same mistake again. Parentheses.

Yes, sorry. I haven't switched over to the Qt 5 style of connect(), so I goofed on the syntax. Should have been obvious C++ that the expression for the address of a member function doesn't contain parentheses.


connect(counting, &counter::Increment_Count(10), ui->progressBar, &QProgressBar::setValue());

In any case, even if you used the old SIGNAL() and SLOT() syntax for the connect() statement, you can't pass in a value as you apparently are trying to do here. The macros are simply the signature of the method with only the parameter types, no variable names or values. The return value is assumed to be void and is ignored anyway. So the equivalent SIGNAL / SLOT version of your connect() should be:


connect(counting, SIGNAL( Increment_Count(int) ), ui->progressBar,SLOT( setValue(int) ));

Ion
18th September 2014, 14:58
Ok brill thanks guys, yea I am very new to signal and slots so this was a bit of a crash course for me, so didn't want to bother learning the old method. Thanks guys