PDA

View Full Version : What's wrong with this signalMapper



Nirvana
23rd January 2016, 04:38
I have been looking docs and other topics about singalMappers but I still couldn't make it work properly.

here is the function I want to call


void theme(QString a)
{

qDebug()<<a;
}

here is how I connected


for (int a=0;a<buttons.count();a++){
QPushButton *button = new QPushButton();

QSignalMapper *signalMapper = new QSignalMapper();

connect(signalMapper, SIGNAL(mapped(QString)), this, SIGNAL(theme(QString)));

connect(button, SIGNAL(clicked()), signalMapper,SLOT(map()));
signalMapper->setMapping(button,button->text());



here is the header file

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void theme(QString a);

private slots:
void on_pushButton_clicked();

void on_pushButton_10_clicked();

void on_temalar_button_clicked();

public:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


But when I click the button, I don't get any debug output. What is the thing that I'm doing wrongly?
Thanks

anda_skoa
23rd January 2016, 11:20
You declare "theme" to be a signal, but you want it as a slot.
I am surprised this even compiles, MOC should have created an implementation of theme and the linker should have complained about the symbol being defined twice.

Btw, you don't need a new signal mapper for every button, just allocate it outside the loop.

And either pass a parent object or store the pointer as a member and delete it manually, otherwise you are leaking it.

Cheers,
_

Nirvana
23rd January 2016, 13:32
I transformed theme into slot both in header file and the signalmapper, and now I'm having this problem

/home/metin/QTProjects/build-settings-Desktop_Qt_5_5_1_GCC_64bit-Debug/moc_mainwindow.cpp:82: error: undefined reference to `MainWindow::tema_izleme(QString)'


connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(theme(QString)));

Thanks for your help so far

anda_skoa
23rd January 2016, 14:18
Apparently you have something called "tema_izleme", likely a function, that you have declared but not defined.

Cheers,
_

Nirvana
23rd January 2016, 14:56
I actually have

void tema_izleme(QString a)
{
qDebug()<<"SUCCES!";
}

header:


private slots:

void tema_izleme(QString a);
error exists

anda_skoa
23rd January 2016, 15:49
error exists

Which is no surprise.
You have declared a member function (method) but implemented a stand-alone function that incidentally has the same name.

Cheers,
_

ars
23rd January 2016, 15:51
Hello,

have you thought about throwing away the SignalHandler? You are using Qt5, and Qt5 provides a couple of new static connect functions. Combining them with lambdas from C++11 the code can be simplified. See http://doc.qt.io/qt-5/qobject.html#connect-4 for a reference.

What I have understood from your example: You have a couple of buttons associated with "themes" and clicking on a button should set the associated theme to your software (currently you are simply showing the theme name on the debug console). To reproduce your setup, I've created a simple application with three buttons pushButton0, ..., pushButton2 in the main window with text "Theme 1", ..., "Theme 2".

For compiling with C++11 (gcc option -std=c++11) add the following line to your .pro file:

CONFIG += c++11

Here is the MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class QPushButton;

class MainWindow : public QMainWindow
{
Q_OBJECT

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

private: // methods
void connectTheme(QPushButton* button);
void theme(const QString& data);

private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

Observe that this does not contain the declaration of a slot. The private method theme(data) should get called when clicking on a button with the data associated to that button (currently the button text). So the buttons need to get connected to method theme(). To simplify the connection process, I have introduced the function connectTheme(QPushButton*). Here is the MainWindow.cpp containing the implementation of these functions:

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include <iostream>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

connectTheme(ui->pushButton0);
connectTheme(ui->pushButton1);
connectTheme(ui->pushButton2);
}

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

void MainWindow::connectTheme(QPushButton* button)
{
/*
* Store the data associated with the button into a local variable.
* In this example, the data are just the button text.
*/
auto themeData = button->text();

/*
* Here we connect the clicked(bool) signal of button to a lambda capturing
* the themeData by value. This lambda calls MainWindow::theme() method passing
* it the captured data.
*/
connect(button, &QPushButton::clicked, [this, themeData](){theme(themeData);});
}

void MainWindow::theme(const QString& data)
{
/*
* Just process the data passed in.
*/
std::cout << data.toStdString() << std::endl;
}
Some explanation: In the constructor I connect the 3 buttons after ui initialization. The connectTheme(button) function stores the button text in a local variable and then connects the clicked signal of QPushButton button to a lambda function
[this, themeData](){theme(themeData);}
The lambda function captures the this pointer (the pointer to the current MainWindow object) and a copy of the local variable themeData. In the lambda body
theme(themeData); method theme() of MainWindow is called with the data associated with the button. This lambda function replaces the QSignalMapper. The theme(data) method just processes the data passed in (in this case just print them to cout). Note that there is no need to declare theme() as a slot.

With porting my application to Qt5 and using C++11 I now prefer the procedure explained above over using QSignalMapper.

Best regards
ars

d_stranz
24th January 2016, 02:08
With porting my application to Qt5 and using C++11 I now prefer the procedure explained above over using QSignalMapper.

Where's the smiley-face emoji that means "My brain just exploded"? :D