QTGraphicsView allways instantly closes after running outside from main method - c++

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.

Related

Qt: How to use slots when object are created in class function

I'm learning Qt quick and want to create a tank game. I create QML components by C++ dynamically. It works great until I use QML signals to connect C++ slots. When the QML emit the signal, C++ fail to receive it and execute the function.
The following code is simplifed.
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
GameMap map;
map.generateMap();
return app.exec();
}
gamemap.cpp
void GameMap::generateMap()
{
Player player;
player.generate(&view);
//QEventLoop loop; //it works when I add these code, but still causes some problems. So I'm wondering if there is other solution?
//loop.exec();
}
player.cpp
void Player::generate(View *view)
{
QQmlComponent component(view.engine(),QUrl("qrc:/Player.qml"));
QObject *myObject=component.create();
QQuickItem *item=qobject_cast <QQuickItem*>(myObject);
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
item->setParentItem(view.rootObject());
item->setParent(&view);
QObject::connect(item,SIGNAL(queryCppFun(QString)),this,SLOT(queryFunction(QString)));
}
void Player::queryFunction(const QString &funName)
{
if(funName=="destroy")
qDebug()<<funName;
}
Player.qml
signal queryCppFun(string funName);
function initDestroy(){
queryCppFun("destroy");
}
OK, I know how to do with it.
Just put static in front of Player player;
And do not handle QML items in C++, thanks #folibis

Custom Qt controls in C++

I'm trying to use a custom control in Qt, but don't know how.
My current main code:
int main(int argc, char *argv[]) {
QApplication application(argc, argv);
MainWindow window;
window.setWindowState(Qt::WindowMaximized);
window.show();
return application.exec();
}
MainWindow ui has a QTextEdit and a PushButton. Now, I want to use another control that inherits from QTextEdit.
I've added a CodeEditor class that is taken from the documentation, but it doesn't appear in Qt Creator designer.

How some objects are created before main event loop?

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.

Qt C++ connect QPushButton click

I have just started developing using QtGUI and I have checked out some tutorials and documentation, and by what I've read this should work.
#define CONNECT QObject::connect
void test();
QPushButton *lpTestBtn;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtProject w;
w.show();
lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
CONNECT(lpTestBtn, SIGNAL(clicked()),qApp,SLOT(test()));
return a.exec();
}
void test()
{
lpTestBtn->setText("Hi");
}
But test() never gets called. Also, lpTestBtn is not null and is found correctly.
I have tried the following changes
CONNECT(lpTestBtn, SIGNAL(clicked()),qApp->activeWindow(),SLOT(test()));
CONNECT(lpTestBtn, SIGNAL(clicked()),w.window(),SLOT(test()));
I know I can just do QtProject::on_TestBtn_clicked(); but I'd like to get it working using CONNECT,SIGNAL and SLOT.
The test function in your code is not a slot, nor does it belong to the Q(Core)Application class as you seem to have used it.
The best would be is to move that one line in the test function to the connection with the lambda syntax. This will require C++11 support, but that is in quite common use these days.
You would use the new shiny signal-slot syntax. This would spare you some headache for runtime issues in the future because they would appear at compilation-time.
Therefore, you would write something like this:
main.cpp
#include <QMainWindow>
#include <QApplication>
#include <QPushButton>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
// Replace it with "QtProject".
QMainWindow w;
w.show();
QPushButton * lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
QObject::connect(lpTestBtn, &QPushButton::clicked, [=]() {
lpTestBtn->setText("Hi");
});
return a.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Please also note that it is bad idea to create a global pointer for a QPushButton object. It not only leaks the memory, but you could have other issues, too.
1) QApplication doesn't have a test() slot in it. You need to make your own class, inheriting QApplication, and give that class a test() slot. What you've done is create a regular function, which won't help.
2) You didn't check the return value of connect, which means you didn't see that it was giving you an error, which would probably have given you some clues.
You can connect signals to the slots which are in classes derived from QObject so meta compiler can deduce slot calls. But your test() is global function. You have to put your slot function inside a class that derives from QObject and supports Q_OBJECT macro or define a lambda function ( with C++11 support) as Laszlo Papp showed.
Example:
// testwrapper.h
class TestWrapper : public QObject
{
Q_OBJECT
//...
public slots:
void test();
};
// main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtProject w;
w.show();
QPushButton * lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
TestWrapper tw;
CONNECT( lpTestBtn, SIGNAL( clicked()),tw,SLOT( test()));
return a.exec();
}

QApplication In Non-Main Thread

I need to exec() a QApplication in a thread that is not main (my GUIs must be plugins that can be dynamically loaded and unloaded at runtime, so I have no access to the main thread). Does anyone know of a (relatively) painless way to hack around Qt's restriction against starting QApplication outside of main?
I'm developing in Linux with Qt4 in C++ using gcc4.3.4.
You can start a QApplication in a PThread as below
//main.cpp
#include <iostream>
#include "appthread.h"
int main(int argc, char *argv[]) {
InputArgs args = {argc, argv};
StartAppThread(args);
sleep(10);
return 0;
}
//appthread.h
struct InputArgs{
int argc;
char **argv;
};
void StartAppThread(InputArgs &);
//appthread.cpp
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include "appthread.h"
#include <pthread.h>
void *StartQAppThread(void *threadArg) {
InputArgs *args = (struct InputArgs*) threadArg;
QApplication app(args->argc, args->argv);
QMainWindow w;
w.show();
w.setCentralWidget(new QPushButton("NewButton"));
app.exec();
pthread_exit(NULL);
}
void StartAppThread(InputArgs &args) {
pthread_t thread1;
int rc = pthread_create(&thread1, NULL, StartQAppThread, (void*)&args);
}
If you are using QThread then you already have normal Qt event loop and can just run exec() inside QThread::run() function. While you can't work with GUI objects outside of the main thread you still can interact with them through queued signal/slot connections. Maybe you can try to store pointer to the main thread QThread object and call QObject::moveToThread() to move your GUI objects to the main thread instead of moving QApplication into another thread.
I think it's not really good idea to try to go against toolkit with different kind of hacks and kluges.
Ok, I got something that works! It's not pretty, but it definitely does the job.
Create a QMainWindow derivative with all of your actual GUI code in it and overload the event() function of this class to call this->show()
Create a class (let's call it Runner) which will hold a pointer to your QMainWindow derivative, and give it a run function.
In the Runner::Runner(), start up a thread which will call Runner::run()
In Runner::run() (which is now running in it's own thread) construct a QApplication, and an instantiation of your QMainWindow derivative. Call the exec() function of the QApplication.
Now, when you want to start up your GUI, just post any event to your QMainWindow derivative, and it will show itself!
This solution seems to work very well in Linux, although it really seems to be exploiting some loophole in Qt and may not work on other platforms. Definitely easier than patching Qt though.
Patch Qt, I guess and remove the main thread check, and test if that works for you.
According to
http://bugreports.qt-project.org/browse/QTBUG-7393
that won't work on OS X/Cocoa though, as Cocoa assumes the first thread spawned to be the main/UI thread.
Adding my 2 cents with a fancy lambda and C++ threads:
#include "mainwindow.h"
#include <QApplication>
#include <thread>
int main(int argc, char *argv[])
{
std::thread t1
(
[&]
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
);
t1.join();
}
Here Mainwindow can be your QMainWindow.
A good solution is found in: git#github.com:midjji/convenient_multithreaded_qt_gui.git
then its just e.g.
run_in_gui_thread(new RunEventImpl([](){
QMainWindow* window=new QMainWindow();
window->show();
}));
or whatever code you wish to run in the gui thread.
callable from any thread, at any time, while taking care of setting things up for you in the bg.