Main window GUI freeze and did not show the command prompt



  • #include "mainwindow.h"
    #include <QApplication>
    #include <iostream>
    #include <Windows.h>
    #include <string>
    #include <QByteArray>
    #include <QProcess>
    #include <cstdlib>
    #include <stdlib.h>
    
    
    using namespace std;
    
    
    int main(int argc, char *argv[])
    {
    
        QApplication a(argc,argv);
         MainWindow w;
          w.show();
    
        QProcess cmd;
        cmd.start("cmd");
        if(!cmd.waitForStarted())
            return false;
        cmd.waitForReadyRead();
        QByteArray result = cmd.readAll();
        cout<<result.data();
    
        string str;
        getline(cin,str);
    
          while(str != string("exit"))
          {
              cmd.write(str.c_str());
              cmd.write("\n");
              cmd.waitForReadyRead();
              result = cmd.readAll();
              cout << result.data();
              getline(cin,str);
          }
    
        return a.exec();
    
    }
    above code is from mainwindow.cpp
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QByteArray>
    #include <QProcess>
    #include <Windows.h>
    #include <iostream>
    #include <string>
    #include <cstdlib>
    #include <stdlib.h>
    
    using namespace std;
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    above code is from main.cpp
    

    I wanted to display the GUI window and command prompt and the same time.The command prompt will be interacting with GUI window . Above codes will give you no error when you compile and build them . Everything is fine until you try to run the project, the GUI window pop out , the command prompt did not pop out and the GUI window freeze. Am i doing the right way? Any help will be appreciated !


  • Qt Champions 2017

    Hi and welcome
    Im not sure you can do it this way as the "shell" wont be interactive as far as I could test.
    Also this statement
    while(str != string("exit"))
    will make infinite loop
    killing the event loop and stop GUI from responding. ( the freezing)

    I have only been able to create such "console" for a gui program using native windows calls
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms682528(v=vs.85).aspx



  • @QT_QT_QT said:

    QApplication a(argc,argv);
    MainWindow w;
    w.show();

    ......

    return a.exec();

    You should understand that until a.exec is executed application event loop is not running.
    and it will not be called until you exit your while loop.
    as pointed by @mrjj


  • Qt Champions 2017

    @QT_QT_QT

    Everything is fine until you try to run the project, the GUI window pop out , the command prompt did not pop out.

    If you run it withing Qt Creator, you should check the "run in terminal" checkbox in the run configuration of your project.

    and the GUI window freeze

    The command prompt is a "view" of three special files: the standard input, output and the standard error streams. So you can do it as you'd do it for any other file. As file IO operations are inherently blocking there are three approaches to this.

    First approach:
    Thread the file reading/writing. Leaving aside the question of how to spawn a thread and manage it (there are a lot of questions and answers how that's done floating about the forum), you can read the standard streams Qt-style like this:

    QTextStream in(stdin);      //< Standard input
    QTextStream out(stdout); //< Standard output
    QTextStream err(stderr);  //< Standard error
    

    Then in the worker thread you can do reading/writing with the streams. However, this is lacking because the reading/writing is blocking and you have no way to gracefully shut-down the thread. To work around this you can attach a QFile instance to an existing file descriptor (by calling QFile::open) and then wait with some timeout with QIODevice::waitForReadyRead for new data to be made available for reading. Reading the data itself can be again done with the stream operators, so as an example:

    QFile stdInFile;
    if (!stdInFile.open(stdin, QIODevice::ReadOnly | QIODevice::Text))
        ; //< Can't open the standard input for reading (handle the error appropriately)
    
    QTextStream in(&stdInFile); //< Convenience for reading
    
    // > The following code polls the device in a dedicated thread
    while (true)  {
        //< Here the appropriate code for exiting the thread should put (this can be done also without the loop, but by scheduling reads through the thread's event loop instead - the preferred method)
        if (stdInFile.waitForReadyRead(300))
            ; //< There's something to read, so read it with the QTextStream instance
    }
    

    Second approach:
    If you don't want to start a new thread and poll the device as in the example above, you can use a QSocketNotifier which allows you to monitor a file. Note, however, I don't know if this works on windows. The notifier will fire activated signals when there's something to be done with the file (reading it for example).

    Third approach
    This is probably the simplest. You can open the streams as above and connect your code to the readyRead signal.

    QFile stdInFile;
    if (!stdInFile.open(stdin, QIODevice::ReadOnly | QIODevice::Text))
        ; //< Can't open the standard input for reading (handle the error appropriately)
    
    QObject::connect(&stdInFile, SIGNAL(readyRead()), myObjectHandlingReading, SLOT(readCommandPrompt()));
    

    EDIT:
    I've added the third alternative.

    Kind regards.



  • @mrjj
    Hello there, thank you for the response. Regarding to the creation of console, I have tried to implement this before, the GUI window and an empty console pop out. However, an empty console wont allowed you to type in any command prompt command such as ipconfig, mkdir and so no. Basically , an empty console is for debugging purposes. I want my program to able to parse a string to cmd . If the end-users wish to know what is the ip address of his or her computer, the end-user going to push a button , and from there, the program it self will send or parse a string to command prompt, eg "ipconfig" . Do you have any suggestion on solving this kind of problem ? FYI, i also modified some of my codes, the gui window is not freezing anymore, but only pop out for like 1 second and then the command prompt window pop out . Feel free to take a look of my code .

     QProcess cmd;
        cmd.startDetached("cmd");
        if(!cmd.waitForStarted())
            return false;
        cmd.waitForReadyRead();
        QByteArray result = cmd.readAll();
        cout<<result.data();
    
        string str;
        getline(cin,str);
    
          while(str != string("exit"))
          {
              cmd.write(str.c_str());
              cmd.write("\n");
              cmd.waitForReadyRead();
              result = cmd.readAll();
              cout << result.data();
              getline(cin,str);
          }
    
    *instead of start("cmd") , I changed to startDetached("cmd")
    

  • Moderators

    @QT_QT_QT You still have a blocking loop before calling a.exec()!
    If you want to execute external commands like ipconfig you can do it with QProcess:

    QProcess cmd;
    cmd.startDetached("ipconfig");
    

    There is no need to start CMD first.



  • Thank you all for the solution that provided by you guys, because of your help, i managed to solved my problem. Right now , i m able to "call out" command prompt and GUI window at the same time. I modified some of the codes in order to "call out" those 2 windows.

    ***mainwindow.cpp***
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QByteArray>
    #include <QProcess>
    #include <Windows.h>
    #include <iostream>
    #include <string>
    #include <cstdlib>
    #include <stdlib.h>
    
    using namespace std;
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    
    {
        ui->setupUi(this);
    
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    void MainWindow::on_pushButton_clicked()
    {
    
    /*
        QProcess process(this);
        process.startDetached("ipconfig");
        process.waitForFinished();
    */
    
    }
    
    
    ***main.cpp***
    
    #include "mainwindow.h"
    #include <QApplication>
    #include <iostream>
    #include <Windows.h>
    #include <string>
    #include <QByteArray>
    #include <QProcess>
    #include <cstdlib>
    #include <stdlib.h>
    
    using namespace std;
     bool check = false;
    
    int main(int argc, char *argv[])
    {QApplication a(argc,argv);
    
         MainWindow w;
         w.show();
    
         QProcess process;
         process.startDetached("cmd");
         process.waitForFinished();
    
       return a.exec();
    
    
    }
    
    

    Right now , i can move into next task . My next task is to parse some string into cmd. Lets assume the GUI window has a push button , there is a string that included within the push button . So when the end-user click the push button , the push button will parse the string into cmd. Example: I set this text "mkdir emptyFolder" to the push button , after that, the push button will parse or "send" this string "mkdir emptyProject" into cmd. Anyone here know what is the best way to approach this kind of problem. Thank you in advance!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.