QMainWindow doesn't .show() but .showFullScreen() works - c++

I have a desktop application that I'm building which checks a QSetting value and if it isn't set shows one QMainWindow class but if it is, shows a different QMainWindow class. The two classes are literally identical at this point as it's early on and don't really contain anything.
In my main function this is what I've got:
int main (int argc, char *argv[]) {
...
if (userToken == "NO_USER") {
LoginWindow w;
w.show();
} else {
MainWindow w;
w.show();
}
return a.exec();
}
The only difference in this between the default project set up from when I created the project is the addition of the conditional window load. Both MainWindow and LoginWindow don't have anything loading other than the ui file associated with them, they're functionally the same.
The weirdness is if I do w.showFullScreen() for the LoginWindow it will show up and take up the whole screen, if I do w.show() nothing at all happens, no compiler warnings|errors, application runs fine, just no window displays.
If I remove the conditional statements and LoginWindow references, MainWindow shows up fine.
Any idea why a call to .showFullScreen() would work but a call to .show() on the same class wouldn't?

I am not sure if this solves you problem, but there definitely is a bug in your code. You are instanciating the window objects on the stack inside a a tight scope, and as you know those objects will be destructed as soon as they go out of that scope. What you are doing is letting them go out of scope before the application is ever started.
Please try this instead:
int main (int argc, char *argv[]) {
...
if (userToken == "NO_USER") {
LoginWindow w;
w.show();
return a.exec();
} else {
MainWindow w;
w.show();
return a.exec();
}
}

Related

How can I call a member function of an object in main.cpp from a Qt button?

I am using Qt and have a start/stop button on the GUI. When the application opens, I call some code like this in my main.cpp file:
QApplication a(argc, argv);
MainWindow w;
w.show();
Something something;
something.start();
In the mainwindow.cpp file that was created by Qt, I have this function that is called when the stop button is pressed:
void MainWindow::on_pushButton_2_released()
{
std::cout << "stopped" << std::endl;
}
How can I call something.stop() from void MainWindow::on_pushButton_2_released()? Or how can I restructure my code so that I can access that class instance?
There are many approaches to this problem, and it depends on what exactly the structure of this program should look like. One simple way would be to add a constructor to the MainWindow class that takes a pointer to something and stores that pointer as a member, i.e.
class MainWindow : public QMainWindow
{
public:
...
MainWindow(Something* something) : something_ptr(something)
{
...
}
...
private:
Something* something_ptr;
...
void MainWindow::on_pushButton_2_released()
{
something_ptr->stop();
}
}
then from your main function:
QApplication a(argc, argv);
Something something;
MainWindow w(&something);
something.start();
w.show();
Since you probably call a.exec() after this, something will exist until the application exits (since exec() is a blocking call).

Qt - Non Modal Dialog before Main Window is created

I've been struggling to do this : I want to show on a window a QWidget, or a QDialog before the MainWindow is created, but I cannot use exec() because it will enter its loop and won't create my MainWindow before I accept or reject the dialog.
The reason I want to do this is to have a widget showing information while the MainWindow constructs itself. I don't want to keep this extra window once the MainWindow is showing up.
I believe the issue comes from the fact that the main window is already created when a.exec() is called and the window won't show up before a.exec(). The solution I found is to use a QDialog instead and call exec() but it blocks the rest of the code which I don't want to happen.
Code :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start; //this is my custom QDialog, can be a QWidget if necessary.
qDebug() << "starting up!";
MainWindow w;
start.exec(); //I tried show() but it won't show up.
w.startApp(&start); //this function will do some stuff.
w.show();
//I don't want start to stay after mainwindow shows up
return a.exec();
}
Here is what I tried so far :
I tried to create and show the StartUpDialog while constructing the MainWindow but it won't work out.
Use start.show(), but it won't show before the mainwindow does, both for a QWidget and a QDialog.
Use start.exec(), this does what I want but it's modal and I couldn't make it non-modal with SetModal(false) or setWindowModality(Qt:NonModal).
I also tried to use start.exec() and attempted to reimplement accepted() and exec() so that it automatically calls accepted() as soon as it appears but it will still close the window.
Hopefully you can help me in that issue, and thanks for reading !
UPDATE : Solved thanks to Trap, here is how I made it :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start;
QSplashScreen *splash = new QSplashScreen();
StartUpWidget *start = new StartUpWidget(splash);
splash->resize(350,380);
start->show();
splash->raise();
splash->show();
qDebug() << "starting up!";
MainWindow w;
w.startApp(start);
w.show();
splash->finish(&w);
start->deleteLater();
splash->deleteLater();
return a.exec();
}
My only concern is that I use a Gif inside my widget using QMovie and updating it has to be done manually apparently.
If I understand your problem correctly (showing a dialog until your main window is created), you should have a look at the QSplashScreen class : http://doc.qt.io/qt-5/qsplashscreen.html

Qt GUI Easiest way to access MainWindow from another class

I am doing a blackjack program and I am keeping track of the cards in the players hand in another class ("hand.h") than the main window class.
In the hand class, for every card that I collect, I am also creating a QLabel that grabs the proper card image for the card and also sets the coordinates for where the card should appear on the main window.
The problem is that I am not able to create the QLabel based on the MainWindows object that is originally created at the main function. Is there any easy way that I am able to get that information fairly easily? Thanks for your help!
I have tried using QGuiApplication::topLevelWindows(), but haven't came to luck with using that. Here is my function that I am using.
#include <QRect>
#include <QApplication>
#include <iostream>
#include <QLabel>
#include "mainwindow.h"
#include <QMainWindow>
#include <QWindowList>
#include <QWidgetList>
#include "ui_mainwindow.h"
void Test() {
QList<QWindow*> Main_Window = QGuiApplication::topLevelWindows();
for (int i = 0; i < Main_Window.size(); ++i) {
if(Main_Window.objectName() == "mainWindow") // name is OK
break;
}
QMainWindow* mainWindow = static_cast<QMainWindow*>(Main_Window);
QLabel* temp;
temp = new QLabel(Main_Window);
temp->setPixmap(QString("Ten of Clubs.png"));
temp->setGeometry(290, 300, 350, 390);
temp->show();
}
Here is the main.cpp file that creates the mainwindow
int main(int argc, char *argv[])
{
srand(time(NULL));
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I found the iterating code online and have been having issues from it.
I am having issues while trying to iterate through the list, but I have no idea how to identify the list and the error says that there is no objectName() function. Also, in the static cast line, there is an error that says that I cannot convert an QList to type QMainWindow. Any help would be greatly appreciated.
No way in general, because some applications may have several (toplevel) QMainWindow-s (and their list could change with time). So for that case you'll better pass the pointer to it (the particular QMainWindow you want to deal with) explicitly....
A possible way might be to have your specific subclass of QApplication (which is a singleton class, see QCoreApplication::instance to get its sole instance) and in your application subclass put, as fields, the explicit windows you want to deal with (maybe you even want to add some new signal or slot to your application class).
However, you could use QGuiApplication::topLevelWindows() or QGuiApplication::allWindows() to get the list of all such windows. Notice that a QWindowList is just a QList<QWindow *>. So see QList for how to traverse or iterate on that list.
Once you have found which QMainWindow you want, adding a QLabel into it is usual practice (but again, signals & slots could be helpful).
BTW, each (displayed) widget has its window, see QWidget::window()
About your code:
Your Main_Window is really poorly named (and the name is so confusing that I cannot use that). It is a list not a window. So code first:
QMainWindow* mainWindow = nullptr;
{
QList<QWindow*> topwinlist = QGuiApplication::topLevelWindows();
int nbtopwin = topwinlist.size();
for (int ix=0; ix<nbtopwin; ix++) {
QWindow*curwin = topwinlist.at(ix);
if (curwin->objectName() == "mainWindow")
mainWindow = dynamic_cast<QMainWindow*>(curwin);
}
}
I did not test the above code and I am not sure it is correct or even can compile. But why don't you just have a global pointer to your main window:
MainWindow*mymainwinp = nullptr;
and initialize it appropriately in your main body:
int main(int argc, char *argv[]) {
srand(time(NULL));
QApplication a(argc, argv);
MainWindow w;
mymainwinp = &w;
w.show();
int r = a.exec();
mymainwinp = nullptr;
return r;
}
then use mymainwinp elsewhere (e.g. in your Test)? If you want more elegant code, define your own subclass of QApplication and have mymainwinp be a field in it.

Qt: How to open a new main window on push button click and delete original main window?

I have files main.cpp, MainWindow.h and MainWindow.cpp. I have a push button on this original main window. What I want is when I click on the button, it should take me to a new main window and delete the original main window.
Also I want to follow good programming practices. So I am wondering that should new source and header files like SecondWindow.cpp/.h be created or all this be done in MainWindow.cpp where I have definition of the SLOT on_button_clicked()?
You need to:
Instantiate the new window and show it.
Delete the current window once the control returns to the event loop.
void MainWindow::on_button_clicked() {
auto win = new MainWindow();
win->setAttribute( Qt::WA_DeleteOnClose );
win->show();
deleteLater();
}
Make sure that the initial instance of the window is created on the heap:
int main(int argc, char** argv) {
QApplication app(argc, argv);
auto win = new MainWindow;
win->setAttribute( Qt::WA_DeleteOnClose );
win->show();
return app.exec();
}
The answer given by Kuba Ober works.However, you can have only 2 main windows at all times no matter how many times you press the button. It seems to crash the program after the second time you run it.
I believe my solution would be better since you can open as many main windows.
At your MainWindow Header:
private:
Ui::MainWindow *ui;
MainWindow *nWin; //Add This bit of code here
As for your triggered event function:
void MainWindow::on_actionNew_triggered()
{
nWin = new MainWindow;
nWin->show();
}
That should do it.
Thanks.

How to do things upon quitting a Qt app

To my understanding, the following will execute an application which will exit when all associated windows are closed.
int main(int argc, char *argv[])
{
QApplication cal(argc, argv); //Application instance
MainWindow window; //Create window in the stack
window.show(); //Show the window
return cal.exec(); //Execute event loop
}
This will also quit said application.
quitButton = new QPushButton("Quit", this);
connect(quitButton, SIGNAL(clicked()), QApplication::instance(), SLOT(quit()));
How should I go about cleaning up (closing hardware connections and libraries etc.) so that I can be sure everything that needs to happen happens no matter how the app it exited, nor at what point in execution it is exited?
I will have a library open throughout the whole app, and a connection to a USB device at most times. I am able to close this connection easily if the process runs its course, but I want the connection to be closed safely if somebody decides to hit quit or close all the windows before it is done.
There is a virtual function called closeEvent for a QWidget (see Documentation, which is called when the widgets close() operation is called.
Alternatively, if you don't want to have your own Base widget, you can hook yourself to the signal QApplication::lastWindowClosed (see here). It is emitted when the last visible window of your application closes.
You can do the following:
int main(int argc, char *argv[])
{
QApplication cal(argc, argv);
// Allocate resources
int ret = cal.exec(); // start the event loop and wait until it quits
// Free the resources
return ret;
}
The proper C++ way of doing it is:
Ensuring that all of your object instances get destructed.
Ensuring that any resources you hold are held via RAII.
Then you don't need to do anything special. As the objects get destructed when main returns, things get cleaned up.
For example:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
QObject foo;
QObject * bar = new QObject(&app);
Widget w;
w.show();
return app.exec();
}
Here, both foo and bar are properly destructed before main returns. Now suppose you hold some non-memory resources, like a file:
class Worker : public QObject {
QFile m_file;
...
void doSomething() {
if (m_file.open()) {
...
}
// No file closing!
}
};
int main(int argc, char ** argv) {
QApplication app(argc, argv);
Worker foo;
Widget w;
w.show();
return app.exec();
}
Again, the file gets closed before main returns.
That's how RAII works, in a nutshell. If you have your own classes that wrap OS or other resources, simply ensure that such resources are freed when the classes get destructed - and that the classes are always destructible (it's always safe to destruct them). My pet peeve is QThread - it breaks this expectation, and you have to implement a wrapper to fix it.
For resources that you need to allocate on the heap, you're supposed to be using smart pointers or QObject memory management.
There is a QApplication signal that you can use for cleaning up before the application quits:
QObject::connect(&app, SIGNAL(aboutToQuit()), &MyCleaner, SLOT(cleanUp()));
Have fun!