While debugging, I came up with strange for me thing. In the main function, I commented out creation of window as follows:
#include <QApplication>
#include <QMetaType>
#include <QDebug>
//#include "mainwindow.h"
int main(int argc, char *argv[])
{
qDebug() << "Creating QApplication";
QApplication a(argc, argv);
qDebug() << "QAplication has been created successfully";
qDebug() << "Creating application window";
// MainWindow w;
qDebug() << "Displaying application window";
// w.show();
qDebug() << "Application window has been displayed successfully";
return a.exec();
}
I thought I am just creating an event loop and lunching it. But output surprised me:
"17:28:32.793" ButtonControl: contructor.
"17:28:32.807" GestureControl: contructor
Creating QApplication
QAplication has been created successfully
Creating application window
Displaying application window
Application window has been displayed successfully
I have ButtonControl and GestureControl classes and first 2 lines of output are from their constructors. I create their objects inside of other class, which I use in MainWindow class. The strange thing for me is they are created before/without MainWindow and event loop. Their messages are printed even if I don't create QApplication object and call its exec() method. I tried cleaning and running qmake, and rebuilding, but no success. What's going on here? What is wrong with ButtonControl and GestureControl classes?
Env: win7, Qt 5.10, MSVC 2015.
Edit
Here is my Control class:
class Control : public QObject
{
Q_OBJECT
public:
explicit Control(QObject *parent = nullptr);
static ButtonControl *getButtonController() {
return &buttonController;
}
static GestureControl *getGestureController() {
return &gestureController;
}
private:
static ButtonControl buttonController;
static GestureControl gestureController;
};
I call this class inside my MainWindow. (As I understand from comments this code snippet is enough)
Following comments, I did a small research and found this answer:
Static members are initialized before main(), and they are destroyed in reverse order of creation after the return in main().
Static members are statically allocated, and their lifetime begins and ends with the program.
Thank you everyone who commented out.
Related
Getting right to it I have a MainWindow and a dialog window which is executed if a condition is met but the problem is I can't get the app to quit if the cancel button from the dialog window is clicked. I've tried putting qApp->quit() in the slot function for the cancel button. I've tried connecting the cancel button slot to the predefined close slot for the MainWindow object via a clickme() signal from the dialog class. (as shown below)
qt application does not quit I read the answer to this question which I think got me close because it made me realize that I can't quit the app before showing the MainWindow but making that change didn't solve the problem. I even tried to explicitly emit the clickme() signal from cancel button slot but that actually caused the OS to throw a signal which threw an error at me saying "the inferior stopped because it received a signal from the operating system signal name: SIGSEGV
signal meaning: segmentation fault"
Here's my code:
Notice warning; // this is the object for the dialog window also all of this code is in main.cpp
warning.setModal(true);
QObject::connect(&warning, SIGNAL(clickme()), &warning, SLOT(on_Cancel_button_clicked()));
QObject::connect(&warning, SIGNAL(clickme()), &w, SLOT(close()));
warning.exec();
Also before that code is
MainWindow w;
w.show();
Also while writing this question I tried this
QObject::connect(&warning, SIGNAL(clickme()), qApp, SLOT(quit()));
But that still didn't work. If you need more info just let me know.
Update: I'm starting to think that the reason I'm having so much trouble with this connect signal/slot function is because it's not designed to connect two windows of two different classes and I should rework my app to do everything from the MainWindow class which is a shame because when I picture a GUI program I picture multiple windows connected to each other regardless of whether or not the object representing each window is from the same class as the others yet I have such a hard time trying do that with the QT framework when it comes to trying to connect objects of different classes.
Update: please forgive me. I assume that the code that I originally thought was the answer would work and took a break from working on the program before actually testing out that code. Going back to it now I discovered that it doesn't work. The code I'm referring to is the following
QMessageBox msg;
msg.setText("Continue?");
msg.addButton(QMessageBox::Yes);
msg.addButton(QMessageBox::No);
QObject::connect(&msg, &QMessageBox::rejected,
&app, &QApplication::quit); // this line doesn't work for me and I don't know why
QObject::connect(&msg, &QMessageBox::accepted, [&dlg]{
(new QLabel("I'm running")).show();
});
QApp->quit(); should work. Remove warning.setModal(true); The dialog becomes modal when you call exec(). SetModal(true) should be used with show() according to Qt docs. So this may be causing your problem.
I think I've found the problem.
Probably, you're calling exec() twice:
To enter the QApplicationevent loop
To execute the dialog.
Use show() instead of exec() for the dialog. You have an example below where you can check the signal/slot works well. In your application, you need the slot to close the window, but:
With the line of code dialog.exec();, the app keeps running. This is your issue.
With the line of code dialog.show();, the app stops.
By the way, I saw your last question update, but it is not correct. In fact, of course you can connect two different classes.
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QApplication>
#include <QMainWindow>
#include <QAbstractButton>
#include <QDebug>
#include "dialog.h"
class Window : public QMainWindow
{
Q_OBJECT
public:
Window()
{
dialog = new Dialog();
dialog->setText("Continue?");
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
auto onClick = [this]() {
auto role = dialog->buttonRole(dialog->clickedButton());
if (role == QMessageBox::NoRole) {
qDebug() << "QMessageBox::NoRole";
QApplication::quit();
}
if (role == QMessageBox::YesRole) {
qDebug() << "QMessageBox::YesRole";
}
};
QObject::connect(dialog, &QMessageBox::buttonClicked, onClick);
dialog->show(); // this must be show(), not exec()
}
virtual ~Window() { delete dialog; }
private:
Dialog *dialog;
public slots:
void windowSlot() { qDebug() << Q_FUNC_INFO;
close();
}
};
#endif // WINDOW_H
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QMessageBox>
class Dialog : public QMessageBox
{
Q_OBJECT
public:
Dialog() {}
virtual ~Dialog() {}
};
#endif // DIALOG_H
main.cpp
#include <QApplication>
#include <QtGui>
#include "window.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Window window;
window.setWindowTitle("window");
window.show();
return app.exec();
}
Update #1: a very interesting post.
I want to create a file that contains and manages the entire UI outside of the main.cpp and its main function.
To start I used the code from this answer, which worked fine
from inside the main method.
To prevent information loss I show the code below as well:
#include ...
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
QGraphicsView view(&scene);
QGraphicsPixmapItem item(QPixmap("c:\\test.png"));
scene.addItem(&item);
view.show();
return a.exec();
}
I tried to outsource this code into an own
class, but after executing the shown code the just created window
disappeared again within a few milliseconds without a warning or an error.
To check if I made a mistake within my own class I tried to use this code
from an own function within my main.cpp
void initUI(QApplication * application){
QGraphicsScene scene;
QGraphicsView view(&scene);
QGraphicsPixmapItem item(QPixmap(application->applicationDirPath() + "\\graphics\\Theme1\\background.png"));
scene.addItem(&item);
view.show();
}
But the same problem ocurs here. Why does the shown code needs to be executed within the main method, and how could you outsource it?
In case this information helps: I'm running on windows with Qt Creator 3.6.1
based on Qt 5.6.0 (MSVC 2013, 32 bit)
Edit:
Here is my main method
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
initUI(&a);
return a.exec();
}
Edit 2:
The error does not occur when I add an
application->exec();
Can somebody explain why this happens? What is the difference between
the call of application->exec() in the initUI-method and the a.exec() call
within the main method?
The destructors of scene and view are called once you exit initUI, as it is put on the stack. You need to put it on the heap in order to survive after exiting the init function. Of course you should take care of dangling pointers.
In my gui project, I need to start another application that updates the application that called the initial update.. if that makes sense.
The only way the secondary program can update the main program is if the main program is closed.
This is what I did:
QDesktopServices::openUrl(QUrl("file:update.exe"));
qApp->quit();
In the update program I also added a 2 second sleep timer before the update begins just in case. The problem is the main program never closes.
I have replaced qApp->quit() with qApp->exit, QApplication::quit(), QCoreApplication::exit() etc and nothing is closing the main program.
Any suggestions?
Try this one:
#include <QApplication>
#include <QProcess>
qApp->quit();
QProcess::startDetached("update.exe");
You can try to do the following (hopefully idea is clear from the source code):
// Launches another application after 5 seconds.
class Launcher : public QObject
{
Q_OBJECT
public:
Launcher()
{
QTimer::singleShot(5000, this, SLOT(launch()));
}
private slots:
void launch()
{
QProcess::startDetached("notepad");
qApp->quit();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Launcher launcher;
[..]
return app.exec();
}
#include "main.moc"
I'm a beginner to both C++ and Qt, so perhaps this is trivial. It certainly feels like it should be simple, but I've been searching for an answer for a few hours now and can't find the solution. I'm making a simple board game where the MainWindow's ui (made in QtDesigner) contains a canvas for the game board (a QGraphicsView). Now, the main.cpp is as simple as can be:
MainWindow Game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game.show();
return a.exec();
}
Since I need to access and edit the MainWindow Widgets from another totally unrelated class, I thought the easiest way would be to just make MainWindow a global variable. It seems that this approach was very wrong, though. Upon trying to run the project in QtDesigner I get a Microsoft Visual C++ runtime library error: the application has requested runtime to terminate it in an unusual way.
So what is the correct way to do what I need?
Aside from the MainWindow I have a dialog for a new game (QDialog, generated from QtDesigner) that is displayed after clicking a menu item in MainWindow. When the user inputs all parameters for the game and clicks OK in the dialog, I instantiate a custom non-Qt class called GameState. This class is meant to operate the game itself, draw the board, prompt the user, etc. However, as this class is created in the QDialog, it does not know of the existence of a MainWindow and so I cannot do anything with the MainWindow from this class. How can I modify the MainWindow from an unrelated class, then?
Also, jsut how does the setEnabled() function work? It never seems to do anything. Any widget I set as disabled in the QtDesigner and then try to enable through this function still stays disabled in the GUI...
First off it's a bad idea to create MainGame before you create your QApplication object.
If you want to have your MainGame object globally available like this it should be a pointer:
MainWindow *Game;
int main (int argc, char **argv)
{
QApplication a (argc, argv);
Game = new MainWindow();
Game->show();
int result = a.exec();
delete Game;
Game = NULL;
return result;
}
This approach is however not the most elegant. There are two much better choices.
The QApplication object actually stores all top level windows like your MainGame which means you can allways aquire it through QApplication::topLevelWidgets() which is a static function and returns a list with all top level widgets. Since you only have one, the first one is your MainGame. The drawback is you'll have to cast it, but using Qts qobject_cast<MainGame*>(...) is fairly safe. You'll have to check the result though to make sure it isn't a NULL pointer.
Use the singelton design pattern. You should store the global Game pointer in the source (cpp) file of the Game class itself (subclass QMainWindow) and your Game class should implement a static public method which returns this global pointer. So if any other class needs the Game pointer, it simply calls:
MyGame *theGame = MyGame::getInstance();
for example.
Regarding your setEnabled() problem. Please post the relevant code. If it's too much feel free to send me the *.ui file and the piece of code via mail.
Best regardsD
I am doing it this way:
QMainWindow* getMainWindow()
{
foreach (QWidget *w, qApp->topLevelWidgets())
if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w))
return mainWin;
return nullptr;
}
If your application has only one window you can simply use:
MainWindow * win = (MainWindow *) qApp::activeWindow();
The easiest way to do this is to first set up a signal in the header file of your other class to say perform a function to manipulate an object in the main class like this
signals:
void disableLoadButtton();
Then create a slot under private slots in the header file of the main window like this
private slots:
void disableLoadButtton();
Then create the function as a members function in the main window to manipulate the object
void MainWindow::disableLoadButton()
{
ui->loadButton->setenabled(false);
}
Then add the following line in another member function of the main window which say sets up the page. My other class is called searchWidget
void MainWindow::setUpPage()
{
connect(searchWidget, SIGNAL(disableLoadButton()), this, SLOT(disableLoadButton()));
}
Then all you have to do to disable the loadButton (which is a object in MainWindow) is to add the following line in any members function of my other class searchWidget
void searchWidget::performSomething()
{
emit disableLoadButton();
}
This will then manipulate the object loadButton in the mainwindow from within a member function of the other class searchWidget.
In the past I used approach described in this answer (found in Qtractor project).
Now I use QObject 'name' property and discover it anywhere as described here.
main.c
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include <QString>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "c.h"
MainWindow * MainWindow::pMainWindow = nullptr;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
pMainWindow = this;
setCentralWidget(&m_pb);
connect(&m_pb, SIGNAL(clicked()), this, SLOT(on_pb_clicked()));
}
MainWindow::~MainWindow() {delete ui;}
// kind of singleton reference.
MainWindow *MainWindow::getMainWinPtr()
{
return pMainWindow;
}
void MainWindow::pbSetText()
{
m_pb.setText(QString{"Call from c."});
}
void MainWindow::on_pb_clicked()
{
c C; // call of MainWindow from class c ctor
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QPushButton>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow * getMainWinPtr();
void pbSetText();
public slots:
void on_pb_clicked();
private:
static MainWindow * pMainWindow;
Ui::MainWindow *ui;
QPushButton m_pb{QString{"Press me."}, this};
};
#endif // MAINWINDOW_H
c.cpp
#include "c.h"
#include "mainwindow.h"
c::c()
{
MainWindow * mw = MainWindow::getMainWinPtr();
mw->pbSetText();
}
c.h
#ifndef C_H
#define C_H
class c
{
public:
explicit c();
};
#endif // C_H
If you have to access your MainWindow from another window, you are probably doing it wrong. Using another class to pass information with signals/slots is probably a much better approach
I'm trying to learn Qt, with a fairly simple application:
#include <QtGui/QApplication>
#include <QPushButton>
#include <QDebug>
/* -- header begin {{{ */
class BareBase {
public:
BareBase();
};
class BareBones: public QApplication {
private:
BareBase* base;
public:
BareBones(int &argc, char **argv);
~BareBones();
};
/* -- header end }}} */
/* -- implementation begin {{{ */
BareBase::BareBase()
{
QPushButton hello("Hello world!");
hello.resize(100, 30);
hello.show();
}
BareBones::BareBones(int& argc, char** argv): QApplication(argc, argv)
{
qDebug() << "Creating new instance ... ";
base = new BareBase();
}
BareBones::~BareBones()
{
qDebug() << "Cleaning up ... ";
delete base;
}
/* -- implementation end }}} */
int main(int argc, char **argv)
{
//Q_INIT_RESOURCE(files);
BareBones app(argc, argv);
return app.exec();
}
Now, the problem is that the Button created in BareBase never shows up, and i'm puzzled why?
Your QPushButton is creating and display correctly but go out of scope when leaving BareBase constructor. Using a member variable or a pointer will solve your problem.
If you use a pointer, you should add your button to its parent. By this way the button will be automatically deleted when the parent will be deleted.
QPushButton might have shown up but not in the visible area of the widget. That's why, you should add all your widgets to the Layouts that are available in Qt to obtain the desired behaviour. Check out the docs here... It has examples also...
Also, basically you will be having a base QWidget or most probably QMainWindow on which all your controls will be present.. So, your QPushButton will be in the parent widget.. Your QApplication will contain your application specific information like setting the window, setting the font for your entire application kinda stuff..
Hope it helps..