添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
空虚的啄木鸟  ·  SIGSEGV: Crash due to ...·  昨天    · 
精明的蜡烛  ·  Qt 4.8: QSslSocket ...·  1 周前    · 
率性的玉米  ·  FFT in Python — ...·  1 周前    · 
长情的自行车  ·  signal — Set handlers ...·  2 周前    · 
个性的灯泡  ·  sigwaitinfo • man page·  2 周前    · 
英勇无比的脸盆  ·  No module named ...·  2 周前    · 
买醉的石榴  ·  Let Dash listen to ...·  2 月前    · 
深沉的伏特加  ·  Download a blob with ...·  4 月前    · 

Abstract:

You find quite a lot of information about writing Qt applications but the information for console application is hard to find. This article shows you a few problems you can run into when writing your first console application. The application will be created with the free version of qt and qt creator will be used as an IDE. Everything is compiled under Debian linux but can also be compiled under Windows. 1 Getting started We start this article with a working Qt Creator IDE environment. Please have a look at the ebook about how to install Qt creator when you do not have the IDE installed yet. The goal of the application is to create a working template of a console application by running into all problems you might get. I will explain why these problems exist and show you some different ways to solve them. I love console applications and need them for systems without GUI. Qt is a wonderfull framework and not limited to GUI applications. #------------------------------------------------- # 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(); 1.2 Ending the application and show some output The application does not end because we never told it to end. It is running a messageloop and exactly doing what it should. To make it end, we need to send it a signal. Now we want to run into all the problems we might run into. I changed the application and gave it a timer which will end the application after 5 seconds. Using the timer makes it possible to show you a few pitfalls. To see some output, I created a QTextStream which will be written to stdout. To have some more output, I also added an iostream and a QDebug message. This program will compile just normal, the funny thing about it, is the output and the timing. Why? (In a normal application you might use one of the output possibilities and stick to it.) #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$ 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. 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... 1.4 More pitfalls you can run into In the program I also introduced an own created signal. The code for the implementation will be generated by the framework! If you generate it you will get an errormessage stating a multiple definition of CTodo::allDone(int). I gave it an int parameter for demonstration purposes. The parameter is not used in the program. Another pitfall you might run into is the Q_OBJECT keyword in the headerfile. This is needed for signals and slots. That's why you will have to run qmake to solve the vtables error messages. I used the flush function in the constructor to demonstrate the usage of it. Try to leave it out and run the program again! The most interested problem is the signal not being sent to the app in the main function. That's why the program does not stop and need the 5 seconds timer to get stopped. 1.5 Signal explication It is wrong to state that the signal is not sent to the application. That's why I wrote the showDone(int) function. The function is called, meaning the signal is sent. The problem we have here is the fact that the signal is sent to early. The messagloop of the app is not running yet. When the signal is sent, it will be seen except from our showDone(int) function. To solve this problem we have to tell the connection to queue the signal. This can be done with the Qt::QueuedConnection parameter. I just changed the line QObject::connect(this,SIGNAL(allDone(int)),this->parent(),SLOT(quit())); 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. 2 Conclusion Qt is a wonderfull framework not just for creating GUI application on different platforms but also for writing powerfull console applications. I use Qt console applications for connection to Postgres databases and doing some interactive database work, as well as for my GUI applications on windows and linux. I hope you liked this introduction, based on this template you can start doing some work. Hope you liked it.