QCoreApplication on the heap - c++

I have the need (for example when building a library) to instantiate QCoreApplication on the heap, and I found the following strange behavior (Qt 5.7):
#include <QCoreApplication>
#include <QDebug>
class Test
{
public:
Test(int argc, char *argv[]) {
m_app = new QCoreApplication(argc, argv);
//uncomment this line to make it work
//qDebug() << "test";
}
~Test() { delete m_app; }
private:
QCoreApplication* m_app;
};
int main(int argc, char *argv[])
{
Test test(argc, argv);
qDebug() << QCoreApplication::arguments(); //empty list!
}
Basically, everything works as expected if "qDebug()" is used just after allocating the object. If not, the list of arguments() is empty.

It seems to be related to this bug, which was fixed in Qt 5.9 and backported to Qt 5.6.3. The workaround is simply:
#include <QCoreApplication>
#include <QDebug>
class Test
{
public:
Test(int argc, char *argv[]) {
//allocate argc on the heap, too
m_argc = new int(argc);
m_app = new QCoreApplication(*m_argc, argv);
}
~Test() {
delete m_app;
delete m_argc;
}
private:
int* m_argc;
QCoreApplication* m_app;
};
int main(int argc, char *argv[])
{
Test test(argc, argv);
qDebug() << QCoreApplication::arguments();
}

I believe another way to fix this bug is to pass argc by reference:
#include <QCoreApplication>
#include <QDebug>
class Test
{
public:
Test(int& argc, char *argv[]) {
m_app = new QCoreApplication(argc, argv);
//uncomment this line to make it work
//qDebug() << "test";
}
~Test() { delete m_app; }
private:
QCoreApplication* m_app;
};
int main(int argc, char *argv[])
{
Test test(argc, argv);
qDebug() << QCoreApplication::arguments(); //empty list!
}
In addition, you don't need to create QCoreApplication on the heap, having it as an automatic member of Test is fine, i.e. QCoreApplication m_app.

Related

I don‘t have member function installNativeEventFilter

That's strange, w have the member function installEventFilter()
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.SerialPortInit();
//w.installNativeEventFilter(&w);
w.installNativeEventFilter(&w);
w.show();
qDebug() << "hello Wolrd";
return a.exec();
}
enter image description here

how to set an event callback for a domain lifecycle

I'm following this document and I'm using qt to implement this event
#include <QCoreApplication>
#include <QDebug>
#include <libvirt/libvirt.h>
void
domainLifecycleCb(virConnectPtr conn,
virDomainPtr dom,
void * opaque)
{
qDebug() << "test";
}
int main(int argc, char *argv[])
{
virEventRegisterDefaultImpl();
QCoreApplication a(argc, argv);
virConnectPtr conn = virConnectOpen("qemu:///session");
virDomainPtr domain = virDomainLookupByName(conn, "Windows");
qDebug() << virConnectDomainEventRegisterAny(conn,
domain,
VIR_DOMAIN_EVENT_ID_LIFECYCLE,
VIR_DOMAIN_EVENT_CALLBACK(domainLifecycleCb),
NULL, NULL);
return a.exec();
}
I tried different methods but the event doesn't work when the domain gets shutdown or started.
By that I mean the callback function should get call when the domain life-cycle changes, And I'm determining that by showing an output in the callback function.
There is a function that needs to be called in a loop to keep the connection alive
#include <QCoreApplication>
#include <QDebug>
#include <libvirt/libvirt.h>
#include <QThread>
void domainLifecycleCb(virConnectPtr conn,
virDomainPtr dom,
void * opaque)
{
qDebug() << "test";
}
int main(int argc, char *argv[])
{
virEventRegisterDefaultImpl();
QCoreApplication a(argc, argv);
virConnectPtr conn = virConnectOpen("qemu:///session");
virDomainPtr domain = virDomainLookupByName(conn, "WindowsECO");
QThread *thread = QThread::create([]{
while (true) {
qDebug() << virEventRunDefaultImpl();
} });
thread->start();
qDebug() << virConnectDomainEventRegisterAny(conn,
domain,
VIR_DOMAIN_EVENT_ID_LIFECYCLE,
VIR_DOMAIN_EVENT_CALLBACK(domainLifecycleCb),
NULL, NULL);
return a.exec();
}

creating QApplication in a different thread

I'm trying to create QApplication in a different thread, but found 2 main problems:
1- I can't interact with GUI
2- some warnings:
WARNING: QApplication was not created in the main() thread.
QObject::startTimer: timers cannot be started from another thread //happens when resizing widget
QObject::killTimer: timers cannot be stopped from another thread
here is the full code: (it may has some memory leaks but for testing purposes it fails)
//main.cpp
#include <QCoreApplication>
#include "cthread.h"
int main(int argc, char *argv[])
{
CThread *MyThread = new CThread;
MyThread->start();
QCoreApplication a(argc, argv);
return a.exec();
}
//CThread.h
#ifndef CTHREAD_H
#define CTHREAD_H
#include <QThread>
#include "theqtworld.h"
class CThread : public QThread
{
Q_OBJECT
public:
CThread();
void run( void );
private:
TheQtWorld *mWorld;
};
#endif // CTHREAD_H
//CThread.cpp
#include "cthread.h"
#include <iostream>
CThread::CThread():mWorld(NULL)
{
}
void CThread::run()
{
std::cout << "thread started" << std::endl;
if(!mWorld)
mWorld = new TheQtWorld();
mWorld->OpenWorld();//now it will init all Qt Stuff inside
// if(mWorld) delete mWorld;
// emit this->exit();
}
//theqtworld.h
#ifndef THEQTWORLD_H
#define THEQTWORLD_H
#include <QObject>
#include "mainwindow.h"
#include <QApplication>
class TheQtWorld : public QObject
{
Q_OBJECT
public:
explicit TheQtWorld(QObject *parent = 0);
int OpenWorld(void);
signals:
public slots:
};
#endif // THEQTWORLD_H
//theqtworld.cpp
#include "theqtworld.h"
TheQtWorld::TheQtWorld(QObject *parent) :
QObject(parent)
{
}
int TheQtWorld::OpenWorld()
{
static int arg = 0;
static char *b[2];
b[0] = "a";
QApplication *a = new QApplication(arg, b);
a->setParent(this);
MainWindow w;
w.show();
return a->exec();
}
I would answer my own question after understanding how to overcome this problem
first the problem was to integrate Qt GUI as a plugin into another Application, so the main issue was the Event loop collision between Qt Events and any other Application Events
my first thoughts was to separate both, so QApplication will stay at a different thread, but this was a totally wrong approach and here is what I have noticed:
1- Qt GUI Must stay in the main() thread so there is no other place for QApplication
2- to avoid the blocking QApplication::exec() , embed QApplication::processEvents() into the other Application Event loop
here is a working code:
//main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication mApp(argc, argv);
MainWindow w;
w.show();
//just for testing and holding the program so it doesn't end
for(int i = 0; i < 100000000; ++i)
{
mApp.processEvents();
}
return 0;
}
edit:thanks to pavel-strakhov for his great suggestion.

Decide which Window open in QT on start

I need help. I'm trying to open 1 of 2 possible windows on start. Program decide which window will open on screen dimensions.
#include <QApplication>
#include <QDesktopWidget>
#include "mainwindow.h"
#include "vincellform.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDesktopWidget mydesk;
if (mydesk.screenGeometry().width() == 800 && mydesk.screenGeometry().height() == 480)
{
VincellForm vf;
vf.show();
}
else
{
MainWindow w;
w.show();
}
return a.exec();
}
I think that this code is correct, but it isn't. If I'm on different screen (1280*1024 I think) program goes to else part (MainWindow w; w.show();) and then goes to return, but no window is opened. But if I changed a code to:
#include <QApplication>
#include <QDesktopWidget>
#include "mainwindow.h"
#include "vincellform.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDesktopWidget mydesk;
if (mydesk.screenGeometry().width() == 800 && mydesk.screenGeometry().height() == 480)
{
VincellForm vf;
vf.show();
}
MainWindow w;
w.show();
return a.exec();
}
it runs perfectly (MainWindow will open after return). I can't even imagine where the problem can be... Thank you very much
You're defining the window variables locally in the if and else blocks. This means the windows are destroyed immediately after they're shown.
You have two solutions. If you don't mind creating both windows, but only showing one, do this:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDesktopWidget mydesk;
VincellForm vf;
MainWindow w;
if (mydesk.screenGeometry().width() == 800 && mydesk.screenGeometry().height() == 480)
{
vf.show();
}
else
{
w.show();
}
return a.exec();
}
If you only want one of them created, you'll have to resort to dynamic allocation:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDesktopWidget mydesk;
std::unique_ptr<VincellForm> vf;
std::unique_ptr<MainWindow> w;
if (mydesk.screenGeometry().width() == 800 && mydesk.screenGeometry().height() == 480)
{
vf.reset(new VincellForm);
vf->show();
}
else
{
w.reset(new MainWindow);
w->show();
}
return a.exec();
}
Note: std::unique_ptr comes from C++11. If you don't have this yet, use raw pointers instead a delete manually at program end.

error Using QTest Macro QCOMPARE

I want use QTest Macro QCOMPARE in my code,but I receive errors.
QTestString.h
#ifndef QTESTSTRING_H
#define QTESTSTRING_H
#include <QtCore/QString>
#include <QtTest/QtTest>
class TestqstringTest : public QObject
{
Q_OBJECT
public:
TestqstringTest();
private slots:
void testCase1();
};
#endif // QTESTSTRING_H
QTestString.cpp
#include "QTestString.h"
TestqstringTest::TestqstringTest()
{
testCase1();
}
void TestqstringTest::testCase1()
{
QString str = "Hello";
QCOMPARE(str.toUpper(),(QString)"hELLO");
}
main.cpp
#include "QTestString.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TestqstringTest *test = new TestqstringTest();
return a.exec();
}
However, I receive the following errors:
ASSERT: "QTest::testLogger" in file qtestlog.cpp, line 266 The program
has unexpectedly finished.
I found the answer,you must use int QTest::qExec ( QObject * testObject, int argc = 0, char ** argv = 0 ) to excute it ,then the testlog output correctly.