A console application is usually used for daemon-style long-running background processes.
But just to get myself wet with Qt, here I create a Qt console application for displaying "Hello World".
Steps to Create The App
From Qt Creator, create a
Qt Console application.
Right click the project, create a new class. Name the class
HelloWorld and inherit from
QObject.
Add
sayHello() and
done() methods so
helloworld.h now looks like this:
helloworld.h :
#ifndef HELLOWORLD_H
#define HELLOWORLD_H
#include <QObject>
class HelloWorld : public QObject
{
Q_OBJECT
public:
explicit HelloWorld(QObject *parent = 0);
signals:
void done();
public slots:
void sayHello();
};
#endif // HELLOWORLD_H
Implement the
sayHello() method:
helloworld.cpp :
#include "helloworld.h"
#include <stdio.h>
HelloWorld::HelloWorld(QObject *parent) :
QObject(parent)
{
}
void HelloWorld::sayHello() {
printf("Hello World!\n");
done();
}
In
main.cpp, add some plumbing to use the
HelloWorld class.
main.cpp :
#include <QObject>
#include <QtCore/QCoreApplication>
#include <QTimer>
#include <helloworld.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
fprintf(stderr, "Starting up...\n");
QCoreApplication a(argc, argv);
HelloWorld helloWorld;
QObject::connect(&helloWorld, SIGNAL( done() ), &a, SLOT( quit() ), Qt::QueuedConnection);
QTimer::singleShot(0, &helloWorld, SLOT( sayHello() ));
return a.exec();
}
Running the App
To run the app, click the
Run button or press
Ctrl+R.
Qt Creator should build the application, and show the output in the Application Output panel.
Starting /home/ceefour/Sandbox/helloworld-console/helloworld-console...
Starting up...
Hello World!
/home/ceefour/Sandbox/helloworld-console/helloworld-console exited with code 0
Application Logic
The main entry point deserves some explanation.
- It creates a Qt Core application (QCoreApplication) in variable a.
- Connects helloWorld's done() signal to the app's quit() slot/method, with a connection type of Qt::QueuedConnection.
- Creates a single shot timer (QTimer) with 0 ms delay that triggers helloWorld's sayHello() slot/method.
See
Qt's Signals and Slots for more explanation what what connect, signals, and slots are. It's basically a unified event handling mechanism for Qt applications.
a.exec() will run Qt's event loop, which will process incoming events:
- The timer event will be processed, therefore executing helloWorld.sayHello().
- sayHello() does its job (printing "Hello World!"), then it will call its done() signal.
- helloWorld.done() signal was connected to a.quit(), therefore telling Qt application to stop the event loop and quit the application.
P.S.: Queued Connection
A default connection calls the slot directly. However, I use
Qt::QueuedConnection here so that the call is queued until the slot processes the message.
In this case it's actually not needed.
It's possible to:
- Run helloWorld.sayHello() directly (without using QTimer), and it can still exit the application because the event is queued.
- Leave out the Qt::QueuedConnection, and it can still exit the application because the direct a.quit() call happens after the event loop is started.
What happens if
helloWorld.sayHello() is run directly, and
Qt::QueuedConnection is not specified?
The app will not quit immediately, because the event loop will not have started when
a.quit() is called, therefore having no effect. Which is incorrect logic.
Why Separate Header (.h) and Implementation (.cpp) Files?
In this example I separated
helloworld.h from
helloworld.cpp. You may be wondering if it's possible to merge them into just one
helloworld.cpp implementation file.
The answer is
No. At least not if you use
Q_OBJECT or other Qt macros. Snippet from
C++ GUI Programming with Qt 4
:
For moc to work correctly, we must put the class definition in a header file, separate from the implementation file. The code generated by moc includes this header file and adds some C++ boilerplate code of its own.
So, don't fight it. Besides, that's the convention in C++ world anyway.
Reference:
qt-interest thread: QCoreApplication won't quit