How can I hide the caret when not in edit mode?

2019-08-08 17:16发布

问题:

I have a TextItem inheriting QGraphicsTextItem. I made it so that on double-click I can edit the text, and when clicking out, the text is no longer editable.

void TextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)
{
    setTextInteractionFlags(Qt::TextEditorInteraction);
    setFocus();

    int p = document()->documentLayout()->hitTest(event->pos(), Qt::FuzzyHit);
    QTextCursor _cursor = textCursor();
    _cursor.setPosition(p);
    setTextCursor(_cursor);
}

void TextItem::focusOutEvent(QFocusEvent *event)
{
    Q_UNUSED(event);
    setTextInteractionFlags(Qt::NoTextInteraction);
}

When clicking out, the text is no longer editable - but the caret is still visible.

Adding setCursor(Qt::OpenHandCursor); in the focusOutEvent (and possibly trying to remember which cursor shape to set... I don't know how yet) fixes this - makes the caret disappear - but I don't think it is the right fix.

Yet I cannot find any method in QTextCursor to hide the caret when no longer in edit mode - and it seems that setting NoTextInteraction should have done that...

What is the best way to hide the caret when not in edit mode ?

回答1:

You are talking of the caret - the on-screen indication of the text editing position. What you describe looks like a Qt bug.

The setCursor call modifies the mouse pointer, not the caret. It has a side effect that forces the item to synchronize the caret state with the interaction flags. The absence of such synchronization is the bug you experience.

The QTextCursor class doesn't represent the caret, but a position in the text document. It's a fancy iterator, completely decoupled from any visible representation of it.

The QGraphicsTextItem happens to maintain a caret that represents the position of its textCursor property. You can have other QTextCursor instances operating on the same document, and they won't have a visible caret associated with them - they are just iterators.

You know one workaround for the bug - via setCursor, but try the ones below, too:

  1. An update() of the item after the interaction has been disabled.

  2. Setting the textCursor to a null cursor, perhaps in combination with an update().

    setTextCursor(QTextCursor());
    


回答2:

Added a clear selection on lost focus, since it seems that not only the caret is left but any selected text is also left selected - and it is not the behavior I wanted.

void TextItem::focusOutEvent(QFocusEvent *event)
{
    Q_UNUSED(event);
    setTextInteractionFlags(Qt::NoTextInteraction);

    QTextCursor _cursor = textCursor();
    _cursor.clearSelection();
    setTextCursor(_cursor);
}

The above clears the caret, as well as any selected text fragment.

(If anybody reading this question is looking to save selection on text fragments, but not display the caret, the option I mentioned in my question - by setting the QCursor - may be the best option)