QTextEdit and "carriage-return" / "\r" character



  • I am using a (multi-line, scrollable) QTextEdit widget to display the grabbed output from a QProcess in real-time.

    One process deliberately embeds a \r (carriage-return) characters in its output --- it's outputting a "progress" something like:

    10%\r20%\r30% ...
    

    This is a common thing for command-line programs to do: in a terminal this avoids occupying multiple lines because the \r jumps back to the start of the current line and overwrites what's there.

    When I blindly send this raw output --- along with everything else --- to QTextEdit::append() the user sees multiple lines instead, making the output look voluminous.

    [EDIT: Hmm, it's a bit confusing. What I actually seem to see is an extra blank line between items, like:

    10
    
    20
    
    30
    

    ]

    • I take it that QTextEdit is not going to handle \r by returning to the start of a line, right?
    • If I want the "nice" behaviour, I would have to do shenanigans along the lines of parsing the output, locating the \rs, and then not just simply appending but rather actually replacing the previous last line which was added, right?
    • Assuming that would be required, it's more code than it's worth. The best might be to blindly remove any \rs before sending to QTextEdit: I wouldn't get the "overwrite" behaviour, I'd get one great long line, but that might be preferable to multiple lines for the user in the output, right?


  • @JNBarchan i think you get an empty line as \r is translated to \n in QTextEdit. append() itself adds another line break.

    the easiest way would be QString::trimmed() before appending.

    if you like to simulate carriage return, you would need to replace the last line instead appending if your line contains \r (you would remove the \r nevertheless). not sure how fluent that would look, though.



  • @aha_1980

    append() itself adds another line break.

    Hmm, where's that documented?** Because I'm receiving "chunks" of output from the subprocess, I want to add exactly what I get from there without extra newlines etc. Is there any different between QTextEdit.append(newStuff) versus QTextEdit.setText(QTextEdit().getText() + newStuff) in this "another line break" respect?

    ** EDIT: OK, I'm seeing the documentation for QTextEdit.append() is talking about "paragraphs" and things. I had not intended that: I just want the quickest way to append some new text to whatever is there exactly. I can now see that QTextEdit.setPlainText(QTextEdit().toPlainText() + newStuff) is getting rid of unwanted blank lines (that's good, though it looks "inefficient"?).

    the easiest way would be QString::trimmed() before appending.

    Does me no good. Because I get "chunks of output" as a single string (byte array actually), the \rs are embedded all over the place in the middle of stuff. That's why I'd have to scan the string to do my work. At the moment I've just put in str.replace("\r", ""), and now at least I'm not getting the blank lines.

    if you like to simulate carriage return, you would need to replace the last line instead appending if your line contains \r (you would remove the \r nevertheless). not sure how fluent that would look, though.

    Yes, and that would mean looking at my existing content to determine where "the last line" starts, and recognising multiple lines with \r in them in what is to be "appended", and I can't be bothered with the whole thing!



  • @JNBarchan said in QTextEdit and "carriage-return" / "\r" character:

    @aha_1980

    append() itself adds another line break.

    Hmm, where's that documented?

    http://doc.qt.io/qt-5/qtextedit.html#append :
    Appends a new paragraph with text to the end of the text edit.

    Because I'm receiving "chunks" of output from the subprocess, I want to add exactly what I get from there without extra newlines etc.

    Understand.

    Is there any different between QTextEdit.append(newStuff) versus QTextEdit.setText(QTextEdit().getText() + newStuff) in this "another line break" respect? I guess QTextEdit.append(newStuff) would be something like QTextEdit.setText(QTextEdit().getText() + '\n' + newStuff)

    You could try http://doc.qt.io/qt-5/qtextedit.html#insertPlainText . It might be faster than calling setText() all over again. Thats also what QtCreator does in the Application and Compile Output windows.

    the easiest way would be QString::trimmed() before appending.

    Does me no good. Because I get "chunks of output" as a single string (byte array actually), the \rs are embedded all over the place in the middle of stuff.

    Ok, yes in that case trimmed() is not enough.

    That's why I'd have to scan the string to do my work. At the moment I've just put in str.replace("\r", ""), and now at least I'm not getting the blank lines.

    If you want a simple solution, than you could stick with this.



  • @aha_1980

    http://doc.qt.io/qt-5/qtextedit.html#append :
    Appends a new paragraph with text to the end of the text edit.

    You could try http://doc.qt.io/qt-5/qtextedit.html#insertPlainText . It might be faster than calling setText() all over again

    Yes, I had put an EDIT into my post as I came to realise these. It turns out most of the "ugliness" was actually due to blank line from each append(). Now with setText() always instead, it doesn't look too bad.

    Qt doesn't offer any "raw" append? In native Windows (and maybe HTML/JS too), when I want to append like this I go something like "caret to end" and then "insert characters". I assume that helps with scroll smoothness/no redraw, whereas setText() is going to rewrite the whole control each time? Since I'm gathering external output, there could be like a megabyte there and I just get one more line at a time to append....

    I've decided now to just leave any \rs in the output as-is. They go to next line, but removing them just results in a very long line anyway, so it's a matter of opinion either way. It leaves my code more generic & simple.



  • I have noticed this behavior. The append(...) option will add a line break but insert(...) will not. I would go with inset(...) unless you are processing the text to manually separate all appends calls to separate lines of text. QString::split('/r'); will work nicely to separate into individual lines.

    If you use the insert(...) option you need to make sure the cursor at the end otherwise the new text could appear in the middle of the document. A simple mouse click will move the insert position.

    Reading back all the text, adding new text, then calling setText(...) doesn't sound efficient.



  • @Rondog
    Ah, OK, I simply had not noticed there is a QTextEdit::insertPlainText(). I had seen QTextEdit::setText() & QTextEdit::append(). I'm familiar with having to position the cursor for appending with insert. I see QTextEdit::moveCursor().

    This sounds like I'd expect instead of resetting whole text! Thanks.



  • @Rondog
    I have now simply set my append code to:

        # append further text at the end, efficiently
        self.text.moveCursor(QtGui.QTextCursor.End)
        self.text.insertPlainText(moreText)
    

    This also seems to scroll to the end for me, avoiding the need for me to explicitly call set the vertical scrollbar's position.

    Sometimes it scrolls to end, but not always. Since I want scroll-to-end (and the widget is read-only, so no visible cursor), I have appended:

        sb = self.text.verticalScrollBar()
        sb.setValue(sb.maximum())
    ``
    
    Thanks to all.

Log in to reply
 

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