QSignalMapper with signal argument and extra argument - qt

I knew that QSignalMapper work well for the condition like this:
QSignalMapper *signalMapper = new QSignalMapper(this);
connect(signalMapper, SIGNAL(mapped(int)), this, SIGNAL(SetSlice(int)));
connect(this->ui->button_1, SIGNAL(slicked()), signalMapper, SLOT(map()));
connect(this->ui->button_2, SIGNAL(clicked()), signalMapper, SLOT(map()));
connect(this->ui->button_3, SIGNAL(clicked()), signalMapper, SLOT(map()));
Now I want to implement 3 sliders all have one SLOT like buttons:
QSignalMapper *signalMapper = new QSignalMapper(this);
connect(signalMapper, SIGNAL(mapped(int)), this, SIGNAL(SetSlice(int)));
connect(this->ui->verticalSlider_1, SIGNAL(valueChanged(int)), signalMapper, SLOT(map()));
connect(this->ui->verticalSlider_2, SIGNAL(valueChanged(int)), signalMapper, SLOT(map()));
connect(this->ui->verticalSlider_3, SIGNAL(valueChanged(int)), signalMapper, SLOT(map()));
As you can see, this is contradictory with the consistent rule between SIGNAL and SLOT.
Is there a workaround here? I am using Qt4.

QSignalMapper is not about sending arguments from signals to slots but to let signal receiver know "who" was that or what data use. If you need to know both value and sender you either can use some internal class mapping, or use QObject * mapper and then cast QObject * to slider.
QSignalMapper * mapper = new QSignalMapper(this);
connect(mapper, SIGNAL(map(QWidget *)), this, SLOT(SetSlice(QWidget *)));
mapper->setMapping(this->ui->verticalSlider_1, this->ui->verticalSlider_1);
mapper->setMapping(this->ui->verticalSlider_2, this->ui->verticalSlider_2);
mapper->setMapping(this->ui->verticalSlider_3, this->ui->verticalSlider_3);
And here's slot body:
void YourClass::SetSlice(QWidget *wgt)
{
QSlider * slider = qobject_cast<QSlider *>(wgt);
if(slider) {
SetSlice(slider->value());
}
}

Related

Why QObject::sender() returns null with QSignalMapper?

I am using QSingalMapper for multiple QSlider and QCheckBox both are working fine.I want to check signal sources in slot.But QObject::sender(); always returns NULL;
void MainWindow::UpdateTempValues(int val)
{
QSlider *m_slider = qobject_cast<QSlider*>(QObject::sender());
if(m_slider)
ui->label_34->setText(QString::number(m_slider->value()));
}
QSignalMapper *checkBoxMapper = new QSignalMapper(this);
QList <QSlider *> SliderList = this->findChildren <QSlider *>();
QList <QCheckBox *>CheckBoxList = this->findChildren<QCheckBox *>();
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(UpdateTempValues(int)));
connect(checkBoxMapper, SIGNAL(mapped(int)), this, SLOT(UpdateInOuConfigRegisters(int)));
foreach(QSlider *w, SliderList) {
signalMapper->setMapping(w,SignalMaperID);
connect(w, SIGNAL(valueChanged(int)), signalMapper, SLOT(map()));
SignalMaperID++;
}
SignalMaperID = 0;
foreach(QCheckBox *c,CheckBoxList){
checkBoxMapper->setMapping(c,SignalMaperID);
connect(c, SIGNAL(stateChanged(int)), checkBoxMapper, SLOT(map()));
SignalMaperID++;
}

how to use connect with member function

I want to connect the tabBarDoubleClicked signal with a member function but the compiler keeps barking at me with:
/home/ron/src/kterminal/sessionstack.cpp:79:56: error: invalid use of non-static member function
this, SessionStack::editTabLabel(session->id()));
^
and I'm not sure how to fix it, my code looks like:
int SessionStack::addSession(Session::SessionType type)
{
Session* session = new Session(type, this);
connect(session, SIGNAL(titleChanged(int,QString)), this, SIGNAL(titleChanged(int,QString)));
connect(session, SIGNAL(terminalManuallyActivated(Terminal*)), this, SLOT(handleManualTerminalActivation(Terminal*)));
connect(session, SIGNAL(activityDetected(Terminal*)), m_window, SLOT(handleTerminalActivity(Terminal*)));
connect(session, SIGNAL(silenceDetected(Terminal*)), m_window, SLOT(handleTerminalSilence(Terminal*)));
connect(session, SIGNAL(destroyed(int)), this, SLOT(cleanup(int)));
m_sessions.insert(session->id(), session);
QString tab_label = QString("Shell (") + QString::number(session->id(), 16) + ")";
addTab(session->widget(), tr(qPrintable(tab_label)));
emit sessionAdded(session->id());
raiseSession(session->id());
connect(this, tabBarDoubleClicked,
this, SessionStack::editTabLabel(session->id()));
return session->id();
}
void SessionStack::editTabLabel(int tabIndex)
{
How can I get editTabLabel() invoked when the tab is double clicked?
EDIT1
In my header I have the following declared:
class SessionStack : public QTabWidget
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kterminal")
public:
explicit SessionStack(QWidget* parent, QWidget* window);
~SessionStack();
private slots:
void tabBarDoubleClicked(int index);
void editTabLabel(int tabIndex);
};
the error occurs because you just forgot to add SIGNAL and SLOT macros at
connect(this, tabBarDoubleClicked, this, SessionStack::editTabLabel(session->id()));
You can't pass session->id() while connecting, you can only pass the argument when you emit the signal.
Please note that your code is not going to connect anyway in runtime since the signal misses an argument (int), so that it matches the editTabLabel slot. So you need to fix that as well.. should be
connect(this, SINGAL(tabBarDoubleClicked(int), this, SLOT(editTabLabel(int)));
if the signal "tabBarDoubleClicked" is builtin and you can't change it to add an argument then you might consider QSignalMapper http://doc.qt.io/qt-5/qsignalmapper.html

connect QPushButton and QComboBox

How can I connect a QPushButton and a QComboBox?
I created a SLOT that accepts 2 parameters, a pointer to the QComboBox and the index of the selected item:
void modificaExp::eliminaExp(QComboBox *combo,int value)
{
......
combo->removeItem(value);
....
}
the widgest are there:
QComboBox* combo=new QComboBox();
combo->addItem("ciao1");
combo->addItem("ciao44");
combo->addItem("ciao222");
combo->addItem("ciao555");
QPushButton* delButton=new QPushButton();
delButton->setText("delete");
connect(delButton, SIGNAL(clicked()), this, SLOT( eliminaExp(combo,combo->currentIndex() )));
so, when I click on delButton the element stays there. I think there is a problem in the connect command, specifically I think than the slot is not called.
Are you sure you need this slot with two parameter?
Another simple way:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);
connect(deleteButton, SIGNAL(clicked(bool)), this, SLOT(deleteSlot()));
}
void MainWindow::deleteSlot()
{
comboBox->removeItem(comboBox->currentIndex());
}
The slot should have the same type and equal or less number of arguments than the signal
Declare the QComboBox and the QPushButton objects in the header
modificaexp.h
private:
QComboBox* combo;
QPushButton* delButton;
modificaexp.cpp
combo=new QComboBox();
combo->addItem("ciao1");
combo->addItem("ciao44");
combo->addItem("ciao222");
combo->addItem("ciao555");
delButton=new QPushButton();
delButton->setText("delete");
connect(delButton, SIGNAL(clicked()), this, SLOT( eliminaExp()));
Modify the slot
void modificaExp::eliminaExp()
{
combo->removeItem(combo->currentIndex());
}
Refer the Qt signal slot documentation

Connect slots QAction dynamically to a function

I want to add some QAction dynamically from settings file :
_settings.beginGroup("openRecent");
QStringList recentList = _settings.childKeys();
foreach(QString recentFile, recentList)
{
QAction * action = new QAction(_settings.value(recentFile, "empty").toString(), this);
action->setObjectName(_settings.value(recentFile, "empty").toString());
connect(action, SIGNAL(triggered()), this, openFile(action->objectName()));
_recentFileButtons.append(action);
}
_settings.endGroup();
which fails to compile due to this line connect(action, SIGNAL(triggered()), this, openFile(action->objectName()));
Question :
How do I connect a QAction to a given function (with parameters)?
you can't, not directly
there are 2 options available:
use sender() to get the sending QObject and use that
use a QSignalMapper which will add a single parameter to the signal
signalMapper->setMapping(action, action->objectName());
connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
and connect signalMapper to this:
connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(openFile(QString)));
You cannot pass parameters in that way. I would suggest to do the following:
connect(action, SIGNAL(triggered()), this, SLOT(openFile()));
And in your openFile() slot just do:
void MyClass::openFile()
{
QObject *obj = sender();
QString objName = obj->objectName();
[..]
}

Work around for signal and slot argument limitation

I want to make a PushButton when it is clicked, its text change into 'clicked'. I tried it by
connect(button1, SIGNAL(clicked()), this, SLOT(markClicked(button1)));
where this refer to the MainWindow and
void MainWindow::markClicked(QPushButton *button) { button->setText("Clicked"); }
It does not seem to work because I think SLOT cannot take more arguments than SIGNAL. If there any approach to work around this limitation?
Thanks.
Qt signals/slots mechanism can only transfer signal to slot function with similar parameters. As a workaround, you should use QSignalMapper:
QSignalMapper mapper;
...
connect(button1, SIGNAL(clicked()), &mapper, SLOT(map()));
mapper.setMapping(button1, button1); // not sure whether this is mandatory or not
...
connect(&mapper, SIGNAL(mapped(QWidget*)), this, SLOT(markClicked(QWidget*)));
and function markClicked is
void MainWindow::markClicked(QWidget *widget) {
QPushButton *button = qobject_cast<QPushButton*>(widget);
button->setText("Clicked");
}
The other way you could do this is to use a default value for the argument and then use the sender() method:
In MainWindow:
void markClicked(QPushButton *button = NULL);
then:
connect(button1, SIGNAL(clicked()), this, SLOT(markClicked()));
and:
void MainWindow::markClicked(QPushButton *button) {
if (button==NULL) { button = qobject_cast<QPushButton*>(sender()); }
button->setText("Clicked");
}

Resources