Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Same application executed as console app or QML GUI



  • Hello,
    I am looking for a way to make my app executable either as a terminal application or as a QML GUI app (depends on the user preferences).
    My problem is that with my current main.cpp (code is below) when I try to execute the exe as a GUI it also opens the terminal/Windows console.
    I have checked for a solution and I found that I should add the following in CMakeLists:

    if (WIN32)
        set_property(TARGET Ptc05Manager PROPERTY WIN32_EXECUTABLE true)
    else ()
        set_property(TARGET Ptc05Manager PROPERTY WIN32_EXECUTABLE false)
    endif ()
    

    In that way the terminal is not opened together with the GUI, but there is another problem that here when I start the app from the terminal with options the output is not printed in the terminal but in a popup dialog box.

    main.cpp

    int main(int argc, char *argv[])
    {
        bool hasUi = false;
        if (argc > 1) {
            hasUi = false;
        } else {
            hasUi = true;
        }
    
        if (hasUi) {
            QGuiApplication guiApp(argc, argv);
            QQmlApplicationEngine engine;
            GuiConext guiContext;
    
            auto rootContext = engine.rootContext();
            rootContext->setContextProperty("Gui", &guiContext);
    
            // This adds the QML library that is used for the GUI.
            engine.addImportPath(QString("qrc:/"));
            MaterialPlugin materialPlugin;
            materialPlugin.registerTypes("Material");
    
            engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
            return guiApp.exec();
        } else {
            // The application runs as terminal app.
            QCoreApplication coreApp(argc, argv);
            int status = 0;
    
    //The following is because there is a need for EventLoop to be executed in the console application.
            QTimer::singleShot(0, [&]()
            {
                {
                    TerminalRunner runner(&coreApp);
    
                    if (!runner.setUpPtcManager()) {
                        status = 1;
                        coreApp.exit(status);
                        return;
                    }
    
                    runner.uploadConfiguration();
                }
                coreApp.exit(status);
            });
            return coreApp.exec();
        }
    }
    

  • Lifetime Qt Champion

    @Rufledore said in Same application executed as console app or QML GUI:

    //The following is because there is a need for EventLoop to be executed in the console application.

    Why? return coreApp.exec(); starts the event loop.

    "the output is not printed in the terminal but in a popup dialog box." - what output and how do you output it?



  • Why? return coreApp.exec(); starts the event loop.

    coreApp.exec() is called in the end of the main function but I need some things to be executed after the event loop is started and that's my way.

    The console output is printed with std::cout.
    Please stick to the topic. Do you have any idea how to help me?



  • @Rufledore said in Same application executed as console app or QML GUI:

    Please stick to the topic. Do you have any idea how to help me?

    He is trying to help you.


  • Lifetime Qt Champion

    @Rufledore said in Same application executed as console app or QML GUI:

    Please stick to the topic

    Where was I off-topic?
    Also, pointing to issues not related to original question isn't a bad thing in my opinion. I always appreciate if others point out issues in my code even if not related to original question.

    OK, what you are doing with the timer is fine.

    I don't see how std::cout output would end-up in a dialog box, unless you implement it by yourself.
    Without seeing the code I can't tell more.



  • @Rufledore said in Same application executed as console app or QML GUI:

    Please stick to the topic. Do you have any idea how to help me?

    Please take time to understand the question asked.
    In your code there is a strange comment: The following is because there is a need for EventLoop to be executed in the console application.

    But, as @jsulm already has written, calling coreApp.exec() will already start an eventloop.

    You code don't made sense:
    Simple change you code to something like this:

    // The application runs as terminal app.
    QCoreApplication coreApp(argc, argv);
    int status = 0;
    
    TerminalRunner runner(&coreApp);
    
    // stop application when runner is done
    QObject::connect(&runner, &TerminalRunner::done, &coreApp, &QCoreApplication::quit);
    // call TerminalRunner start slot asap
    QTimer::singleShot(0, &runner, &TerminalRunner::start);
    
    // start event loop and wait until finished
    return coreApp.exec();
    

    Note: I suppose here that your TerminalRunner class has a signal called done() which is emitted when all is done and a slot called start() which has to be called to start processing.



  • @jsulm said in Same application executed as console app or QML GUI:

    I don't see how std::cout output would end-up in a dialog box, unless you implement it by yourself.
    Without seeing the code I can't tell more.

    Like that: Capture.PNG

    With WIN32_EXECUTABLE false it is like that: Capture.PNG



  • @Rufledore said in Same application executed as console app or QML GUI:

    set_property(TARGET Ptc05Manager PROPERTY WIN32_EXECUTABLE true)

    This is to force the creation of a Windows application without console.
    So what did you expect what happen when using this?



  • @KroMignon said in Same application executed as console app or QML GUI:

    So what did you expect what happen when using this?

    I would like to have an app that executes as a console application when it is started with parameters and as a GUI when it is started without parameters e.g. the icon or in console. Everything works fine usually except the fact that when I start the GUI from the icon a console is opened too and I don't wont that to happen. The solution that I found was to set WIN32_EXECUTABLE to true, but that stops the console app behavior. So, I would like to find a working solution.



  • @Rufledore said in Same application executed as console app or QML GUI:

    The solution that I found was to set WIN32_EXECUTABLE to true, but that stops the console app behavior. So, I would like to find a working solution.

    This is not the solution, is will only allow/disable the Windows application to create a Console.
    If there is not console, there will be a Window which will be created to show the stdout message.

    You can hide console on application startup with something like this:

    HWND hWnd = GetConsoleWindow();
    ShowWindow( hWnd, SW_HIDE );
    

    Of course, this only works for Windows



  • Windows does not support the same application to be both a console and a GUI app. The major problem is that a GUI application should not have an attached console and a console application should use an existing console when started from the command line instead of opening a new one. This is not possible on Windows.

    Here is the next best thing you can do on Windows (I have read that Microsoft's own devenv command does it this way): Compile your application both as .exe (GUI application) and .com (console/command line application). This can be done from the same source code if you use a few #ifdef's. If you have a myapp.exe and a myapp.com and type myapp (without the file extension) on the command line, Windows will do the right thing. In our own application we provided an option to specify you want the GUI. If the console app was started with the GUI option it will just use QProcess to launch the GUI version and exit.

    Here is a short snippet with the most important information how we do it:

    // Windows header
    #include <windows.h>
    #include <consoleapi.h>
    
    #ifdef _MSC_VER
    #pragma warning(push)
    #pragma warning(disable : 4100)     // false warning of unused parameter 'a'
    #endif
    void startGui(QApplication &a)
    {
        QString currentDir = QDir::currentPath();
        QStringList arguments = a.arguments();
        arguments.removeFirst();
        QDir::setCurrent(QCoreApplication::applicationDirPath());
        QProcess::startDetached(QFileInfo(QCoreApplication::applicationFilePath()).completeBaseName() + ".exe",
                                arguments, currentDir);
    }
    #ifdef _MSC_VER
    #pragma warning(pop)
    #endif
    
    void openConsole()
    {
        AllocConsole();
        std::freopen( "CON", "w", stdout );
        std::freopen( "CON", "w", stderr );
        std::freopen( "CON", "r", stdin );
    }
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        CommandLineArgs args = parseCommandLine(a);
    
    #ifdef CONSOLE_APP
        if(args.gui)
        {
            startGui(a);
            return 0;
        }
    #else
        if(args.gui)
        {
            QString filename;
    
            Dialog w(filename);
            w.show();
            return a.exec();
        }
    
        openConsole();
    #endif
    
        return processWithArgs(args);
    }
    

    The difference is that we don't have an event loop when run as a pure console application.


Log in to reply