Qt 4.8 signalMapper signal and slot - c++

I have been trying to use QSignalMapper with Qt 4.8. But I have not been able to get signal from the signalmapper. My code is similar with what qt has on their website. my mySlot function should receive value and execute, But nothing happens with button clicked.
vector<QPushButton *> button;
QSignalMapper *signalMapper;
signalMapper = new QSignalMapper(this);
for (int i = 0; i<10; i++)
{
button.push_back(new QPushButton(“myButton”);
QObject::connect(button[i], SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button[i], i);
}
QObject::connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(mySlot(int)));
void class::mySlot(int position)
{
QMessageBox msgBox;
msgBox.setText(QString(“Button #: %1”).arg(position));
msgBox.exec();
}

Related

Replacing deprecated QtSignalMapper class to forward Signals in Qt5

I have this code which makes a mdi window written for Qt 4:
class MdiWindow : public QMainWindow
{
Q_OBJECT
public:
MdiWindow( QWidget *parent = nullptr)
...
private:
QWorkspace* workspace
QSignalMapper* mapper
}
MdiWindow::MdiWindow( QWidget *parent ) : QMainWindow( parent )
{
...
workspace = new QWorkspace;
setCentralWidget( workspace );
connect( workspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(enableActions()));
mapper = new QSignalMapper( this );
connect( mapper, SIGNAL(mapped(QWidget*)), workspace, SLOT(setActiveWindow(QWidget*)) );
....
}
According to the QT documentation QWorkspace should be replaced with QMdiArea.
I did that and wrote the first connect like this:
connect(workspace, &QMdiArea::subWindowActivated,
this, &MdiWindow::enableActions);
But what about QSignalMapper also that is also deprecated.
So how can I update this line:
mapper = new QSignalMapper( this );
connect( mapper, SIGNAL(mapped(QWidget*)), workspace, SLOT(setActiveWindow(QWidget*)) );
I read QSignalMapper can be replaced with lamdas but how in this case?
If i understand right mapper forwards all the signals from this to the active window of workspace
Previously you used QSignalMapper::setMapping() to make sure that you'd be sent data you need when the SLOT() was called. Now you can just encapsulate this logic inside a lamba, so if you did (like in Qt example):
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]);
}
connect(signalMapper, SIGNAL(mapped(const QString &)),
this, SIGNAL(clicked(const QString &)));
you can now do (somewhat):
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, &QPushButton::clicked, [=]() {
emit clicked(texts[i]);
});
}
If the setMapping() is not being used, then it probably could have been connected directly to a SLOT() already.

signal mapping issue with QlineEdit

I want to pass the argument to slot. so i'm using signal mapping . I'm passing the QlinEedit variable as a argument to the slot using setmapping . but my slot function is not calling.
QSignalMapper* maper = new QSignalMapper (this) ;
connect(ui->step2,SIGNAL(returnPressed()),maper,SLOT(map()));
maper->setMapping(ui->step2,ui->step2);
connect (maper, SIGNAL(mapped(QLineEdit*)), this, SLOT(on_steps_returnPressed(QLineEdit*))) ;
The QSignalMapper class is deprecated and you should use the new signal/slots syntax with a lambda function:
connect(ui->step2, &QLineEdit::returnPressed, [=]() { this->on_steps_returnPressed(ui->step2); });
You can also pass only the text inside you QLineEdit instead of a pointer on it:
connect(ui->step2, &QLineEdit::returnPressed, [=]() { this->on_steps_returnPressed(ui->step2->text()); });
If you have to use a QSignalMapper anyway, you have to use the signal QSignalMapper::mapped(QWidget*). Since a slot has to have the same signature than the connected signal, on_steps_returnPressed becomes on_steps_returnPressed(QWidget*) (cast the parameter to a QLineEdit):
QSignalMapper* maper = new QSignalMapper (this) ;
connect(step2, SIGNAL(returnPressed()), maper, SLOT(map()));
maper->setMapping(step2, step2);
connect(maper, SIGNAL(mapped(QWidget*)), this, SLOT(on_steps_returnPressed(QWidget*)));
Your slot should be something like that:
void on_steps_returnPressed(QWidget* widget)
{
QLineEdit* edit = qobject_cast<QLineEdit*>(widget);
if (!edit)
return;
label->setText(edit->text());
}
A complete example to compare the two solutions:
class Widget: public QWidget
{
Q_OBJECT
public:
Widget(QWidget* parent=nullptr): QWidget(parent),
lineEdit1(new QLineEdit(this)),
lineEdit2(new QLineEdit(this)),
label(new QLabel(this))
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(lineEdit1);
layout->addWidget(lineEdit2);
layout->addWidget(label);
connect(lineEdit1, &QLineEdit::returnPressed, [=]() { this->on_steps_returnPressed(lineEdit1); });
QSignalMapper* maper = new QSignalMapper (this) ;
connect(lineEdit2, SIGNAL(returnPressed()), maper, SLOT(map()));
maper->setMapping(lineEdit2, lineEdit2);
connect(maper, SIGNAL(mapped(QWidget*)), this, SLOT(on_steps_returnPressed(QWidget*)));
}
public slots:
void on_steps_returnPressed(QLineEdit* edit)
{
label->setText(edit->text());
}
void on_steps_returnPressed(QWidget* widget)
{
QLineEdit* edit = qobject_cast<QLineEdit*>(widget);
if (!edit)
return;
label->setText(edit->text());
}
private:
QLineEdit* lineEdit1;
QLineEdit* lineEdit2;
QLabel* label;
};

How to have multiple Qt buttons return each different values

I'm relatively new to Qt and I’m stuck with trying to figure out how to have different buttons each return a specific value when they're clicked.I've read through the Qt doc on signals and slots but I didn't find something useful.
I know that I can just have used the clicked function and return a value using the "goto slots" however, from the main, I would like to just call a getChoice function that would open a new window and based of what the user clicks I would return a corresponding int that I can use for later. Something like this is how it would look from the main.
OptionMenuWindow option;
int choice = option.checkChoice();
So this is my code in the OptionMenuWindow class and I've tried passing an int as a reference through to the slot so that when choice0Clicked is activated I know which button was clicked.
int OptionMenuWindow::checkChoice(){
this->show();
QEventLoop waitForResponse;
//THIS IS WHERE I TRY AND DO THAT
connect(ui->manageEmployee, SIGNAL (clicked()), &waitForResponse, SLOT(choice0Clicked()));
connect(ui->view, SIGNAL (clicked()), &waitForResponse, SLOT(choice1Clicked()));
connect(ui->generatePayroll, SIGNAL (clicked()), &waitForResponse, SLOT(choice2Clicked()));
waitForResponse.exec();
cout << "here" << endl
cout << choice << endl;
return choice;
}
void OptionMenuWindow::choice0Clicked()
{
choice = 0;
}
void OptionMenuWindow::choice1Clicked()
{
choice = 1;
}
void OptionMenuWindow::choice2Clicked()
{
choice = 2;
}
choice is defined in the header file.
This is the error I'm getting:
QObject::connect: No such slot QEventLoop::choice0Clicked(&choice)
QObject::connect: (sender name: 'manageEmployee')
QObject::connect: No such slot QEventLoop::choice1Clicked(&choice)
QObject::connect: (sender name: 'view')
QObject::connect: No such slot QEventLoop::choice2Clicked(&choice)
QObject::connect: (sender name: 'generatePayroll')
I really believe that there is a better of doing this so if there is, can someone please explain it?
And if there is anything you need me to elaborate on, please tell me it in the comments.
Thank you
You can use QSignalMapper.
From Qt Assistant :
This class collects a set of parameterless signals, and re-emits them
with integer, string or widget parameters corresponding to the object
that sent the signal
signalMapper = new QSignalMapper(this);
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]);
}
connect(signalMapper, SIGNAL(mapped(QString)),
this, SIGNAL(clicked(QString)));
You can not overload a slot. It should match the signal signature.
It should be something like this only
QObject::connect(ui->manageEmployee, SIGNAL (clicked()), &waitForResponse, SLOT(choice0Clicked()));
QObject::connect(ui->view, SIGNAL (clicked()), &waitForResponse, SLOT(choice1Clicked()));
QObject::connect(ui->generatePayroll, SIGNAL (clicked()), &waitForResponse, SLOT(choice2Clicked()));
Now coming to the button indexing
Let us assume you have push buttons -- "button1", "button2" and "button3".
Create "QButtonGroup" object.
QButtonGroup *bGroup = new QButtonGroup ();
Add all buttons with Ids.
bGroup->addButton(button1, 0);
bGroup->addButton(button2, 1);
bGroup->addButton(button3, 2);
Now in the slots to get ID of button:
void OptionMenuWindow::choice0Clicked()
{
QPushButton* button = qobject_cast<QPushButton*>(sender());
int buttonID = bGroup->id(button);
}
void OptionMenuWindow::choice1Clicked()
{
QPushButton* button = qobject_cast<QPushButton*>(sender());
int buttonID = bGroup->id(button);
}
void OptionMenuWindow::choice2Clicked()
{
QPushButton* button = qobject_cast<QPushButton*>(sender());
int buttonID = bGroup->id(button);
}

How to add a slot to a QWidget?

I have a QMainWindow, which has a QAction whose signal triggered() is connected to a slot about2().
...
connect(mAboutAction2, SIGNAL(triggered()), this, SLOT(about2()));
...
void occQt::about2() //UI
{
QWidget* pWidget = new QWidget;
QPushButton* okbtn = new QPushButton(tr("ok"));
QPushButton* cancelbtn = new QPushButton(tr("cancel"));
btnlayout->addWidget(okbtn);
btnlayout->addWidget(cancelbtn);
dlglayout->setMargin(50);
dlglayout->addLayout(gridlayout);
dlglayout->addStretch(40);
dlglayout->addLayout(btnlayout);
pWidget->setLayout(dlglayout);
pWidget->setWindowTitle(tr("Make a Box by custom."));
pWidget->show();
connect(okbtn, SIGNAL(clicked()), pWidget, SLOT(make_a_box()));
connect(cancelbtn, SIGNAL(clicked()), pWidget, SLOT(close()));
}
void occQt::make_a_box()
{
TopoDS_Shape aTopoBox = BRepPrimAPI_MakeBox(3.0, 4.0, 95.0).Shape();
Handle_AIS_Shape anAisBox = new AIS_Shape(aTopoBox);
anAisBox->SetColor(Quantity_NOC_AZURE);
mContext->Display(anAisBox);
}
When I run the slot about2(), the UI opens. I can close it when I click the cancelbtn, but I can't enter the slot make_a_box().
Where can I add this slot in order to make this code working?
This is ok and runs fine, because the slot you are using is located at the right place : in your occQt class.
// You connect the signal FROM the action TO "this", i.e. your class
connect(mAboutAction2, SIGNAL(triggered()), this, SLOT(about2()));
void occQt::about2() //UI
{
QWidget* pWidget = new QWidget;
QPushButton* okbtn = new QPushButton(tr("ok"));
QPushButton* cancelbtn = new QPushButton(tr("cancel"));
btnlayout->addWidget(okbtn);
btnlayout->addWidget(cancelbtn);
dlglayout->setMargin(50);
dlglayout->addLayout(gridlayout);
dlglayout->addStretch(40);
dlglayout->addLayout(btnlayout);
pWidget->setLayout(dlglayout);
pWidget->setWindowTitle(tr("Make a Box by custom."));
pWidget->show();
Now, this is not ok :
// You connect the signal FROM the button to pWidget, which doesn't have a slot make_a_box()
connect(okbtn, SIGNAL(clicked()), pWidget, SLOT(make_a_box()));
The slot make_a_box() doesn't exist for pWidget, which is a QWidget. You are trying to connect a signal to a slot that does not exist.
You have to define this slot in your occQt class, and connect the signal clicked() of the button to your slot in your class :
// Now, you connect the signal FROM the button to "this", which is your class and has a slot make_a_box()
connect(okbtn, SIGNAL(clicked()), this, SLOT(make_a_box()));
In your .h file, you will have :
private slots :
void make_a_box();
And in your .cpp file :
void occQt::make_a_box()
{
TopoDS_Shape aTopoBox = BRepPrimAPI_MakeBox(3.0, 4.0, 95.0).Shape();
Handle_AIS_Shape anAisBox = new AIS_Shape(aTopoBox);
anAisBox->SetColor(Quantity_NOC_AZURE);
mContext->Display(anAisBox);
}

how to use mousePressEvent on QPushButtons

I've made some QPushbuttons like QPushButton **btn and I want to know when the user clicks on one of them using QMouseEvent here is the code but this idea does not work at all any ideas??
void Game::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton)
{
btn[ev->x()][ev->y()].setStyleSheet("background-color : black;");
}
else
{
btn[ev->x()][ev->y()].setStyleSheet("background-color : red;");
}
that else part is for right click
and here is the code that generates the buttons
void Game::MakeButton()
{
btn = new ApButton*[column];
hrztl = new QHBoxLayout[column];
hrztl->setSpacing(0);
for(int i=0; i<column;i++)
{
btn[i] = new ApButton[row];
for(int j=0; j<row; j++)
{
btn[i][j].setRowCol(i,j);
btn[i][j].setFixedSize(50,50);
hrztl[i].addWidget(&btn[i][j]);
}
ui->MainLayout->addLayout(&hrztl[i]);
}
ui->MainLayout->setSpacing(0);
}
ApButton is a class that inherits QPushButton
This is a good example of use for a QSignalMapper, as seen there: http://qt-project.org/doc/qt-5.0/qtcore/qsignalmapper.html#details
ButtonWidget::ButtonWidget(QStringList texts, QWidget *parent)
: QWidget(parent)
{
signalMapper = new QSignalMapper(this);
QGridLayout *gridLayout = new QGridLayout;
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]);
gridLayout->addWidget(button, i / 3, i % 3);
}
connect(signalMapper, SIGNAL(mapped(QString)),
this, SIGNAL(clicked(QString)));
setLayout(gridLayout);
}
In that example, every button is identified by its title, as a QString. The mapper allows you to retrieve the corresponding button's title when one of them is clicked.
Switch your
Game::mousePressEvent(QMouseEvent *e)
to
ApButton::mousePressEvent(QMouseEvent *e)
since you are trying to implement the Press Event of the Button. If you only want to have the moment of the button being pressed and not changing Button behaviour with this, use a SIGNAL/SLOT connection instead of reimplementing the event (add to your creation):
connect(btn[i][j], SIGNAL(pressed()), this, SLOT(slotButtonPressed());
void Game::slotButtonPressed(){
//doSomething
}
use a QButtonGroup or the QSignalMapper if you need to identify more then one Button in a single method or use QObject::sender(), but this can be tricky sometimes.
I had a similar situations some times ago.. I had a QDialog and I had to dinamically add some QPushButton.. then I need to know on which button the user pressed.. so I needed something like:
connect( btn, SIGNAL( clicked(int) ),
this, SLOT( handle(int) ));
for instance a signal-slot connection with the id of the clicked button and a function for handle the click. The function is the same for each buttons and can handle the specific button because of the id..
Implementing this is quite simple subclassing QPushButton adding an id and a new signal..
Hope it's some help!
If Apbutton inherits QPushButton, why don't connect to clicked()?
then you can call QObject::sender()
On slot:
ApButton *but = dynamic_cast<ApButton*>QObject::sender()
if(but)
{
but->setStyleSheet("background-color : black;");
}
to get the clicked buttonbutton and set its stylesheet