I am trying to implement a signal-slot system for a QDialog. After a Google search, I've got this question on Stack Overflow. That answer looks promising, so I tried to use it. I get no error, but the slot doesn't work. Below is my code:
newactivity.cpp
// in the QDialog constructor
QObject::connect(this->ui.createBtn, SIGNAL(clicked()), this, SLOT(accept()));
QObject::connect(this->ui.cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
void newActivity::accept() {
QDialog::accept(); // to close the dialog and return 1
}
void newActivity::reject() {
QDialog::reject(); // to close the dialog and return 0
}
schedule.cpp
void Schedule::on_actionNew_Activity_triggered() {
newActivity *newActivityWnd = new newActivity(this, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
newActivityWnd->exec();
QObject::connect(newActivityWnd, SIGNAL(accepted()), this, SLOT(on_activityCreated()));
}
void Schedule::on_activityCreated() {
this->ui.timeLine->hide();
}
Here is my dialog:
Nothing happens when I press the Create button on New activity dialog. Where am I wrong?
I suppose you reorder the code in schedule.cpp as:
void Schedule::on_actionNew_Activity_triggered() {
newActivity *newActivityWnd = new newActivity(this, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
QObject::connect(newActivityWnd, SIGNAL(accepted()), this, SLOT(on_activityCreated()));
newActivityWnd->exec();
}
Does this solve your problem?
Related
I have a simple flow
Click on QPushButton
QMenu with a couple of actions appears
Navigate through the QMenu using key clicks or mouse move.
(Triggering actions from code isn't a way, it should be a clean GUI test).
QTest::keyClick(m_menu, Qt::Key::Key_Down); - doesn't seem to work for me.
Simple example:
#include "mainwindow.h"
#include <QTest>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
m_button = new QPushButton("My Button", this);
m_button->setFixedSize(100,50);
m_menu = new QMenu("&Menu");
m_menu->addAction("&test1");
m_menu->addAction("&test2");
m_menu->addAction("&test3");
m_menu->addAction("&test4");
m_menu->addAction("&test5");
m_menu->addAction("&test6");
connect(m_button, SIGNAL (released()), this, SLOT (handleButton()));
}
void MainWindow::handleButton()
{
m_menu->exec(m_button->mapToGlobal(QPoint(20,20)));
QTest::qWait(2000);
for(int i = 0 ;i<=5;i++){
QTest::keyClick(m_menu, Qt::Key::Key_Down);
QTest::qWait(1000);
QTest::mouseMove(m_menu, QPoint(0,20));
QTest::qWait(1000);
}
}
MainWindow::~MainWindow()
{
}
Thanks to vahancho I found work around.
QMenu.exec() is executing synchronously. So, to have an opportunity to provide some input when menu is opened we should use next template:
QTimer::singleShot(0, [menu]()
{
//code that should be executed
});
menu->exec();
I have main window and 1 dialog in Qt(in Linux OS).I want to send some thing from main window to my dialogs. When the user press menu button, then my button clicked emit a signals. this is my code in main.cpp:
MainWindow w;
MyDialog m;
//------------------------------
//this connection send key button press mood from MainWindow
QObject::connect(&w,SIGNAL(pressMood(QString)),
&m,SLOT(getPressMood(QString)));
w.show();
and this is my mainwindos.h:
signals:
void pressMood(QString mood) ;
mainwindow.cpp:
void MainWindow::on_btnMenu_clicked()
{
if(database->checkEmpty())
{
menu mn;/*=new menu();*/
mn.showFullScreen();
}
else
{
MyDialog *d=new MyDialog(this);
d->show();
d->raise();
d->activateWindow();
emit pressMood("menu");
if(d->Accepted>0)
{
if(loginResult)
{
menu *mn=new menu();
mn->showFullScreen();
}
}
else
QMessageBox::warning(this, tr("Login failed"), "Sorry.Your authenticate is not valid.", QMessageBox::Ok);
}
}
//--------------------------------------------
void MainWindow::on_btnPassword_clicked()
{
//emit sendID2(result);
CardDialog *d=new CardDialog(this);
emit pressMood("pass");
d->show();
d->raise();
if(d->Accepted<=0)
QMessageBox::warning(this, tr("Login failed"), "Sorry.Your authenticate is not valid.", QMessageBox::Ok);
}
I do not use dialog.exec() because I do not need to show modal.
MyDialog.h:
public slots:
void getPressMood(QString mood);
and MyDialog.cpp:
//=================================================
void MyDialog::getPressMood(QString mood)
{
mood=mood;
//ui->lblMood->setText(mood);;
//ui->lblMood->hide();
}
void MyDialog::on_buttonBox_accepted()
{
//QString mood=ui->lblMood->text();
bool st=database->checkPassword(ui->txtID->text(),ui->txtPass->text(),"3");
int id=(ui->txtID->text()).toInt();
//this user is valid to go to menu page
//s/he is admin
if((st)&&
mood=="menu" &&
database->checkAdmin(id))
{
.......
}
when I trace my code line by line. the emit signal is works , it sends the string data to my slot in another form and also the getpressedmood() slot is also worked. But the global var mood become NULL when the dialog show, also I decide to save data in label. In trace mood I see the string is send but when the dialog shows the label becomes to default value.
I can not find the mistake. Could you help me?
It solved.
my mistake is connect the signal and slot in main.cpp. The answer is :
MyDialog *d=new MyDialog(this);
//should connect here not in main.cpp
QObject::connect(this,SIGNAL(pressMood(QString)),
d,SLOT(getPressMood(QString)));
emit pressMood("menu");
d->show();
d->raise();
d->activateWindow();
I was trying to set the close event to my code but when I set this code my program crashes.
mainwindow.cpp
void MainWindow::closeEvent(QCloseEvent *event)
{
event->ignore();
if (QMessageBox::Yes == QMessageBox::question(this, "Close Confirmation?",
"Are you sure you want to exit?",
QMessageBox::Yes|QMessageBox::No))
{
if(QMessageBox::Yes)
{
if(aboutDialog)
{
aboutDialog->close();
event->accept();
}
event->accept();
}
}
}
void MainWindow::showAboutDialog()
{
aboutDialog = new QDialog;
Ui::About aboutUi;
aboutUi.setupUi(aboutDialog);
connect(aboutUi.Close, SIGNAL(pressed()), aboutDialog, SLOT(close()));
aboutDialog->show();
}
mainwindow.h
private:
QDialog *aboutDialog;
I am confused why this happens. Help me out to solve this!
Don't ignore the event if you're planning to close, try this:
void MainWindow::closeEvent(QCloseEvent *event)
{
if (QMessageBox::Yes != QMessageBox::question(this, "Close Confirmation?",
"Are you sure you want to exit?", QMessageBox::Yes | QMessageBox::No))
{
event->ignore();
}
}
And when creating the aboutDialog-box, you should pass the mainWindow as parent as Nejat's comment suggests: aboutDialog = new QDialog(mainWindow);. This will make sure that the aboutDialog will get closed if the main window closes.
The dialog opens with two buttons, OK and Cancel. None of the buttons responds to user click. I have to press the X on the top right to cancel the dialog.
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == mTabWidget && event->type() == QEvent::MouseButtonDblClick)
{
// query and set tab(s) names
QTabWidget *tab = qobject_cast<QTabWidget *>(obj);
if(tab)
{
QDialog dlg;
QVBoxLayout la(&dlg);
QLineEdit ed;
la.addWidget(&ed);
QDialogButtonBox bb(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
la.addWidget(&bb);
dlg.setLayout(&la);
if(dlg.exec() == QDialog::Accepted)
{
tab->setTabText(0, ed.text());
return true;
}
}
}
// Standard event processing
return QObject::eventFilter(obj, event);
}
Am I missing any connect() line or signals? I tried to read the Qt documentation, but from what I understood, calling QDialogButtonBox::OK gets processed as Accepted.
UPDATE :
New Dialog Function
OK, i have created a new function that takes care of the Dialog box, i am calling it from the event function. it is still not responding, now on the terminal, i see an error that says, : no such slot MainWindow::accept() and another for reject. I know that i have no slots for these two in the .h file. i tried to find how to build the slots but i couldnt, any help would be great. thank you
void MainWindow::initializeBOX()
{
QDialog dlg;
QVBoxLayout la(&dlg);
QLineEdit ed;
la.addWidget(&ed);
//QDialogButtonBox bb(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
//btnbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
la.addWidget(buttonBox);
dlg.setLayout(&la);
if(dlg.exec() == QDialog::Accepted)
{
mTabWidget->setTabText(0, ed.text());
}
}
Rather than launching the dialog from event filer you should trap QWidget::mouseDoubleClickEvent by overloading that virtual function in your code. And as long as it is a callback already you can do more stuff immediately from there including the dialog. Or maybe send the signal to slot that does the dialog (a bit cleaner). I would do the signal from mouseDoubleClickEvent event handler and make the parent QWidget::mouseDoubleClickEvent to consume the event to avoid possible complications especially when porting the code to other platform.
Event filters are for non-standard event processing. There is nothing non-standard in your case.
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