1

I have a QTextBrowser widget and I'm adding text to this widget like

QTextBrowser m_outputLog;
...
void MainWindow::readStdout()
{
  if (m_running)
  {
    QByteArray data = m_runProcess->readAllStandardOutput();
    QString text = QString::fromUtf8(data);
    if (!text.isEmpty())
    {
      m_outputLog->moveCursor (QTextCursor::End);
      m_outputLog->insertPlainText (text);
      m_outputLog->moveCursor (QTextCursor::End);
    }
  }
}

the readStdout is connected to the m_outputLog through the signal / slot mechanism. This all works OK. The text is appended at the end though the disadvantage is that with each insertion there is a jump back to the end even when I did scroll up a bit. When I remove the m_outputLog->moveCursor (QTextCursor::End); statements the text is still nicely appended at the end but there is no automatic show of the text, I always have to use the mouse to scroll down.

  • how can I put the text at the end
  • automatically show the new text when the end of the text was already shown
  • stay at the scroll position when I used the mouse to scroll through the text

Any suggestions?

albert
  • 8,285
  • 3
  • 19
  • 32

1 Answers1

2

Here is what I have done for my own need:

void appendLogMessage(const QString& message)
{
    QScrollBar vbar = verticalScrollBar();

    // analyze cursor and scrollbar positions
    const QTextCursor old_cursor = textCursor();
    const bool is_scrolled_down = vbar->value() == vbar->minimum();
    const int distanceFromBottom = vbar->maximum() - vbar->value();

    // move the cursor to the begining of the document.
    moveCursor(QTextCursor::Start);

    // adding new text
    textCursor().insertPlainText(message);

    if (old_cursor.hasSelection() || !is_scrolled_down)
    {
        // text is selected or scrollbar is not anymore at the bottom: maintain position.
        setTextCursor(old_cursor);
        vbar->setValue(vbar->maximum() - distanceFromBottom);
    }
    else
    {
        // no text is selected and the scrollbar is at the top: scroll to the top.
        moveCursor(QTextCursor::Start);
        vbar->setValue(verticalScrollBar()->minimum());
    }
}

Basically, you need to save the scrollbar position before adding the new text, and then decide to move back the scrollbar to this position depending on your own criteria (for example, I decided not to move the scrollbar only if the user has selected some text).

Pamputt
  • 173
  • 1
  • 11
  • This looks very promising, only problem I have is that it adds the text at the top and not at the bottom, but I think this should be easily "corrected" by means of positioning the cursor at the right place and doing something with minimum and maximum. – albert Jun 08 '23 at 10:04
  • I got the message that `textCursor` doesn't have a method `insertPaintText`, so I replaced it by a plain `insertPlainText`. Might be a difference between the used Qt versions (I use Qt 5.14) – albert Jun 08 '23 at 10:06
  • 1
    `insertPaintText` was a typo. I will fix it – Pamputt Jun 08 '23 at 10:24
  • I get now 'insertPlainText': is not a member of 'QTextCursor', looks like it should not be `textCursor().insertPlainText(message);` but `insertPlainText(message);` (at least for me). – albert Jun 08 '23 at 10:28
  • 1
    Indeed, you may need to adapt a bit the code because my class is derived from `QPlainTextEdit` (not from `QTextBrowser`) but the philosophy remains the same. – Pamputt Jun 08 '23 at 10:43