Creating QT Application as GUI for existing console-based application on windows

前端 未结 2 2069
日久生厌
日久生厌 2020-12-06 15:25

i\'m trying to set up a GUI with Qt for an existing application which is meant to be run in the windows commandline. It\'s not just running the app with the system()<

2条回答
  •  独厮守ぢ
    2020-12-06 16:22

    Out of curiosity, I played around with QProcess.

    I'm really impressed how easy and straight forward everything works (remembering with horror how difficult it was when we did it in the past without Qt).

    Thus, I can provide my little rather MCVE for demonstration.

    First I made a simple console application testQProcessIOChild.cc:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    // inspired by:
    // https://try.kotlinlang.org/#/Examples/Longer%20examples/99%20Bottles%20of%20Beer/99%20Bottles%20of%20Beer.kt
    string bottlesOfBeer(int n)
    {
      switch (n) {
        case 0: return "no more bottles of beer";
        case 1: return "1 bottle of beer";
        default: {
          ostringstream outFmt;
          outFmt << n << "  bottles of beer";
          return outFmt.str();
        }
      }
    }
    
    int main()
    {
      enum { delay = 1000 };
      for (int n;;) {
        cout << "Initial number of bottles (-1 ... finish): " << flush;
        if (!(cin >> n)) {
          cerr << "Input error!" << endl;
          continue;
        }
        if (n < -1) {
          cerr << "Illegal input!" << endl;
          continue;
        }
        if (n < 0) break;
        if (n > 100) {
          cerr << "The ministry of health warns:" << endl
            << " Abuse of alcoholics may damage your health." << endl;
          n = 99;
        }
        cout << "Go to the store and buy some more, "
          << bottlesOfBeer(n) << " on the wall." << endl;
        while (n) {
          this_thread::sleep_for(chrono::milliseconds(delay));
          cout << bottlesOfBeer(n) << " on the wall, "
            << bottlesOfBeer(n) << '.' << endl
            << "Take one down, pass it around, ";
          --n;
          cout << bottlesOfBeer(n) << " on the wall." << endl;
        }
        this_thread::sleep_for(chrono::milliseconds(delay));
        cout << "No more bottles of beer on the wall, no more bottles of beer."
          << endl;
      }
      return 0;
    }
    

    I did this to have something which provides:

    • usage of standard input
    • usage of standard output
    • usage of standard error
    • certain specific time consuming behavior (to see whether and when the parent process reacts).

    Second I made the Qt GUI application testQProcessIO.cc as wrapper:

    // Qt header:
    #include 
    
    const char *childProgram = "./testQProcessIOChild";
    
    int main(int argc, char **argv)
    {
      qDebug() << QT_VERSION_STR;
      // main application
      QApplication app(argc, argv);
      QProcess qProcessChild;
      // GUI setup
      QWidget qWin;
      QGridLayout qGrid;
      QPushButton qBtnStart(QString::fromUtf8("Start"));
      qGrid.addWidget(&qBtnStart, 0, 0);
      QPushButton qBtnStop(QString::fromUtf8("Stop"));
      qBtnStop.setEnabled(false);
      qGrid.addWidget(&qBtnStop, 0, 1);
      QLabel qLblInput(QString::fromUtf8("Input: "));
      qLblInput.setEnabled(false);
      qGrid.addWidget(&qLblInput, 0, 2);
      QLineEdit qInput;
      qInput.setEnabled(false);
      qGrid.addWidget(&qInput, 0, 3);
      QTextEdit qTxtLog;
      qTxtLog.setReadOnly(true);
      qGrid.addWidget(&qTxtLog, 1, 0, 1, 4);
      qGrid.setRowStretch(1, 1);
      qGrid.setColumnStretch(3, 1);
      qWin.setLayout(&qGrid);
      qWin.show();
      // install signal handlers
      QObject::connect(&qBtnStart, &QPushButton::clicked,
        [&](bool) {
          qProcessChild.start(QString::fromLatin1(childProgram));
        });
      QObject::connect(&qBtnStop, &QPushButton::clicked,
        [&](bool) {
          qProcessChild.kill();
        });
      QObject::connect(&qInput, &QLineEdit::returnPressed,
        [&](){
          QString text = qInput.text() + '\n';
          qProcessChild.write(text.toLatin1());
        });
      QObject::connect(&qProcessChild, &QProcess::started,
        [&]() {
          qBtnStart.setEnabled(false);
          qBtnStop.setEnabled(true);
          qLblInput.setEnabled(true);
          qInput.setEnabled(true);
        });
      QObject::connect(&qProcessChild,
        // cast needed because QProcess::finished() is polymorph
        (void(QProcess::*)(int))&QProcess::finished,
        [&](int) {
          qBtnStart.setEnabled(true);
          qBtnStop.setEnabled(false);
          qLblInput.setEnabled(false);
          qInput.setEnabled(false);
          qTxtLog.clear();
        });
      QObject::connect(&qProcessChild, &QProcess::readyReadStandardOutput,
        [&]() {
          qTxtLog.append(qProcessChild.readAllStandardOutput());
        });
      QObject::connect(&qProcessChild, &QProcess::readyReadStandardError,
        [&]() {
          qTxtLog.append(qProcessChild.readAllStandardError());
        });
      // run application
      return app.exec();
    }
    

    I compiled and tested this with VS2013 and Qt 5.9.2 on Windows 10 (64 bit).

    To illustrate the test session I wrote a QMake project afterwards testQProcessIO.pro:

    SOURCES = testQProcessIO.cc
    
    QT += widgets
    

    and compiled and tested on cygwin again:

    $ g++ -std=c++11 -o testQProcessIOChild testQProcessIOChild.cc 
    
    $ ./testQProcessIOChild 
    Initial number of bottles (-1 ... finish): -1
    
    $ qmake-qt5 testQProcessIO.pro
    
    $ make
    g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQProcessIO.o testQProcessIO.cc
    g++  -o testQProcessIO.exe testQProcessIO.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 
    
    $ ./testQProcessIO
    5.9.2
    
    $
    

    Snapshots of my test sessions:

      

提交回复
热议问题