Dennis
Dennis

Reputation: 41

Qt Console Application with optional GUI

I have written a console application for my server. It works very well, I can start it over the terminal and all is okay. For desktop environments it would be very nice, to set a flag in the settings.ini file of the program to open a MainWindow to show some information of the running console application. The console in the background can be left open. All I need is a window and some SINGAL/SLOTS between the main application running in console and the MainWindow.

How to realize this? I figured out, I have to handle with QApplication and QCoreApplication right?

Upvotes: 3

Views: 3161

Answers (1)

Pixtar
Pixtar

Reputation: 361

Simply put this line to your pro file:

CONFIG += console

In Qt5.x from Win7 to Win10 you could do something like this:

//includes
#include <QApplication>
#include <QMainWindow>
#include <QString>
#include <QObject>
#include <QDir>
#include <QSettings>

#include <windows.h>
#include <stdio.h>
#include <iostream>

//
// Add to project file:
// CONFIG += console
//

The server:

//Here we have the Server class able to send signals
//Server will be used in main.cpp for console
//and/or in MainWindow to handle the signals
class Server : public QObject
{

    Q_OBJECT

public:
    Server( QObject *parent = 0 ) : QObject( parent )
    {
        //do server stuff
        //this->setName( "Test" );
        //std::cout << this->getName( ) << std::endl;
        //std::cout << "Enter URL: << std::endl;
        //std::string url;
        //std::cin >> url;
        //_url = QString::fromStdString( url );
        //emit finished();
    }

signals:
    void finished( );

private:
    QString _url;

};

The MainWindow:

//Here is the MainWindow using Server
class MainWindow : public QMainWindow
{

    Q_OBJECT

public:
    MainWindow( QWidget *parent = 0 ) : QMainWindow()
    {
        server = new Server( this ); //use server in hybrid mode (console and gui)
        connect( server, SIGNAL(finished()), this, SLOT(close()) ); //establish connection
    }

private:
    Server *server;

};

The main:

int main( int argc, char *argv[] )
{
    QString iniPath = QFileInfo( QDir::fromNativeSeparators(argv[0]) ).absolutePath(); //get the current dir
    QSettings settings( iniPath+"/settings.ini", QSettings::IniFormat ); //open ini
    bool gui = settings.value( "gui", false ).toBool(); //read ini
    if( gui ) //decide
    {
    #if defined( Q_OS_WIN )
        // hide console window, but not in your case
        // ::ShowWindow( ::GetConsoleWindow(), SW_HIDE );
    #endif
        //std::cout will print to the console in the bg like you wished
        QApplication a( argc, argv );
        MainWindow *w = new MainWindow;
        w->show();
        int e = a.exec();
        delete w; //needed to execute deconstructor
        exit( e ); //needed to exit the hidden console
        return e;
    }
    else
    {
        QCoreApplication a( argc, argv );
        Server *instance = new Server; //use server in console only
        exit( 0 );
        return a.exec();
    }
}


I tried it also without the "CONFIG += console", but then you need to redirect the streams and create the console on your own:

#ifdef _WIN32
if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()){
    freopen("CONOUT$", "w", stdout);
    freopen("CONOUT$", "w", stderr);
    freopen("CONIN$", "r", stdin);
}
#endif

BUT this only works if you start it through a debugger, otherwise all inputs are directed towards the system too. Means, if you type a name via std::cin the system tries to execute the name as a command. (very strange)

Two other warnings to this attempt would be, that you can't use ::FreeConsole() it won't close it and if you start it through a console the app won't close.



Last there is a Qt help section in QApplication to this topic. I tried the example there with an application and it doesn't work for the GUI, it stucked somewhere in an endless loop and the GUI won't be rendered or it simply crashes:

QCoreApplication* createApplication(int &argc, char *argv[])
{
    for (int i = 1; i < argc; ++i)
        if (!qstrcmp(argv[i], "-no-gui"))
            return new QCoreApplication(argc, argv);
    return new QApplication(argc, argv);
}

int main(int argc, char* argv[])
{
    QScopedPointer<QCoreApplication> app(createApplication(argc, argv));

    if (qobject_cast<QApplication *>(app.data())) {
       // start GUI version...
    } else {
       // start non-GUI version...
    }

    return app->exec();
}


So if you are using Windows and Qt simply use the console option, hide the console if you need the GUI and close it via exit.

Upvotes: 3

Related Questions