QFileDialog from child window closes the application
-
Hey guys,
This is a cross-post from SO with no answers:
I'm new to QT and I'm having issues when calling
QFileDialogfrom a child window. My app is relatively simple. I have one prompt widget that gets user input and then runs show on its parent. This is my main:int main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidjet w(nullptr); ChildWidget input(&w); input.show(); return a.exec(); }This is the relevant section of the child widget:
ChildWidget::ChildWidget(QWidget *parent) : QDialog(parent), ui(new Ui::InputPrompt){ ui->setupUi(this); this->setParent(parent); } ... void ChildWidget::on_imagesSelect_clicked() { inputFilepath = QFileDialog::getExistingDirectory(static_cast<ParentWidget *>(this->parent()), QCoreApplication::translate("main", "Open directory"), "./", QFileDialog::ShowDirsOnly); ui->inputPath->setPlainText(inputFilepath); std::cout << "y u exit" << std::endl; } //Setup and show the parent void ChildWidget::on_buttonBox_accepted() { static_cast<ParentWidjet *>(this->parent())->setup(inputFilepath, outputFilepath); static_cast<ParentWidjet *>(this->parent())->show(); }For some reason when
QFileDialogis called, closing it with either OK or Cancel closes both the parent and the child. If I don't use it, but click the OK button of the child, which calls theon_buttonBox_accepted()function, the child closes and the parent widget appears as expected. If I don't pass the parent widget to the child widget in the main,QFileDialogno longer closes the child widget when running. I tried changing the parent ofQFileDialogtothisor tonullptrbut that didn't help.Any ideas? Is this expected or am I use the API wrong?
Cheers,
Nick
-
Hi and welcome to devnet,
Why are you using the parent of your widget ?
Why a static cast on it ? -
Hey guys,
This is a cross-post from SO with no answers:
I'm new to QT and I'm having issues when calling
QFileDialogfrom a child window. My app is relatively simple. I have one prompt widget that gets user input and then runs show on its parent. This is my main:int main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidjet w(nullptr); ChildWidget input(&w); input.show(); return a.exec(); }This is the relevant section of the child widget:
ChildWidget::ChildWidget(QWidget *parent) : QDialog(parent), ui(new Ui::InputPrompt){ ui->setupUi(this); this->setParent(parent); } ... void ChildWidget::on_imagesSelect_clicked() { inputFilepath = QFileDialog::getExistingDirectory(static_cast<ParentWidget *>(this->parent()), QCoreApplication::translate("main", "Open directory"), "./", QFileDialog::ShowDirsOnly); ui->inputPath->setPlainText(inputFilepath); std::cout << "y u exit" << std::endl; } //Setup and show the parent void ChildWidget::on_buttonBox_accepted() { static_cast<ParentWidjet *>(this->parent())->setup(inputFilepath, outputFilepath); static_cast<ParentWidjet *>(this->parent())->show(); }For some reason when
QFileDialogis called, closing it with either OK or Cancel closes both the parent and the child. If I don't use it, but click the OK button of the child, which calls theon_buttonBox_accepted()function, the child closes and the parent widget appears as expected. If I don't pass the parent widget to the child widget in the main,QFileDialogno longer closes the child widget when running. I tried changing the parent ofQFileDialogtothisor tonullptrbut that didn't help.Any ideas? Is this expected or am I use the API wrong?
Cheers,
Nick
When all windows are closed, by default your application is going to quit as well. This is controllable through a property in
QGuiApplication. -
When all windows are closed, by default your application is going to quit as well. This is controllable through a property in
QGuiApplication.Thank you for the replies!
@SGaist said in QFileDialog from child window closes the application:
Hi and welcome to devnet,
Why are you using the parent of your widget ?
Why a static cast on it ?I just played around with it, trying to make it work. Using
thishas the same behaviour. The static cast was necessary because the parent is a superclass of QWidget... I think. There was a compiler error without it.@kshegunov said in QFileDialog from child window closes the application:
When all windows are closed, by default your application is going to quit as well. This is controllable through a property in
QGuiApplication.When the file Dialog window appears, there is still a window open in the background which is my widget. It is not by any means the last window closed... Or it shouldn't it be. I will try the property later when I have access to a computer.
My point is that if the child widget does not receive a pointer to the parent in the constructor, the file dialog does not close it.
I'll give an update in a few hours.
Cheers,
Nick
-
Hi
I was wondering, since ChildWidget is a QDialog, why dont you use its blocking feature ?
likeint main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidget w(nullptr); ChildWidget input; if ( input.exec() == QDialog::accepted) // exec() blocks execution until ok/cancel. unlike show() { w.setup(input.inputFilepath, input.outputFilepath); // assuming these are public w.show() } else { // user closed or pressed cancelled ... what u want to do.. } return a.exec(); } -
Hi
I was wondering, since ChildWidget is a QDialog, why dont you use its blocking feature ?
likeint main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidget w(nullptr); ChildWidget input; if ( input.exec() == QDialog::accepted) // exec() blocks execution until ok/cancel. unlike show() { w.setup(input.inputFilepath, input.outputFilepath); // assuming these are public w.show() } else { // user closed or pressed cancelled ... what u want to do.. } return a.exec(); }@mrjj said in QFileDialog from child window closes the application:
Hi
I was wondering, since ChildWidget is a QDialog, why dont you use its blocking feature ?
likeint main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidget w(nullptr); ChildWidget input; if ( input.exec() == QDialog::accepted) // exec() blocks execution until ok/cancel. unlike show() { w.setup(input.inputFilepath, input.outputFilepath); // assuming these are public w.show() } else { // user closed or pressed cancelled ... what u want to do.. } return a.exec(); }This worked like a charm, thank you! Could you tell me why the previous solution I had was closing all the windows as soon as the file dialog closed? Is it undefined behaviour or..?
Cheers,
Nick -
@mrjj said in QFileDialog from child window closes the application:
Hi
I was wondering, since ChildWidget is a QDialog, why dont you use its blocking feature ?
likeint main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidget w(nullptr); ChildWidget input; if ( input.exec() == QDialog::accepted) // exec() blocks execution until ok/cancel. unlike show() { w.setup(input.inputFilepath, input.outputFilepath); // assuming these are public w.show() } else { // user closed or pressed cancelled ... what u want to do.. } return a.exec(); }This worked like a charm, thank you! Could you tell me why the previous solution I had was closing all the windows as soon as the file dialog closed? Is it undefined behaviour or..?
Cheers,
Nick@XapaJIaMnu
Hi
Nope, the other solution was not that kinky.
Normally FileDialog::getExistingDirectory will not just close other widgets.
so my best bet is what @kshegunov wrote about.
The quitOnLastWindowClosed property that is default true.
You can test this if you still have old code.int main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidjet w(nullptr); ChildWidget input(&w); input.show(); return a.exec(); int me=100; // place break point here }and try code. if it stops there as soon as you press Ok, it was the reason.
One note about the casting:
static_cast<ParentWidjet *>(this->parent())->setup(inputFilepath, outputFilepath);
static_cast<ParentWidjet *>(this->parent())->show();
this is pretty unsafe as static_cast does not check if its ok to do so
so with QWidgets we have a better cast qobject_cast
and a better version would be likevoid ChildWidget::on_buttonBox_accepted() { ParentWidjet * myparent=qobject_cast<ParentWidjet *> ( parent() ); if (myparent) // always check if not null { myparent->setup(inputFilepath, outputFilepath); myparent->show(); } }This applies to any case where you give it a custom QWidget and reading it back as a base pointer
(QWidget *).
Then you can safely cast and check this way.
in short, no static_cast on QWidgets/QObjects :) -
@XapaJIaMnu
Hi
Nope, the other solution was not that kinky.
Normally FileDialog::getExistingDirectory will not just close other widgets.
so my best bet is what @kshegunov wrote about.
The quitOnLastWindowClosed property that is default true.
You can test this if you still have old code.int main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidjet w(nullptr); ChildWidget input(&w); input.show(); return a.exec(); int me=100; // place break point here }and try code. if it stops there as soon as you press Ok, it was the reason.
One note about the casting:
static_cast<ParentWidjet *>(this->parent())->setup(inputFilepath, outputFilepath);
static_cast<ParentWidjet *>(this->parent())->show();
this is pretty unsafe as static_cast does not check if its ok to do so
so with QWidgets we have a better cast qobject_cast
and a better version would be likevoid ChildWidget::on_buttonBox_accepted() { ParentWidjet * myparent=qobject_cast<ParentWidjet *> ( parent() ); if (myparent) // always check if not null { myparent->setup(inputFilepath, outputFilepath); myparent->show(); } }This applies to any case where you give it a custom QWidget and reading it back as a base pointer
(QWidget *).
Then you can safely cast and check this way.
in short, no static_cast on QWidgets/QObjects :)@mrjj said in QFileDialog from child window closes the application:
@XapaJIaMnu
Hi
Nope, the other solution was not that kinky.
Normally FileDialog::getExistingDirectory will not just close other widgets.
so my best bet is what @kshegunov wrote about.
The quitOnLastWindowClosed property that is default true.
You can test this if you still have old code.Yeah, you are right @kshegunov tweaking that property also fixes the issue. However I don't understand how it was triggered since the documentation says.
If this property is true, the applications quits when the last visible primary window (i.e. window with no parent) is closed.
However my dialog window clearly has a parent. Anyways, problem solved
One note about the casting:
static_cast<ParentWidjet *>(this->parent())->setup(inputFilepath, outputFilepath);
static_cast<ParentWidjet *>(this->parent())->show();
this is pretty unsafe as static_cast does not check if its ok to do so
so with QWidgets we have a better cast qobject_cast
and a better version would be likevoid ChildWidget::on_buttonBox_accepted() { ParentWidjet * myparent=qobject_cast<ParentWidjet *> ( parent() ); if (myparent) // always check if not null { myparent->setup(inputFilepath, outputFilepath); myparent->show(); } }This applies to any case where you give it a custom QWidget and reading it back as a base pointer
(QWidget *).
Then you can safely cast and check this way.
in short, no static_cast on QWidgets/QObjects :)I was under the impression that if the programmer is certain about the type, they should use
static_castfor performance reasons, as opposed todynamic_castorqobject_cast, which are much safer. I got rid of all my casting shizz anyways since i no longer need it.Thank you all for the help and the explanations!
Cheers,
Nick
-
Thank you for the replies!
@SGaist said in QFileDialog from child window closes the application:
Hi and welcome to devnet,
Why are you using the parent of your widget ?
Why a static cast on it ?I just played around with it, trying to make it work. Using
thishas the same behaviour. The static cast was necessary because the parent is a superclass of QWidget... I think. There was a compiler error without it.@kshegunov said in QFileDialog from child window closes the application:
When all windows are closed, by default your application is going to quit as well. This is controllable through a property in
QGuiApplication.When the file Dialog window appears, there is still a window open in the background which is my widget. It is not by any means the last window closed... Or it shouldn't it be. I will try the property later when I have access to a computer.
My point is that if the child widget does not receive a pointer to the parent in the constructor, the file dialog does not close it.
I'll give an update in a few hours.
Cheers,
Nick
@XapaJIaMnu said in QFileDialog from child window closes the application:
The static cast was necessary because the parent is a superclass of QWidget
This is not possible. Your parent class can't be a superclass/baseclass of QWidget, it is for sure other way around.
So this cast is not needed:inputFilepath = QFileDialog::getExistingDirectory(static_cast<ParentWidget *>(this->parent()), QCoreApplication::translate("main", "Open directory"), "./", QFileDialog::ShowDirsOnly);I find the way you're doing it wrong: the child should NOT call show on the parent. Instead, it should emit a signal when it's done. Before calling show on child you connect this signal to a slot in your parent. In this slot you call show() then. Reason: child should not define the behaviour of the parent directly (decoupling).
-
@XapaJIaMnu said in QFileDialog from child window closes the application:
The static cast was necessary because the parent is a superclass of QWidget
This is not possible. Your parent class can't be a superclass/baseclass of QWidget, it is for sure other way around.
So this cast is not needed:inputFilepath = QFileDialog::getExistingDirectory(static_cast<ParentWidget *>(this->parent()), QCoreApplication::translate("main", "Open directory"), "./", QFileDialog::ShowDirsOnly);I find the way you're doing it wrong: the child should NOT call show on the parent. Instead, it should emit a signal when it's done. Before calling show on child you connect this signal to a slot in your parent. In this slot you call show() then. Reason: child should not define the behaviour of the parent directly (decoupling).
@jsulm said in QFileDialog from child window closes the application:
@XapaJIaMnu said in QFileDialog from child window closes the application:
The static cast was necessary because the parent is a superclass of QWidget
This is not possible. Your parent class can't be a superclass/baseclass of QWidget, it is for sure other way around.
Yes, my bad, it's a subclass.
So this cast is not needed:
inputFilepath = QFileDialog::getExistingDirectory(static_cast<ParentWidget *>(this->parent()), QCoreApplication::translate("main", "Open directory"), "./", QFileDialog::ShowDirsOnly);I find the way you're doing it wrong: the child should NOT call show on the parent. Instead, it should emit a signal when it's done. Before calling show on child you connect this signal to a slot in your parent. In this slot you call show() then. Reason: child should not define the behaviour of the parent directly (decoupling).
I have gone with the answer suggested by @mrjj . I don't quite understand what you mean by connecting the signal. Could you illustrate with some code?
Cheers,
Nick
-
@jsulm said in QFileDialog from child window closes the application:
@XapaJIaMnu said in QFileDialog from child window closes the application:
The static cast was necessary because the parent is a superclass of QWidget
This is not possible. Your parent class can't be a superclass/baseclass of QWidget, it is for sure other way around.
Yes, my bad, it's a subclass.
So this cast is not needed:
inputFilepath = QFileDialog::getExistingDirectory(static_cast<ParentWidget *>(this->parent()), QCoreApplication::translate("main", "Open directory"), "./", QFileDialog::ShowDirsOnly);I find the way you're doing it wrong: the child should NOT call show on the parent. Instead, it should emit a signal when it's done. Before calling show on child you connect this signal to a slot in your parent. In this slot you call show() then. Reason: child should not define the behaviour of the parent directly (decoupling).
I have gone with the answer suggested by @mrjj . I don't quite understand what you mean by connecting the signal. Could you illustrate with some code?
Cheers,
Nick
@XapaJIaMnu You define a signal in the child. You define a slot in the parent. You connect the signal to the slot:
int main(int argc, char *argv[]) { QApplication a(argc, argv); ParentWidjet w(nullptr); ChildWidget input(&w); connect(&input, &ChildWidget::someSignal, &w, &ParentWidjet::someSlot); input.show(); return a.exec(); int me=100; // place break point here return 0; }