Wim Peeters
We give the project a name and a directory.
We select the modules we need for the application. If we do now add modules now, we can add them to the project later.
Qt creater created two files for us. The first one is consoleapp.pro. The contents is the following:
#------------------------------------------------- # # Project created by QtCreator 2009-11-18T21:47:34 # #------------------------------------------------- QT -= gui TARGET = consoleapp CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp
This is a Qt project file and we do not have to change it now. The second one is the main.cpp file. As you might expect, this program is not doing anything. I even have bad news for you, if you run it, it does not end!
#include <QtCore/QCoreApplication> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); return a.exec(); }
#include <QtCore/QCoreApplication> #include <QTimer> #include <QTextStream> #include <QDebug> #include <iostream> //by Wim Peeters: a console application int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); //renamed the a to app QTextStream qout(stdout); //I connect the stout to my qout textstream qout << "1. Starting the application\n"; std::cout << "2. Some normal iostream output before using qDebug\n"; qDebug() << "3. Some output with qDebug after the iostream output\n"; QTimer::singleShot(5000, &app, SLOT(quit())); //stop after 5 seconds return app.exec(); //and we run the application }
The output of this application is not what you expect. You will have to run the application to know exactly what I mean. The first two lines of output will be shown immediately. The one you expect to be the first will be the last and it will be shown after 5 seconds. The last funny thing is the qDebug output. It has an extra newline after it! Did you expect this output?
wpeeters@debian5:~/data/code/consoleapp/consoleapp$ ./consoleapp 2. Some normal iostream output before using qDebug 3. Some output with qDebug after the iostream output 1. Starting the application wpeeters@debian5:~/data/code/consoleapp/consoleapp$
Using endl will flush the buffer inplicitly. In this case, it is the prefered way. You could have used qout.flush() to explicitly flush to buffer to. The qDebug has a kind of build in endl and does not need to have an extra one. I took it out! Now this is what the code looks like:
#include <QtCore/QCoreApplication> #include <QTimer> #include <QTextStream> #include <QDebug> #include <iostream> //by Wim Peeters: a console application int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); //renamed the a to app QTextStream qout(stdout); //I connect the stout to my qout textstream //I took \n out and replace it with endl qout << "1. Starting the application" << endl; std::cout << "2. Some normal iostream output before using qDebug\n"; //built in endl! qDebug() << "3. Some output with qDebug after the iostream output"; QTimer::singleShot(5000, &app, SLOT(quit())); //stop after 5 seconds return app.exec(); //and we run the application }
The output you expected to get in the first place.
wpeeters@debian5:~/data/code/consoleapp/consoleapp$ ./consoleapp 1. Starting the application 2. Some normal iostream output before using qDebug 3. Some output with qDebug after the iostream output wpeeters@debian5:~/data/code/consoleapp/consoleapp$
You will see the output at once, than the application waits till the 5 seconds are over and quits. So far so good. To write some nice console application we need to do something. Now we will add some sourcecode which can be filled to do something usefull. When the task is done, we will end the application. For demonstration purposes, we still leave the 5 seconds trigger at the end. We will need it! The first thing to do is to add a new class. This can be done by right clicking on the project and selecting add.
Now I changed the generated class a bit so it can be used. The ctodo.h file has been changed to:
#ifndef CTODO_H #define CTODO_H #include <QObject> //by Wim Peeters showing a console application class CTodo : public QObject { Q_OBJECT public: CTodo(QObject *parent=0); //we need the *parent here ~CTodo(); //destructor void go(); //here we will do the work signals: void allDone(int); //we add a new signal public slots: void showDone(int); //just needed to explain something about signals }; #endif // CTODO_H
I also changed the ctodo.cpp file so it can show something on the screen.
#include <QTextStream> #include <QCoreApplication> #include <QTimer> #include <QDebug> #include "ctodo.h" CTodo::CTodo(QObject *parent) : QObject(parent) { QTextStream qout(stdout); qout << "a. Constructor...\n"; qout.flush(); //the other way to flush the buffer! } CTodo::~CTodo() { qDebug() << "d. Destructor..."; //no need for and endl! } void CTodo::go() { qDebug() << "b. Working very hard..."; //we want to know if the signal has been emitted QObject::connect(this, SIGNAL(allDone(int)),this, SLOT(showDone(int))); //we want to connect it to the quit of the application to QObject::connect(this,SIGNAL(allDone(int)),this->parent(), SLOT(quit())); emit allDone(5); //sending the signal to stop the app } void CTodo::showDone(int) { qDebug() << "c. Yes, the signal has been sent"; } //Do you miss the implementation of the signal? //We defined the following the ctodo.h file: //signals: // void allDone(int); //we add a new signal //We should not define it, the framework will do it for us! //You get the following error if you do define it: //error: multiple definition of CTodo::allDone(int)
If you get error messages concerning "vtables not found" you need to run qmake. This can be done by selecting it from the menu or by involing a complete build from the menu. If you run the programm you will see that the program will not quit with your signal. Instead it will wait and end after 5 seconds. This again is not what I would expect. If you would not have this 5 seconds signal, it will run forever! The program will output is shown below.
wpeeters@debian5:~/data/code/consoleapp/consoleapp$ ./consoleapp 1. Starting the application 2. Some normal iostream output before using qDebug 3. Some output with qDebug after the iostream output a. Constructor... b. Working very hard... c. Yes, the signal has been sent d. Destructor...
QObject::connect(this,SIGNAL(allDone(int)),this->parent(),SLOT(quit())); into QObject::connect(this,SIGNAL(allDone(int)),this->parent(),SLOT(quit()), Qt::QueuedConnection);If you run the application now, you will notice that the 5 seconds timer is not needed anymore. The program will stop before it can be triggered. If you fill this template application with life, do not forget to take the 5 seconds timer out just in case your application runs longer than 5 seconds. This timer (QTimer::singleShot()) was only needed for explaining the application so we did not have to kill it all the time during experimenting.