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.
Any suggestions?
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).