Saturday, February 16, 2013

QT Console Application Template Tutorial

Writing a command line program in QT may be a little harder than you would expect; particularly if you want to use the full features of QT including Signals, Slots and Threads.

If you start writing a QT program as a standard “main” program in “c” none of the QT messaging structure will operate as expected.

I have written many QT command line programs, some are commercial products.  Here is a template that I have developed which seems to work well.

Lets get started:

Here is the main.cpp file where it all starts.

#include <QtCore/QCoreApplication>
#include <QTimer>
#include "mainclass.h"
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);


    // create the main class
    MainClass myMain;


    // connect up the signals
    QObject::connect(&myMain, SIGNAL(finished()), 

             &app, SLOT(quit()));
    QObject::connect(&app, SIGNAL(aboutToQuit()), 

             &myMain, SLOT(aboutToQuitApp()));

    // This code will start the messaging engine in QT and in
    // 10ms it will start the execution in the MainClass.run routine;
    QTimer::singleShot(10, &myMain, SLOT(run()));
    return app.exec();
}

 

A few things worth noting here.
  • A instance of the MainClass class called myMain is created.  
  • A signal in that MainClass called "finished" actually quits the application.
  • A signal from the app works with a slot in myMain called aboutToQuitApp
  • A 10ms timer sends a signal to the slot run in the myMain class.  This bootstraps your code.
  • The last line “return app.exec()” starts all of the QT messaging including the Slots and Signals system across various threads.
  • By the time myMain gets the signal on the “run” Slot the QT application structure is up and running.

Now lets create the header file for the MainClass;  mainclass.h

#ifndef MAINCLASS_H
#define MAINCLASS_H
#include <QObject>
#include <QCoreApplication>
class MainClass : public QObject
{
    Q_OBJECT
private:
    QCoreApplication *app;


public:
    explicit MainClass(QObject *parent = 0);
    /////////////////////////////////////////////////////////////
    /// Call this to quit application
    /////////////////////////////////////////////////////////////
    void quit();


signals:
    /////////////////////////////////////////////////////////////
    /// Signal to finish, this is connected to Application Quit
    /////////////////////////////////////////////////////////////
    void finished();


public slots:
    /////////////////////////////////////////////////////////////
    /// This is the slot that gets called from main to start everything
    /// but, everthing is set up in the Constructor
    /////////////////////////////////////////////////////////////
    void run();


    /////////////////////////////////////////////////////////////
    /// slot that get signal when that application is about to quit
    /////////////////////////////////////////////////////////////
    void aboutToQuitApp();
};
#endif // MAINCLASS_H


Lets look at a couple of things here.

  • Call “quit()” when you want to exit the application
  • The “finished” signal is sent to the app to close the application
  • The “run() slot is where your code “starts” gets called 10ms after the application is started
  • “aboutToQuitApp() slot gets called after the “finished” signal is executed by the QT application.

The last thing to look at is the actual mainclass.cpp code.

#include "mainclass.h"
#include <QDebug>
MainClass::MainClass(QObject *parent) :
    QObject(parent)
{
    // get the instance of the main application
    app = QCoreApplication::instance();
    // setup everything here
    // create any global objects
    // setup debug and warning mode
}


// 10ms after the application starts this method will run
// all QT messaging is running at this point so threads, signals and slots
// will all work as expected.
void MainClass::run()
{
    // Add your main code here
    qDebug() << "MainClass.Run is executing";
    // you must call quit when complete or the program will stay in the
    // messaging loop
    quit();
}


// call this routine to quit the application
void MainClass::quit()
{
    // you can do some cleanup here
    // then do emit finished to signal CoreApplication to quit
    emit finished();
}


// shortly after quit is called the CoreApplication will signal this routine
// this is a good place to delete any objects that were created in the
// constructor and/or to stop any threads
void MainClass::aboutToQuitApp()
{
    // stop threads
    // sleep(1);   // wait for threads to stop.
    // delete any objects
}


There are a few things to discuss here:

  • The constructor gets a instance of the QT application and sets it to “app”
  • The “run” slot is where your code will actually start execution.
  • When you are through running your code you must call “quit” to stop the application.  This will tell the QT application to terminate.
  • While the QT application is in the process of terminating it will execute the slot aboutToQuitApp().  This is a good place to do any clean-up work.

Well I hope this helps you get a QT Console application up and running quickly.

Comments are welcome.