QMainWindow wont open in conditional block - c++

Before opening a QMainWindow a login occurs, and there are 3 possible results, an error, a teacher and a user, if the login result is a user must open a QMainWindow pro user, if he is a teacher his QMainWindow.
LoginDialog login;
login.exec();
switch(login.result()){
case LoginResult::NONE:
qDebug() << "None";
break;
case LoginResult::PROF:
qDebug() << "Prof";
break;
case LoginResult::USER:
{
MainWindow w;
w.show();
}
break;
case LoginResult::ERROR:
Database::Terminate();
return -1;
}
The problem is that inside the case the window only opens for less than a second and automatically closes, outside the switch, the window shows and stays as it should.
Why does this occur?

The main window object goes out of scope at the end of the block, and is destroyed. You need to create it with new to prevent this:
case LoginResult::USER:
{
auto *w = new MainWindow;
w->setAttribute(Qt::WA_DeleteOnClose); // to prevent memory leak
w->show();
}
Above pointer variable w goes out of scope, but since it is plain raw pointer, this doesn't delete the actual object. Setting the object to delete itself when it is closed is a QWidget feature, and is one way to make sure the main window gets cleanly deleted. Not sure if it is a good way for your application, but you can start with it, and then do something else later if needed.

Related

How to have a timer in main.cpp in qt creator to update the GUI when a button is clicked?

I am creating a laundry machine simulation with my team for school. I have simulation.cpp where I have functions to control the GUI and main.cpp where I only call one Work() function which is supposed to check whether the user has clicked on a button (e.g. adding coins). There are many classes and interfaces in between these two which handles the application logic which do not matter for the simulation part.
My problem is that I want to be able to check a checkbox when a button is clicked. However, in main.cpp I cannot do anything after return a.exec(). I also cannot do anything before that since this is what pops up the GUI.
So I want to use a timer with 1 sec interval, which when ticks calls the Work() function. I created this timer in simulation.cpp which works but I could not create it in main.cpp.
My simulation.cpp looks like this:
bool button10 = false;
Simulation::Simulation(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::Simulation)
{
ui->setupUi(this);
timer = new QTimer(this); // create it
connect(timer, &QTimer::timeout, this, &Simulation::TimerSlot ); // connect it
timer->start(1000);
}
void Simulation::TimerSlot()
{
SetCoin_10(coin10);
coin10++;
}
void Simulation::SetCoin_10(uint8_t nrOfCoins){
if(nrOfCoins == 1){
ui->checkBox_17->setChecked(1);
}
else if(nrOfCoins ==2){
ui->checkBox_16->setChecked(1);
}
else if(nrOfCoins ==3){
ui->checkBox_15->setChecked(1);
}
}
uint8_t Simulation::GetBtn_10(){
if(button10){
button10 = false;
return true;
}
else{
return false;
}
}
and main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
simulation = new Simulation();
cs = new Coins(simulation);
ps = new ProgramSelector(simulation);
sp = new Soap(simulation);
dr = new Director(cs, ps, sp);
simulation->show();
dr->Work(); //this is what I want to execute every second (from director class)
return a.exec();
}
How do I make this happen? Thanks a lot in advance!
You can "connect" to Events. Qt will enter the event loop on exec() and call the connected functions when events occur.
You already did that on your timer. You just call the TimerSlot() whenever the timer fires.
Your problem is just the accessibility of your variables. Right now, you cannot access "dr" to call "dr->Work()" from within the simulation class.
Option1:
Pass the objects like "dr" and "cs" to the Simulation, either in Constructor like new Simulation(dr, cs...) or by adding setter function that you then call like simulation.setCoins(cs)
Option2:
Create the objects like "dr" and "cs" in the Simulation. Probably best in constructor.
Hint: For both options, you should probably create member variables like this:
private Coins coins;
This will not require new keyword, because it's created on the stack instead of the heap. This also means, you don't need to delete the coins object in destructor. As you don't get a pointer then, you access functions using . instead of ->.

delete qtabwidget

my program keeps crashing with returncode 0.
The cause is somewhere in my qtabwidget but I can't find the error.
QTabWidget *layout_tabs;
// create tabs
void myclass::fill_tabs(void)
{
kill_tabs(); // remove old tabs
layout_tabs = new QTabWidget();
// program adds content into a few tabs, like:
// widgets created, content created, put into layout, put into widget..
layout_tabs->addTab(widget, "description");
layout_tabs->addTab(widget2, "description2");
layout_tabs->show();
}
void myclass::kill_tabs(void)
{
if(layout_tabs==nullptr)
return;
layout_tabs->hide();
QWidget *window;
for ( int i=layout_tabs->count()-1; i>=0; --i)
{
window = layout_tabs->widget(i); // remember widget
layout_tabs->removeTab(i); // remove tab
free(window); // remove widget
}
free(layout_tabs); // remove qtabwidget
layout_tabs=nullptr;
}
the filltabs() function is used a few times. The old tabwidget is destroyed and a new is created.
It does not matter if I don't delete the tabwidget, but remove only the tabs. The program still exits with returncode 0.
You call free(layout_tabs) but you allocate it with operator new(). You should deallocate it with delete layout_tabs instead. I don't see how your window variable is allocated but you should check if it too should be deallocated with operator delete(), or if your QTabWidget owns its memory (i.e. if it is responsible for managing that memory).
Set the QApplication::quitOnLastWindowClosed to false.
#include <QApplication>
// ...
qApp->setQuitOnLastWindowClosed (false);
Or you can go and set the container for your tabs (the main window/ main widget) to have the property of Qt::WA_QuitOnClose set to false.
myWidget->setAttribute(Qt::WA_QuitOnClose, false);
Either of those should fix it. Also returning with "0" is not a crash. Zero typically indicates a normal exit.
http://qt-project.org/doc/qt-4.8/qapplication.html#quitOnLastWindowClosed-prop
http://qt-project.org/doc/qt-4.8/qt.html#WidgetAttribute-enum

QT quit does not call MainWindow destructor

In my application I have a tray icon and so I overrode closeEvent so that the application "minimizes" when certain things happen. However, I do expect that upon pressing exit, that the application will completely exit. However, after overriding closeEvent and calling the function quit(), it seems to bypass the MainWindow destructor, where I have some code.
What am I missing in closeEvent to properly close the application so that the destructor of MainWindow is called, as is the case when closeEvent isn't overriden?
I've tried using
QMainWindow::closeEvent(event);
and a few other things, but the destructor is never called.
My close event implementation is:
void MainWindow::closeEvent(QCloseEvent * event)
{
if(m_closeCompletely == false)
{
if (trayIcon->isVisible())
{
QMessageBox::information(this, tr("Hello"),
tr("The program will keep running in the "
"system tray. To terminate the program, "
"choose <b>Quit</b> in the context menu "
"of the system tray entry."));
}
}
else
{
event->accept();
}
}
The WA_DeleteOnClose attribute needs to be set to call the destructor on a close event, otherwise a widget or window is just hidden from view. Add the following to the class constructor:
this->setAttribute(Qt::WA_DeleteOnClose);
This will cause the destructor to be called on a close event.
It all depends on where and how you allocated the objects you are using. If you create the QApplication and QMainWindow on the heap then they will lurk around until the OS cleans up the memory. Sending a close() to a QWidget (and QMainWindow is one) will only close it .. hide it visually from the user. You can show() later on, close() does not destruct it.
You could use something like this:
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
MyMainWindow mw;
mw.show();
int rc = app.exec();
// optional: do_cleanup();
return rc;
}
app and mw are constructed on the stack. They will be destructed in reverse order when the app returns from the exec() call (usually when you send quit() to the QCoreApplication::instance()). You can even provide a plain cleanup function, no need to put something into the destructor of the UI.
Remember that all the Application Resources are hold by the QApplication;
Once your MainWindow is closed, it just be close, aka hide from the screen;
I wonder why you want to destructor your MainWindow, it seems that you've made a system tray entry, so my suggestion is just to hide the MainWindow but to destructor, cause there is a system tray, you may want to click it to show the MainWindow.
Hope to Help. : )
I just ran into this same problem and it was because I was running an infinite loop that never allowed the application to close.
forever
{
_runGameLoop();
}
I had to make the loop end when MainWindow closed
while(!M->isClosed())
{
_runGameLoop();
}
And of course I had to implement isClosed()
bool MainWindow::isClosed()
{
return _isClosed;
}
void MainWindow::closeEvent(QCloseEvent*)
{
_isClosed = true;
}

How do I share objects between a closed QDialog and newly opened QMainWindow?

I have an application that opens a QDialog for some flow, and when it is closed, the QMainWindow is opened.
In the QDialog I create some objects that I'd like to pass as a pointer (or some other way) to the QMainWindow. For example I create a SysTray object that needs to change its state from the QMainWindow. What is the best way? Singletons?
update .
after implementing the sulotion another question was rises , does the QDialog is cleaned from memory that means , invoked its destructor ? i don't think its the case . i have to do some object cleaning , and there destructor never invoked
One approach is to allocate on the heap with the QMainWindow as a parent. The QObject-hierarchy will take care of freeing the memory and you will access the object for the lifetime of the QMainWindow.
If at any point you know for sure that you don't need the QDialog or the shared object anymore, you can call deleteLater.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QObject* _objToShare;
public:
QObject* objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = new QObject(this); // either use this as the parent
// or free by hand in the destructor
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QObject* ptrToSharedObj; // alternatively you can hold a pointer
// to your MyDialog instance
};
Where you use your QDialog:
MyDialog* d = new MyDialog(this);
d->exec();
ptrToSharedObj = d->objToShare();
// don't delete d explicitly, the QObject hierarchy will take care of that
A better (and likely more memory-friendly) approach is to use a shared pointer implementation. Qt has a variety of smart pointer classes, one of which is QSharedPointer. It is basically a thread-safe, reference-counted pointer which means that if you grab one that points to the shared object of your QDialog, it will not get freed as long as there are any other QSharedPointers pointing to it. Keep in mind that this might cause circular references if you are not careful.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QSharedPointer<QObject> _objToShare;
// ^ don't delete in the destructor
public:
QSharedPointer<QObject> objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = QSharedPointer<QObject>(new QObject);
// no parent to avoid destruction when the dialog is destructed
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QSharedPointer<QObject> ptrToSharedObj;
};
Where you use your QDialog:
MyDialog d;
d.exec();
ptrToSharedObj = d.objToShare();
From this point on, even if d goes out of scope (i.e. destroyed), you will still have a valid pointer to the shared data (well, of course unless you do something explicitly to invalidate it).
You have a lot of different options. Some of these may not be applicable to your situation:
Case 1: Caller knows best (i.e. procedural programming)
Define a controller that can control the ordering. That control can then act as the intermediary and get the data once the dialog has closed:
void FlowController::displayFlow()
{
MyDialog *dialog = new MyDialog();
YourSharedData *data = NULL;
int result = dialog->exec();
if (result == QDialog::Accepted) {
data = dialog->sharedDataAccessor();
}
MyMainWindow *window = new MyMainWindow();
window->setSharedData(data);
window->exec();
}
Case 2: Message Passing
Create both the dialog and the main window up front. Connect the corresponding signals and slots and let them both be ignorant of one another. This is usually much easier to test and keep decoupled:
void AppLauncher::launch()
{
MyDialog *dialog = new MyDialog();
MyMainWindow *window = new MyMainWindow();
window->connect(
dialog,
SIGNAL(dialogResult(int, const SharedData&)),
SLOT(setDialogResult(int,const SharedData&))
);
}
void MyMainWindow::setDialogResult(int result, const SharedData& sharedData)
{
if (result == Dialog::Accepted) // something domain-specific would be better
{
this->processSharedData(sharedData); // do whatever with it.
}
}
Case 3: Shared State Dependency
Define your shared data up front and make it a dependency for each form. Each form then defines state, acts based on that state, or some combination of both:
void AppLauncher::launch()
{
SharedData *data = this->createSharedData();
MyDialog *dialog = new MyDialog(data);
MyMainWindow *window = new MyMainWindow();
dialog->exec(); // does what it needs with shared data
window->exec(); // checks shared data and acts accordingly
}
Case 4: MVC / MVP / MVVM
You may be able to define your shared state as a model that they both act upon. This may not be much different than case three above.
Case 4: Singleton or global state
It will work, but please don't do it :).
In QDialog you have owner, which is probably QMainWindow. (if not, you may add it there, ore get parent objects until you come to QMainWindow class). You may refer to it when creating new objects...
You can subclass QApplication to have it keep a pointer to your systray object, or other objects which should be available "application wide".
In a Qt application, there is only a single instance of QApplication, available everywhere using the qApp macro.
See this mailing list discussion which also contains an example.

Closing a QMainWindow on startup?

I have a Qt application that uses a QMainWindow-derived class for the main UI. On startup I want to make some security checks and, if they fail, display a message to the user and close the main window. Currently I make these checks in the QMainWindow constructor, but if I call the close method, nothing happens and the application continues to run. For example:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setupUi(this);
...
if (checkFails())
{
QMessageBox::warning(this, tr("Error"), tr("You cannot run this app"));
// This has no effect
close();
}
}
Alternatively I could make the checks in the main function but then I lose the ability to display a language-specific message box (the tr macro only works in a QObject-derived class by the looks of things.)
Any ideas on how to close the main window on startup or make the tr macro work outside of a QObject derived class?
The event loop needs to be running before you can successfully close the main window. Since you probably first construct a window, and then start the event loop the close() call has no effect. Try the following solution instead:
QTimer::singleShot(0, this, SLOT(close()));
The QTimer::singleShot() will fire as soon as an event loop has been started, and subsequently calls the close() method on your application main window.
The above solution will probably cause your main application window to be visible for a short period of time, causing unwanted flickering.
A cleaner solution should perform the security checks prior to constructing the main window. Since tr() is also available as a static method on QObject, this can be done from the main function.
Most applications start up in three steps: 1) construct the window; 2) show the window; 3) start the event loop. You can make steps 2 and 3 conditional on the success of step 1 by adding a flag, whose value is set by the window constructor, to the window class:
Window class:
class myMainWindowClass : public QMainWindow
{
Q_OBJECT
public:
myMainWindowClass()
: isFinished_(false) { if (error) isFinished_ = true; } // constructor
bool isFinished() const { return isFinished_; }
private:
bool isFinished_;
}
Application code:
int main()
{
myMainWindowClass main_window(); // Step 1
// Finish early if isFinished flag is set
if (main_window.isFinished())
return 0;
main_window.show(); // Step 2
return a.exec(); // Step 3
}
This should also avoid any flicker as the application will end before the window is show()n.
tr is a public static member of QObject. You should be able to call QObject::tr("Error") in your main function.
Have you tried first hide()ing the window (this should occur anyway when close() is called) to see if this then allows close() to destroy the window.
If this does not work, you could always try destroy(true, true)ing the window along with any sub-windows.