How to add a slot to a QWidget? - c++

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

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

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.

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

Mouse events aren't passed to QPushButton added in QGraphicsItemGroup

I'm using Qt 4.8.3 (32 bit) on Windows 7 Ultimate x64.
In a constructor of a QGraphicsScene subclass, I have:
QGraphicsItemGroup *point_table = new QGraphicsItemGroup;
addItem(point_table);
Later in the constructor:
QPushButton *button = new QPushButton("Call++");
QGraphicsProxyWidget *inc_button = addWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(onCallIncrease()));
onCallIncrease() gets called whenever the button is clicked. However, if I add inc_button to point_table, onCallIncrease() doesn't get called.
QPushButton *button = new QPushButton("Call++");
QGraphicsProxyWidget *inc_button = addWidget(button);
point_table->addToGroup(inc_button);
connect(button, SIGNAL(clicked()), this, SLOT(onCallIncrease())); // doesn't work
Even if I manually set to accept left mouse button:
QPushButton *button = new QPushButton("Call++");
QGraphicsProxyWidget *inc_button = addWidget(button);
inc_button->setAcceptedMouseButtons(Qt::LeftButton);
point_table->setAcceptedMouseButtons(Qt::LeftButton);
point_table->addToGroup(inc_button);
connect(button, SIGNAL(clicked()), this, SLOT(onCallIncrease())); // doesn't work
onCallIncrease() doesn't get called on left mouse click. Why is this happening?