QDialog closing on it's own, how can i fix it? - c++

My class names is like (what it does)_(type) for example: reg_QDialog
Here is code of an executing dlg and if Accepted creating QMainWindow:
if(log_dlg->exec() == QDialog::Accepted)
{
find_wnd = new find_QMainWindow();
find_wnd->show();
}
log_dlg has 2 btns: "Enter" (here is the accept result) and "Reg" (opens a new dlg)
"Enter" and "Reg" code is here:
void log_QDialog::on_btn_enter_clicked()
{
this->accept();
}
void log_QDialog::on_btn_reg_clicked()
{
reg_QDialog *reg_dlg = new reg_QDialog();
this->hide();
if(reg_wnd->exec() == QDialog::Accepted)
{
//code
}
this->show();
}
So, here is the problem:
Step by step:
1) run the prog //it starts with dlg_log
2) "Reg" //creating dlg_reg
3) accept dlg_reg //returning to dlg_log
4) "Enter" //trying to create QMainWindow
QMainWindow is not created, and the app just closed
After "returning"(it's, actually, just hiding and then showing) from the reg_dlg and pushing btn with accept result it does nothing! It just closes the programm, but it had to show QMainWindow!
All real code of main.cpp:
#include "log_window_root.h"
#include "find_mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
log_window_root * log_wnd;
find_mainwindow * find_wnd;
log_wnd = new log_window_root();
log_wnd->setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
log_wnd->setModal(true);
if(log_wnd->exec() == QDialog::Accepted)
{
find_wnd = new find_mainwindow();
find_wnd->setWindowFlags(Qt::MSWindowsFixedSizeDialogHint);
find_wnd->show();
}
return a.exec();
}

You are a operating a bit beyond the limits of Qt. Looking at the documentation:
Generally, no user interaction can take place before calling exec().
As a special case, modal widgets like QMessageBox can be used before
calling exec(), because modal widgets call exec() to start a local
event loop.
Testing your code on Mac OS will give you the dreaded warning
modalSession has been exited prematurely - check for a reentrant call
to endModalSession
which shows, that you are working on thin ice and your code will break any time.
Consider reworking your code so that the MainWindow comes up and then show your dialogs. If you want to go on with the Dialog sequence, then remove the hide()/show() pair from on_btn_reg_clicked (these calls mess up your event loops).

QApplication exits and close when the last window has been closed.
You can discard this by setting QApplication::quitOnLastWindowClosed property to false.
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
You may want to revert it to it's previous state when your job is done with those dialogs.
As #Jens mentioned in the other answer to your question, this is will break evenloop at some point and QApplication exits before even a.exec() being called. So, you can also create a zero width/height or off-screen QWidget as a parent of your dialogs. A QSplashScreen is also a good candidate for this. All your dialogs should be your splash screen children. At last, you can finish your splash screen by calling QSplashScreen::finish.

[Re-posting from duplicate-closed question since the top banner on it may cause people to skip that question entirely, and IMHO this one doesn't have a good answer.]
Here's a very simple example of showing a dialog before a QMainWindow. The dialog simply presents the option of starting the main app or not. They key points are that the QDialog portion happens before any other widgets are created (eg. QMainWindow here), and the app (main()) exits before that if needed. No reason to keep the QDialog around after it is used, so I create it on the stack and delete afterwards.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog *d = new QDialog();
QPushButton *pbYes = new QPushButton("Would you like to play a game?", d);
QPushButton *pbNo = new QPushButton("Get me out of here!", d);
QObject::connect(pbYes, &QPushButton::clicked, [d]() { d->done(QDialog::Accepted); });
QObject::connect(pbNo, &QPushButton::clicked, [d]() { d->done(QDialog::Rejected); });
d->setLayout(new QVBoxLayout);
d->layout()->addWidget(pbYes);
d->layout()->addWidget(pbNo);
const int ret = d->exec();
delete d;
if (ret == QDialog::Rejected)
return 0;
QMainWindow mw;
mw.setCentralWidget(new QLabel("Welcome to the Game!", &mw));
mw.show();
return a.exec();
}

Related

QT "Tick" widget loop

I'm trying to understand the correct way to update a widget at frame-time.
The specific problem I'm trying to solve is to set the remaining time of a timer on a label.
I created and started the timer
MainTimer = new QTimer(this);
MainTimer->setSingleShot(true);
MainTimer->start(5000);
and on the QML I have a label, UI_MainTimerLabel, that I can access through ui->UI_MainTimerLabel->setNum(int).
Since the QTimer doesn't provide a OnTimerUpdate signal or callback method, I suppose I have to create some kind of loop to read the timer's value and set it to the label.
Should I do it through a QThread?
QThread::create([&]() {
while(true)
{
ui->UI_RemainingTimer->setNum(MainTimer->remainingTime());
}
})->start();
(note: I know that this won't work, but it's not a problem since I'm just trying to understand the concept)
Should I use a 0-timed QTimer?
UpdateTimer = new QTimer(this);
//{binding the UpdateTimer end signal to a ui->UI_RemainingTimer->SetNum(MainTimer->RemainingTimer() function}
UpdateTimer->start(0);
Should I use a QEventLoop (but I have yet to fully understand what is their correct usage)?
Should I use a user-created "MyTimerLabel" widget that self-updates (in which virtual overridden method?)?
Or is there some other correct way to manage a frame-time update, that I couldn't understand? (I'm trying to get the general correct approach, not the solving approach of this specific problem, though)
Thanks in advance
Is it necessary to update the GUI at every moment? No, each frame is updated every 30ms so something appropriate is to update half of that time, that is 15 ms. So the second timer is set to that period by calculating the remaining time showing it in the GUI:
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTimer main_timer;
main_timer.setSingleShot(true);
QTimer update_timer;
QLabel label;
label.setAlignment(Qt::AlignCenter);
label.resize(640, 480);
QObject::connect(&update_timer, &QTimer::timeout, [&main_timer, &update_timer, &label](){
int rem = main_timer.remainingTime();
if(rem <0){
label.setNum(0);
update_timer.stop();
}
else{
label.setNum(rem);
}
});
label.show();
main_timer.start(5000);
update_timer.start(15);
return a.exec();
}

how to restart an application in qt?

I do this works for restarting my game but program has error .I want to show a QDialog when user losses .In this QDilag i put two pushbutton for retry and exit.also i have a QDialog for beginning of game.Where is my mistake? (I read similar questions and do according these but yet i have problem)
extern int const EXIT_CODE_REBOOT;
mydialog_end::mydialog_end(QWidget *parent) :
QDialog(parent
{
retry=new QPushButton(this);
exit=new QPushButton(this);
retry->setText("RETRY");
exit->setText("EXIT");
connect(retry,SIGNAL(clicked()),this,SLOT(on_retry_clicked()));
connect(exit,SIGNAL(clicked()),this,SLOT(on_exit_clicked()));
}
void mydialog_end::on_retry_clicked()
{
qApp->exit(EXIT_CODE_REBOOT);
accept();
}
void mydialog_end::on_exit_clicked()
{
//what do i do for end of game?
reject();
}
//////////////in class myenemy///////
public slots:
void loss();
void Myenemy1::loss()
{
if(this->collidesWithItem(_mario))
{
//do something....
mydialog_end dialog;
dialog.exec();
}
}
//////////////in main////////////
extern int const RESTART_CODE;
int main(int argc, char *argv[])
{
Mydialogstart dlg;//a dialog for beginning game
int state= dlg.exec();
int return_from_event_loop_code=0;
do
{
QApplication a(argc, argv);
MainWindow w;
if( state==QDialog::Accepted)
{
w.show();
qDebug()<<"accepted";
}
else if(state==QDialog::Rejected)
{
qDebug()<<"rejected";
dlg.close();
return 0;
}
return_from_event_loop_code = a.exec();
} while(return_from_event_loop_code==RESTART_CODE);
return return_from_event_loop_code;
}
You can use QProcess::startDetached to run an instance of your application in a new process and detach from it. After that you should exit the application :
QProcess process;
process.startDetached("myApp",QStringList());
qApp->quit();
Here myApp is the name of the executable file of the application. On Windows it can be myApp.exe.
On this one, I would make a little inception... let's say your main application is called A then you should run A in a global B application. When A crashes, B throws the QDialog. If the use click on Retry then kill the old instance of A and start a new one.
There is a Qt Wiki entry that explains what you need to do in quite a lot of detail.
As it seems you have at least partially taken inspiration from there, but from what you post here, you seem to have never initialized the values for EXIT_CODE_REBOOT and RESTART_CODE in your code sample, or at least linked them to one another (which I would expect you'd want to do in some way)

QObject::moveToThread: Widgets cannot be moved to a new thread

My IDE Qt 5.0.1, platform Linux
i have a problem about set widgets to window.(My opinion)
this is my main.cpp->
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread cThread;
MainWindow w;
w.doSetup(cThread);
w.moveToThread(&cThread);
cThread.start();
if(cThread.isRunning())
{
qDebug() << " Thread is Running...";
}
w.show();
return a.exec();
}
this is doSetup() method->
void MainWindow::doSetup(QThread &mainThread)
{
QObject::connect(&mainThread, &QThread::started, this, &MainWindow::activeLoopMainC);
}
i checked my signal-slot mechanism and it works.
slot method->
void MainWindow::activeLoopMainC()
{
qDebug() << " Signal-Slot structure working successfully..";
mainThreadProc((void*)(instAddr));
}
i call a function from my main.c by this slot method.
In debugging there is no problem about working codes. But my window is blank. there is only frame.
i receive an error message: QObject::moveToThread: Widgets cannot be moved to a new thread
How can i solve this problem?
Thank you in advance for your answers.
You can't move widgets into another thread - in order to keep user interface responsive, Qt needs to do all GUI work inside main thread.
If you have background work to do, then move background worker to other thread, and not the user interface.

Qt process stays in memory after application closes

i have simple application that start QDialog from its main like this :
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(resources);
QApplication app(argc, argv);
QCoreApplication::setApplicationName(APP_NAME);
QCoreApplication::setApplicationVersion(APP_VERISON);
QCoreApplication::setOrganizationDomain(APP_DOMAIN);
app.setStyle("WindowsXP");
QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
AuthenticationDialogContainer *pAuthenticationDialogContainer = new AuthenticationDialogContainer();
if(pAuthenticationDialogContainer->exec() != QDialog::Accepted ) {
return 0;
}
return app.exec();
}
when its pass the end of the application that is after app.exec() and the application doing what is suppose to do . when i open the windows xp task manager i see that the process is still in memory and i need manually kill it . how can i prevent it from happening ?
QDialog::exec is a blocking call: this code show and close the dialog before the QApplication start.
You can use QDialog::show and handle the return code in QDialog::accept method.

Constructing / destructing QApplication causes QWebView to mess up rendering of HTML

We need to create & destroy instances of QApplication, as we want to use Qt in a plug-in to an existing host application.
void multiQT()
{
int argc = 0;
QApplication app(argc, NULL);
QWebView view;
view.setHtml("<html><head><title>Title</title></head><body><h1>Hello World</h1></body></html>");
view.show();
app.exec();
}
main(int argc, char** argv)
{
// First call works fine, QWebView renders the HTML just fine
multiQT();
// Second call fails, QWebView strips HTML tags from HTML text and
// and renders "TitleHello World"
multiQT();
}
When showing the QWebView the second time, it does not render the HTML properly. Do we need to do some additional (re-)initializations in QApplication or QWebView?
You might have run into something that has been very lightly tested, the QApplication object among others creates/holds some of the rendering context information of widgets, I don't think it was ever planned for people to take it down and put it back up again. There might be some static content that does not get reinitialised correctly when somebody tries what you are trying to do.
You are supposed to have only 1 QApplication object, and only 1 call to exec(). Maybe you should try this.
QWebView * multiQT()
{
QWebView *view = new QWebView;
view->setHtml("<html><head><title>Title</title></head><body><h1>Hello World</h1></body></html>");
view->show();
return view;
}
main(int argc, char** argv)
{
QApplication app(argc, NULL);
QWebView * web0 = multiQT();
QWebView * web1 = multiQT();
app.exec();
}