QDialog Non-modal Behaves as Modal for Parent Window
-
Hi,
I recently changed over from Qt 4.7.something to Qt 5.3.2, and I am experiencing some difficulties due to changes in how Qt works.
I have a QMainWindow which spawns some QDialogs. The QMainWindow is passed in as the parent widget to the QDialogs. Then, the QDialogs are made available to the user via dialog->setVisible(true); I can launch multiple QDialogs and they aren't modal to each other, however they all overlap the parent widget, ie: the QMainWindow.
I have googled the issue and attempted to set flags to resolve this but currently nothing works. If I create the dialogs with no parent, then they no longer overlap the QMainWindow, but then they create their own entry in the taskbar.
Is anyone else seeing this? Am I missing something easy?
Thanks!
-
Hi,
passing a parent to QDialog (like your QMainWindow) does exactly what you want to avoid. QDialogs are used to "arrest" processing until user makes some input. By default, QDialogs are application modal, what means you even can't interact with other QDialogs, so you really have to close the QDialog before doing anything else. By passing a parent to the QDialog (in your case the QMainWindow), the QDialog becomes window modal mode, what means only interaction with your QMainWindow is stopped until QDialog is closed again..
To avoid blocking other stuff, you call the QDialogs with show() command, so focus goes immediately back to QMainWindow after showing it. If you do that and QDialog still blocks your QMainWindow, you should check modality via QDialog::modal(), if that is true, you should set it to false (setModal(false))..
If you want to avoid the taskbar button, just create the QDialog with a new QWidget as parent:
@QDialog myIndependendDialog(new QWidget);@
But note that you will have to free memory manually...EDIT:
Documentation says QDialog::setVisible() does the same as QDialog::show(), so I'm really wondering why your QDialog is window modal... But it also says there is no need to use setVisible(), instead you should use show()... maybe you try it with show() and QMainWindow as parent and if it is still blocked... then I don't know what's going on..Hope that helps you ;-)
-
Thanks for your reply,
I have looked at the Qt::WindowsFlags of each window, and have the following:
MainWindow = 0x8800F001;
Qt::WindowFullscreenButtonHint 0x80000000
Qt::WindowCloseButtonHint 0x08000000
Qt::WindowMaximizeButtonHint 0x00008000
Qt::WindowMinimizeButtonHint 0x00004000
Qt::WindowSystemMenuHint 0x00002000
Qt::WindowTitleHint 0x00001000
Qt::Window 0x00000001Dialogs = 0x08013003
Qt::WindowCloseButtonHint 0x08000000
Qt::WindowContextHelpButtonHint 0x00010000
Qt::WindowSystemMenuHint 0x00002000
Qt::WindowTitleHint 0x00001000
Qt::Dialog 0x00000002
Qt::Window 0x00000001And the dialog.isModal() returns false.
I have tried replacing dialog->show() / dialog->hide() and they have the same effect as dialog->setVisible(true). I use setVisible because there is a function with a bool input to toggle the dialog visibility.
This did work as expected in Qt 4.7... It would give me non-modal dialog windows which would not generate a new entry on the taskbar.
-
Here is an example, not my exact code but essentially the same. The function "showDialog" is called from intermediate functions which are connected to button "toggled(bool)" signals, 1:1. In my version the "showDialog" does more than just show the dialogs so it was implemented in a common function.
@
// Main Window Header:MyMainWindow : public QMainWindow
{
Q_OBJECT
public:
// constructors, functions I need, etc..
....private:
void showDialog(QWidget * window, bool show);
std::vector<std::shared_ptr<MyDialog>> m_myDialogs;
}// Main Window Cpp
namespace
{
const int numberOfDialogs = 10;
};MyMainWindow::MyMainWindow(...)
{
for (int i = 0; i < numberOfDialogs; ++i)
{
std::shared_ptr<MyDialog> tempDialog;
tempDialog.reset(new MyDialog(this));
m_myDialogs.push_back(tempDialog);
}
}void MyMainWindow::showDialog(QWidget * dialog, bool show)
{
dialog->setVisible(show);// I have also tried:
// if (show)
// {
// dialog->show();
// }
// else
// {
// dialog->hide();
// }
}
@ -
Is there any reason why you use QWidget ptr in your parameter list of MyMainWindow::showDialog(..) ?
Have you tried to use QDialog ptr instead? Or if not (for reasons like you also have to pass QWidgets to this function), maybe downcast before handling the dialog as a QDialog?
Try the following first:
@ // Main Window Header:MyMainWindow : public QMainWindow { Q_OBJECT public: // constructors, functions I need, etc.. .... private: void showDialog(QDialog*, bool show); std::vector<std::shared_ptr<MyDialog>> m_myDialogs; } // Main Window Cpp namespace { const int numberOfDialogs = 10; }; MyMainWindow::MyMainWindow(...) { for (int i = 0; i < numberOfDialogs; ++i) { std::shared_ptr<MyDialog> tempDialog; tempDialog.reset(new MyDialog(this)); m_myDialogs.push_back(tempDialog); } } void MyMainWindow::showDialog(QDialog* dialog, bool show) { dialog->setVisible(show); // I have also tried: // if (show) // { // dialog->show(); // } // else // { // dialog->hide(); // } }@
If that still doesn't work, maybe you can show how you call the function?
-
Yeah I have other window types I pass in as well, of type QMainWindow. These other MainWindows don't seem to have the problem (ie: they don't hide the parent). Maybe I will change all my dialogs to MainWindows.
It just seems like this is not the expected behaviour for a Dialog, given the way I am using it, though maybe I am wrong.
-
The problem must be anywhere else in the code. Normally, a QDialog shouldn't behave like that. You do downcasting to QDialog in your function body, right?
It won't be the best solution to give up and go away from QDialogs, but If you want to do so, you don't have to use QMainWindows, you can simply use QWidgets as windows... -
I have tried to use straight up "QDialog *" instead of "QWidget *", and it made no difference. I know you are saying that the problem is in my code, but have you tried to do the same thing I have done and had different results?? I would be glad if I was simply making a mistake with how I was using dialogs, because it means I can fix the way I am using them, without replacing them with something else.
-
The problem is, I can't really test your code in the way you do it, because obviously you are using a subclass of QDialog with new functionallity which I can't see, also I don't know where in your code you ever call the function showDialog.
Tipp:
Try always to use Qt's class system when working with Qt stuff, it avoids problems and in most cases, it is faster and more powerful.
Take a look at "QSharedPointer":http://qt-project.org/doc/qt-5/qsharedpointer.html or "QVector":http://qt-project.org/doc/qt-5/qvector.html, there is no need to use the std stuff I think.. -
I changed my windows to inherit from QWidget instead of QDialog. This has seemed to fix the issues I was seeing. Maybe that is the intended behaviour of QDialog?
I am using a subclass of QDialog. All it is doing was connecting signals from controls (two QPushButton(s), and a QTableView) to some private slots. I was not overriding any specialized control of QDialog anywhere. The showDialog() function was being called by X different slots, each of which was connected to a different QPushButton::toggled() signal. The main window was used as a "launcher" of these other windows. So picture 10 buttons, each with their own slot, which when the button is clicked, it calls "showDialog" with a very specific *Widget passed in, and the "show" set true if toggled on, and false if toggled off.
Anyway, mixing std:: and Qt:: should not have any issues. A shared_ptr or a vector are not going to change the behaviour of a QDialog.
Thank you everyone for your suggestions, this can be considered closed.