QProcess - unexpected behaviour with execute()



  • Hello everyone,

    I am facing a very strange problem.
    I am trying to execute external program using QProcess, but QProcess::start() returns wrong result and QProcess::execute() returns the result in a way which cannot be captured.

    What I am doing is a Linux console application which will be working with long lines of text. I want to be able to cut the text at the end of each line, thus showing one result per line. In order to do this, I need to get the size of the terminal window. I don't know and I couldn't find better ways to do that then to use "tput":http://en.wikipedia.org/wiki/Tput

    I tried having QProcess both on the stack and on the heap, using both start and execute. Here is what I am currently trying:

    In the constructor:

    @
    proc = new QProcess(this);
    proc->setProcessChannelMode(QProcess::MergedChannels);
    proc->setEnvironment(QProcess::systemEnvironment());

    connect( proc, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChanged(QProcess::ProcessState)));
    

    @

    and then later in the execution:
    @
    proc->execute("tput cols");
    connect( proc, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadScreenWidth()));
    proc->waitForFinished(-1);
    proc->close();
    disconnect( proc, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadScreenWidth()));
    @

    I am using disconnect because I am using the same QProcess object for the height as well, which looks pretty much the same. I know I could use the QObject::sender() method, but I don't think that's the problem.

    @
    void base::readyReadScreenWidth()
    {
    QByteArray data = proc->readAllStandardOutput();
    qDebug() << "width:" << data;
    width = data.trimmed().toInt();
    }
    @

    Now, the strange thing is - when I use execute, it returns the correct resolution of the terminal window, however it just spits it out in the terminal, not comming on the object "proc" stdout or stderr. If I use the start method instead, the result I get is wrong - even if I resize the window, it'll keep showing me width 80 and height 24.

    I am currently compiling on a CentOS 5.4 virtual machine because I want to avoid compatibility issues if I need to run my application on different boxes (and I know for sure that the oldest one which I will need to run this on is a CentOS 5.4 box). I am using Qt 4.8.6, however the same QProcess code resides in 5.3.2 as well.

    What I mean is the following, located in qprocess.cpp in the sources:
    @
    int QProcess::execute(const QString &program, const QStringList &arguments)
    {
    QProcess process;
    process.setReadChannelMode(ForwardedChannels);
    process.start(program, arguments);
    if (!process.waitForFinished(-1))
    return -2;
    return process.exitStatus() == QProcess::NormalExit ? process.exitCode() : -1;
    }
    @

    What that method does is creating another instance of the class QProcess to which it passes the program name and arguments and sets that stderr and stdout are merged and sent to it. It waits for the process to finish, but does NOT take care of the output. At the end of the method, that instance just goes out of scope and thus destroyed. And that is why I get the output to the terminal, but not back in my application. I don't know if that is intended behaviour, but it certainly is not helpful....

    I am puzzled as to why using start() returns 80x24 as well, I can only imagine that this geometry is somehow hard coded (as a default size for terminal applications?). Can someone more into Qt confirm please?

    Can someone tell me if there is any bether way of doing what I am trying to achieve? I would like to use the Qt way of doing things, don't want to resort to pure c/c++ methods like popen.



  • Seriously guys, did nobody had such problem before??
    It's quite weird....


  • Lifetime Qt Champion

    Hi,

    It's not really hardcoded (in a sense), it's the default used by your system (technically for all *nix 80x24). If you change it, you should see the new value instead.



  • Hi and thanks for the response.

    Indeed I didn't thought that probably these numbers are the defaults for the linux boxes. 80x24 seems pretty low nowdays, not sure why would linux devs keep going at it. Still, as I mentioned in my post, execute() cannot be used as it returns the exit status only and start() returns wrong result, at least within my project and test case.
    I couldn't find a workaround, so I ended up using "popen" instead, but I would really like to use QProcess or whatever else may be relevant and considered to be the Qt way.

    If you can see a flaw in what I tried, or if you can suggest another way of actually clearing the screen in a console application, I would be most grateful. My project is pretty much on hold for now with one of the reasons being the problem with clearing the screen (which also flickers during these updates, so I can't do them too often :( )


  • Lifetime Qt Champion

    Maybe low, but compatible with current and older devices and also if you don't have a graphic server. And don't forget python :)

    Anyway, can you explain what your application should exactly do ?



  • I am trying to build an application which updates the screen every second (or twice every second) with information which it reads from a resource - file, socket, anything. Pretty much sort of a monitoring of live stats (like mytop, (h)top, etc). What I couldn't do is clear the screen in a way it wouldn't flicker and also get the size of the terminal. What I used is the linux "tput" command and was trying to execute it with QProcess::execute or QProcess::start.

    Is there anything in Qt which I couldn't find that would provide me with information about the terminal size and also is there anything in Qt which would allow me to clear the terminal without executing external application? If not, how can I do this with QProcess, since it doesn't work correctly, as I described in my first post.



  • I am trying to build an application which updates the screen every second (or twice every second) with information which it reads from a resource - file, socket, anything. Pretty much sort of a monitoring of live stats (like mytop, (h)top, etc). What I couldn't do is clear the screen in a way it wouldn't flicker and also get the size of the terminal. What I used is the linux "tput" command and was trying to execute it with QProcess::execute or QProcess::start.

    Is there anything in Qt which I couldn't find that would provide me with information about the terminal size and also is there anything in Qt which would allow me to clear the terminal without executing external application? If not, how can I do this with QProcess, since it doesn't work correctly, as I described in my first post.


  • Lifetime Qt Champion

    Something 's not clear, is it a console application (QCoreApplication) Or do you want to show your content in a console from your GUI ?


  • Lifetime Qt Champion

    Something 's not clear, is it a console application (QCoreApplication) Or do you want to show your content in a console from your GUI ?



  • Ugh, sorry for the late response, been busy with work and didn't do much about that project.

    Yes, it's a QCoreApplication, it's application which is supposed to output stuff into the terminal once started. What I am trying to do is call external application to clean the terminal window of previous text and replace it with new one. Was just surprised by QProcess behaviour and was looking for a more Qt way then using popen(). When I use the external application (called "tput"), I kind of get the behaviour I want, but it gives it sort of a flickering, which makes me think what I use is not quite optimal.....



  • Ugh, sorry for the late response, been busy with work and didn't do much about that project.

    Yes, it's a QCoreApplication, it's application which is supposed to output stuff into the terminal once started. What I am trying to do is call external application to clean the terminal window of previous text and replace it with new one. Was just surprised by QProcess behaviour and was looking for a more Qt way then using popen(). When I use the external application (called "tput"), I kind of get the behaviour I want, but it gives it sort of a flickering, which makes me think what I use is not quite optimal.....


Log in to reply
 

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