signal mapping issue with QlineEdit - c++

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;
};

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.

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);
}

QTableView: How can i use clicked() signal correctly to get index of selected item?

I am having a delete button in every row. I am trying to use clicked() SIGNAL of QTableview to get the current index and then do something accordingly, but this slot is not called in this case. For some reason it doesn't work, am I making some mistake in connecting clicked() SIGNAL?
void MyClass::myFunction()
{
ComboBoxItemDelegate* myDelegate;
myDelegate = new ComboBoxItemDelegate();
model = new STableModel(1, 8, this);
filterSelector->tableView->setModel(model);
filterSelector->tableView->setItemDelegate(myDelegate);
connect(filterSelector->tableView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(slotHandleDeleteButton(const QModelIndex&)));
exec();
}
void MyClass::slotHandleDeleteButton(const QModelIndex& index)
{
if(index.column() == 8)
model->removeRow(index.row());
}
One of the solutions can look like this:
class Button : public QPushButton
{
Q_OBJECT
public:
Button(int row, QWidget *parent = 0) : QPushButton(parent), m_row(row)
{
connect(this, SIGNAL(clicked()), this, SLOT(onClicked()));
}
signals:
void clicked(int row);
private slots:
void onClicked()
{
emit clicked(m_row);
}
private:
int m_row;
};
Button class contains a custom signal clicked(int) with the row number as an argument. To use it in your table view you need to do:
Button *btn = new Button(rowNumber, this);
connect(btn, SIGNAL(clicked(int)), this, SLOT(onButtonClicked(int)));

QT: Dynamic child button not visible

I have a project that I want to add button dynamically wherever I click in my form.
This is my header:
namespace Ui {
class frmBedBook;
}
class frmBedBook : public QWidget
{
Q_OBJECT
public:
explicit frmBedBook(QWidget *parent = 0);
void mousePressEvent(QMouseEvent *event);
~frmBedBook();
private:
Ui::frmBedBook *ui;
QSignalMapper *signalMapper;
QList<QPushButton*> buttonList;
QGridLayout *lyWidget;
QWidget *m_widget;
public slots:
void clicked(int buttonId);
};
And this is my implementation:
frmBedBook::frmBedBook(QWidget *parent) :
QWidget(parent),
ui(new Ui::frmBedBook)
{
ui->setupUi(this);
signalMapper = new QSignalMapper();
QPushButton *p;
lyWidget = new QGridLayout();
m_widget = new QWidget();
m_widget->setGeometry(0,0,930,472);
lyWidget->setContentsMargins(0,0,0,0);
lyWidget->addWidget(m_widget);
setLayout(lyWidget);
p = new QPushButton(m_widget);
p->setText("00");
p->setGeometry(0, 0, 50, 50);
buttonList.append(p);
connect(p, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(p,0);
p = new QPushButton(m_widget);
p->setText("01");
p->setGeometry(50, 0, 50, 50);
p->setObjectName("01");
buttonList.append(p);
connect(p, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(p,1);
connect(signalMapper, SIGNAL(mapped(int)),this, SLOT(clicked(int)));
}
void frmBedBook::mousePressEvent(QMouseEvent *event)
{
QPushButton *p;
p = new QPushButton(m_widget);
p->setText("02");
p->setGeometry(QCursor::pos().x(), QCursor::pos().y(), 50, 50);
buttonList.append(p);
connect(p, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(p,2);
}
The problem is the button is created, but not visible. I know it because I have traced through m_widget's children and it's found. I also already resetting layout in MousePressEvent function, but nothing happened. Could anyone please help me about this problem?
You need to call show() on your buttons if they are added after the form has been constructed. Also, QCursor::pos() will probably not deliver the position you want to have.
You can use the x()/y() functions of the QMouseEvent instead:
void frmBedBook::mousePressEvent(QMouseEvent *event)
{
QPushButton *p;
p = new QPushButton(m_widget);
p->setText("02");
p->setGeometry(event->x(), event->y(), 50, 50);
p->show();
buttonList.append(p);
connect(p, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(p,2);
}
Note that you need to #include <QtGui/QMouseEvent> unless you already have that.
You never show the buttons, so they stay hidden. Use QWidget::show(). This applies to widgets created in mousePressEvent, after parent is already shown. The button created in constructor should get automatically shown when its parent is shown.

Qt no matching function for call

I'm trying to connect a button click to a function, and pass an int value, but keep getting an error: no matching function for call to Main::connect... I'm guessing that I'm not initializing something correct?
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
setupUI();
}
MainWindow::~MainWindow() {
}
void MainWindow::setupUI() {
QFrame* frame = new QFrame(this);
_layout = new QVBoxLayout;
frame->setLayout(_layout);
parseXML();
QScrollArea* scrollArea = new QScrollArea;
scrollArea->setWidget(frame);
scrollArea->setWidgetResizable(true);
setCentralWidget(scrollArea);
}
void MainWindow::parseXML() {
this->parseItem(xml, count)
}
QMap<QString, QString> MainWindow::parseItem(QXmlStreamReader& xml, int count) {
QString valueName = "buttonid";
QSignalMapper *signalMapper = new QSignalMapper(this);
QPushButton* button = new QPushButton(valueName);
_layout->addWidget(button);
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(addMenu(int)));
signalMapper->setMapping(button, valueName);
connect(button, SIGNAL(clicked())), signalMapper, SIGNAL(map());
return something;
}
void MainWindow::addMenu(int count) {
_layoutToAdd = new QVBoxLayout;
QPushButton* button = new QPushButton("New Button");
_layoutToAdd->addWidget(button);
_layout->insertLayout(count, _layoutToAdd, 0);
}
mainwindow.h
ublic:
MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void parseXML();
void addMenu(int count);
signals:
void clicked();
There's a syntax error in your code. Count your parenthesis :
connect(button, SIGNAL(clicked())), signalMapper, SIGNAL(map());
// ^ ^ ^^^^
// 1 2 3321 <-- All your parenthesis are closed at this point
// meaning you are calling connect() with only 2 parameters
You must white Q_OBJECT (for using signals and slots ) in descriction of your class
class MainWindow: public QObject
{
Q_OBJECT