Tuesday, December 29, 2009

Create a Hello World Console Application with Qt

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:
  1. The timer event will be processed, therefore executing helloWorld.sayHello().
  2. sayHello() does its job (printing "Hello World!"), then it will call its done() signal.
  3. 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

No comments:

Post a Comment

Be the first to comment!