Qt - Close subMenu with signal/slot - qt

I have a Qt main window where I call another window, actually a kind of submenu wich contains parameters for the first one; here is a part of this main window :
void Ui_MainWindow::createSignals()
{
connect(actionDisk_galaxy, SIGNAL(triggered()), this, SLOT(ICMenu()));
}
void Ui_MainWindow::ICMenu()
{
qmenu = new QMainWindow;
DiskMenu = new Ui_DiskGalMenu;
DiskMenu->setupUi(qmenu,this);
setInitialDiskMenuPosition(qmenu, this);
qmenu->show();
}
As you can see, I call another QMainwindow ("qmenu"); here's the code of this new window (whose type is "Ui_DiskGalMenu"):
void Ui_DiskGalMenu::createMenuSignals()
{
connect(pushButton_4, SIGNAL(clicked()), this, SLOT(closeMenu()));
}
void Ui_DiskGalMenu::closeMenu()
{
close(true);
}
After setting parameters in this sub-menu, I would like to close it with a pushButton (here "pushButton_4").
My problem is that when I click on "pushButton_4", this window doesn't close.
I have also tried to reimplement closeEvent but without success.

This function call looks like a mistake:
close(true);
QWidget::close() doesn't take any parameters. So what you're doing here, is call the close(int) function of the C library (for closing file descriptors.) bool is implicitly converted to int, so you end up with this call:
::close(1);
Which is (probably) closing stderr.
You can see what's happening if you change the above to:
this->close(true);
You should get a compilation error since no such function exists. So the correct call would have been:
this->close();
However, QWidget::close() is already a slot, so you don't need the Ui_DiskGalMenu::closeMenu() function at all. All you need is connect to the close() slot to begin with:
connect(actionDisk_galaxy, SIGNAL(triggered()), this, SLOT(close()));
If you need to do more stuff when the window closes, you can override closeEvent() which will be called before the window gets closed.

Related

QT , my form was hidden after calling setWindowFlags() in my slots

I just want to disable form's close button while doing a task(by QThread), So I connected the thread's signal "started()" and "finished()" to my two slots, for controlling my form's close button.
//...
m_pTestThread = new TestThread();
connect(m_pTestThread, SIGNAL(started()), this, SLOT(onThreadStart()));
connect(m_pTestThread, SIGNAL(finished()), this, SLOT(onThreadFinish()));
m_pTestThread->start();
//...
void QTest::onThreadStart()
{
this->setWindowFlags(this->windowFlags() & (~Qt::WindowCloseButtonHint));
}
void QTest::onThreadFinish()
{
this->setWindowFlags(this->windowFlags() | Qt::WindowCloseButtonHint);
}
After the thread started, my form was hidden... that is strange.
So I call show() after setWindowFlags() function to avoid this problem,
but still don't know why this happened...
Is this the expected behaviour? Should I call show() after setWindowFlags()?
Check the documentation for setWindowFlags here:
Note: This function calls setParent() when changing the flags for a
window, causing the widget to be hidden. You must call show() to make
the widget visible again..

How to programmatically close QMenu

I have pretty specific situation. I want to place a QAction into QToolbar and reach following behaviour:
Checkable QAction with icon.
Classic arrow on the right side which is used for showing menu
By pressing this arrow my QDialog should appears on screen instead of QMenu-like one
Now I'm a bit confused with implementing all this things together.
For now I've created QAction added it to toolbar and also created an empty QMenubecause I didn't get the idea of how to add the "dropdown" arrow another way.
So, I also connected my slot to QMenu aboutToShow() signal and now, I can create my dialog and exec() it just before QMenu shows. But here's the main problem appears: after I did everything with my dialog an click OK button QMenu trying to appear, but as it is empty it shows nothing and further actions become available only after I left-click somwhere to "close" this menu.
Is there any way to force QMenu not to show or can inherit from QMenu and reimplemnt its behaviour (I've tried to do such trick with exec() show() popup() methods of QMenu after subclassing from it, but none of them are being called when menu appears on the screen) ?
Here's the solution, which worked for me.
class QCustomMenu : public QMenu
{
Q_OBJECT
public:
QCustomMenu(QObject *parent = 0):QMenu(parent){};
};
In code:
QAction* myActionWithMenu = new QAction ( "ActionText", toolbar);
QCustomMenu* myMenu = new QCustomMenu(toolbar);
connect(myMenu, SIGNAL(aboutToShow()), this, SLOT(execMyMenu()));
execMyMenu() implementation:
void execMyMenu(){
m_activeMenu = (QCustomMenu*)sender(); // m_activeMenu -- private member of your head class, needs to point to active custom menu
QMyDialog* dlg = new QMyDialog();
// setup your dialog with needed information
dlg->exec();
// handle return information
m_myTimer = startTimer(10); // m_myTimer -- private member of your head(MainWindow or smth like that) class
}
Now we have to handle timerEvent and close our menu:
void MyHeadClass::timerEvent(QTimerEvent *event)
{
// Check if it is our "empty"-menu timer
if ( event->timerId()==m_myTimer )
{
m_activeMenu->close(); // closing empty menu
killTimer(m_myTimer); // deactivating timer
m_myTimer = 0; // seting timer identifier to zero
m_activeMenu = NULL; // as well as active menu pointer to NULL
}
}
It works great on every platform and does what I wanted.
Hope, this would help someone. I've spent week trying to find this solution.

Using the closeEvent in a qt application does not close it

I am learning qt, and experimenting with examples from a textbook.
The original textbook code has the following, set up to save and close on the x button:
void MainWindow::closeEvent(QCloseEvent *event)
{
if (okToContinue()) {
writeSettings();
event->accept();
} else {
event->ignore();
}
}
i experimented with a simple exit in its menu - and it works:
void MainWindow::close()
{
if (okToContinue()) {
QApplication::quit();
}
}
But I want to take advantage of the already written closeEvent, so i replaced the code above with
void MainWindow::close()
{
QCloseEvent *event = new QCloseEvent();
closeEvent(event);
}
I get the checking for changes and saving app, implemented through the okToContinue function. But the application does not close.
i tried to follow through debugging and.. with my small understanding, it seems that there is a close signal being sent...
I don't have a good understanding of this, can somebody please help me figure out what am i doing wrong and how to fix it ?
(the sample code is from C++ GUI Programming with Qt 4, chapter 3)
You don't have to reimplement MainWindow::close() in your subclass.
From the Qt Docs:
...QCloseEvent sent when you call QWidget::close() to close a widget
programmatically...
So you just have to reimplement MainWindow::closeEvent(QCloseEvent *event) if you want to control this event.
This event fires when you click x or call close() from the code.
The closeEvent and related methods don't actually execute the action that happens when a given event is received. They merely allow you to act on the event and perhaps disable its further processing. The closing of the window is done within QWidget::event, where closeEvent is called from.

Qt PushButton exec widgets

I have a checkable pushbutton set to exec/close a dialog widget that I have created.
My idea is when the pushbutton is checked, it will close the dialog widget. If it's not checked, it should open the dialog widget. But I am unable to get it to work. It keeps on opening instances of the dialog widget. I wanted to open one instance of the dialog widget only. Could anyone please help?
MainDlg::MainDlg()
{
connect(dialogButton, SIGNAL(clicked()), this, SLOT(setDialog()));
}
void MainDlg::setDialog()
{
SetDialogDlg setDlg;
if(dialogButton->isChecked())
{
setDlg.close();
}
else
{
setDlg.exec();
}
}
There are a few things that are wrong in your code. First thing is, your SetDialogDlg object will only exist inside your MainDlg::setDialog() function. Once this function finishes your SetDialogDlg object will be destroyed.
Then you are creating a new instance of SetDialogDlg every time MainDlg::setDialog() function is called. And you are trying to close a dialog that hasn't been shown yet.
Then there is a problem with setDlg.exec(). This is a blocking function. So you shouldn't even be able to push your dialogButton once the dialog has been shown.
To solve these problems you should have a member variable in your MainDlg class.
//maindlg.h
...
public:
SetDialogDlg *myDialog;
...
 
//maindlg.cpp
MainDlg::MainDlg()
{
...
myDialog = new SetDialogDlg(this);
...
}
 
Then inside your MainDlg::setDialog() function, call QWidget::show() instead of QDialog::exec().
void MainDlg::setDialog()
{
if(dialogButton->isChecked())
{
myDialog->close();
}
else
{
myDialog->show();
}
}

Cannot change cursor in Qt main window from menu action

In my MainWindow, I have a push button and a menu bar item whose signals are both connected to the same slot. In the slot function, I have written:
mainWindow->setCursor(QCursor(Qt::WaitCursor));
This works as expected when the slot function is invoked via the button; however, when the same function is invoked from the menu, the wait cursor doesn't appear. Any idea why?
I also considered using QApplication::setOverrideCursor; however, that causes other problems.
Any recommendations? Thanks!
(I am using Qt 4.7 and doing my development on Windows 7 using Qt Creator with the default MinGW compiler.)
Here's more detail.
in MainWindow constructor: this->setCursor(Qt::CrossCursor);
signal/slot connections:
QObject::connect(button, SIGNAL(clicked()), MainWindow, SLOT(showMessageBox()));
QObject::connect(action, SIGNAL(triggered()), MainWindow, SLOT(showMessageBox()));
showMessageBox function:
void MainWindow::showMessageBox()
{
this->setCursor(Qt::WaitCursor);
// display wait cursor briefly before showing message box
for (int i = 0; i < 1<<30; ) {++i;}
QMessageBox msgBox;
msgBox.setText("Hello!");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setCursor(Qt::PointingHandCursor);
msgBox.exec();
this->setCursor(Qt::CrossCursor);
}
When showMessageBox is invoked with 'button', the wait cursor is displayed as expected.
When showMessageBox is invoked through 'action', the wait cursor does not appear; instead the cursor changes from Qt::CrossCursor to a Qt::ArrowCursor as soon as the user selects the 'action' menu item, and then changes to Qt::PointingHandCursor once the message box opens. The wait cursor never appears.
Your code is synchronous and uses a delay loop. When you're in the delay loop, there's no way for any Qt code to execute. A cursor change requires the event loop to be spinning -- so it appears from the symptoms you give.
Here's how to do it correctly -- remember, if you use delays/sleeps and other blocking calls in your GUI code, your users will hate you, and rightly so. Using exec() in message/dialog boxes is also bad style. Your application is asynchronous, code it so. Make sure your slots are declared as such (in the protected slots: section of MainWindow declaration).
void MainWindow::showMessageBox()
{
this->setCursor(Qt::WaitCursor);
QTimer::singleSlot(200, this, SLOT(slot1()); // fire slot1 after 200ms
}
void MainWindow::slot1()
{
QMessageBox * msgBox = new QMessageBox(this);
msgBox->setText("Hello!");
msgBox->setStandardButtons(QMessageBox::Ok);
msgBox->setCursor(Qt::PointingHandCursor);
msgBox->show();
connect(msgBox, buttonClicked(QAbstractButton*), SLOT(slot2(QAbstractButton*)));
}
void MainWindow::slot2(QAbstractButton* button)
{
// a button was clicked on the message box
this->setCursor(Qt::CrossCursor);
}

Resources