Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent a QTextEdit widget from scrolling when there is a selection

I've researched this extensively but haven't found a satisfactory solution yet:

How do I append text at the end of QTextEdit widget without triggering a scroll to the bottom of the widget when either of these conditions is met:

  • The user has selected some text.
  • The user has scrolled away from the bottom.

(In all other cases, a scroll to the bottom of the QTextEdit widget should be triggered.)

Here is the code I'm currently using to append text at the bottom of a QTextEdit widget:

const QTextCursor old_cursor = widget.textCursor();

widget.moveCursor(QTextCursor::End);
widget.textCursor().insertText(text);

if (old_cursor.hasSelection())
    widget.setTextCursor(old_cursor);
else widget.moveCursor(QTextCursor::End);

This partially takes care of condition 1: the problem is that the view will still scroll until only the last line of the selection is visible, at which point it will indeed stop scrolling.

Condition 2 is not taken care of at all: some posts suggest to save the position of the vertical scrollbar and restore it after the text was appended, however I don't think this is correct since the scrollbar should move upward when text is appended, even though the view stays still.

Note that I'm using QTextCursor::insertText() instead of QTextEdit::append() because I need to adjust the color of the text being appended, regardless of whether the user has selected text or not.


Update: Here is the code I ended up with, thanks to Pavel's answer:

const QTextCursor old_cursor = widget.textCursor();
const int old_scrollbar_value = widget.verticalScrollBar()->value();
const bool is_scrolled_down = old_scrollbar_value == widget.verticalScrollBar()->maximum();

// Move the cursor to the end of the document.
widget.moveCursor(QTextCursor::End);

// Insert the text at the position of the cursor (which is the end of the document).
widget.textCursor().insertText(text);

if (old_cursor.hasSelection() || !is_scrolled_down)
{
    // The user has selected text or scrolled away from the bottom: maintain position.
    widget.setTextCursor(old_cursor);
    widget.verticalScrollBar()->setValue(old_scrollbar_value);
}
else
{
    // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom.
    widget.moveCursor(QTextCursor::End);
    widget.verticalScrollBar()->setValue(verticalScrollBar()->maximum());
}
like image 559
François Beaune Avatar asked Feb 22 '14 14:02

François Beaune


People also ask

How do you scroll down in qtextedit?

QTextEdit: scroll down automatically only if the scrollbar is at the bottom. There's a QTextEdit that displays quite a lot of text. It is NOT editable. Suppose I want to read something around the beginning, scroll up, but then a new line is added and the scrollbar automatically goes to the bottom.

Is it possible to add qscrollbar as a child to qtextedit?

method. But result was exactly the same as with a default scroll bar - scroll bar is still dependent from the text. In the end I added the QScrollBar as a child to QTextEdit like this : , but I have to synchronize scroll bar size and position with parent widget manually, and it's bad.

Does scrollbar size depend on qtextedit content?

, is such , that from one hand does not depend from the QTextEdit content , and from the other hand depend from its size. ( I've tried to put my scroll bar into internal QTextEdit layout , but I can't get access to it. ) Thanks.

How do I set a selection in qtextedit?

If you want to set a selection in QTextEdit just create one on a QTextCursor object and then make that cursor the visible cursor using setTextCursor () . The selection can be copied to the clipboard with copy () , or cut to the clipboard with cut () . The entire text can be selected using selectAll () .


1 Answers

Saving and restoring scrollbar position is quite correct and works perfectly. When document's length is increased, scrollbar's maximum value is increased. But its value is still equal to number of pixels above the viewport. So when you add contents to the document and set the same scrollbar value repeatadly, scrollbar's handle will move to the top, but the content will remain immobile.

It seems that you already know how to check if the user has selected some text. To check if the user has scrolled away from the bottom, you should simply compare vertical scrollbar's value with its maximum.

like image 140
Pavel Strakhov Avatar answered Sep 18 '22 00:09

Pavel Strakhov