Search code examples
qtcursortext-editorqgraphicsitemqgraphicstextitem

How can I get my caret to show up on first double-click action on a QGraphicsTextItem?


I am struggling to get a QGraphicsTextItem to work as a user friendly object.
Since it is very hard to move while being editable, I start it as not editable, and make it editable on double-click. Then turn editing off on losing focus.

My problem is, the caret does not show up on first edit.
I have tried getting the position based on mouse position (as in this question that was trying to solve a different problem), or calling the QGraphicsTextItem::mouseDoubleClickEvent(event);

No matter what I try, the caret is invisible on first action - until I start typing (or if I focus out and back in) - even though it is at the correct location.

After typing, or unselecting and reselecting , the caret shows up in normal location every time.

I have tried to call the QTextCursor in the item constructor, setting its position at 0, made no difference.

What made a difference : one of the 2 situations (neither of which I can do though):
a) start item with Qt::TextEditorInteraction in constructor
b) start item with no moving/focus/selectable flags

I can't do either - because my default state of item must be movable, and that interferes with text editing (as explained at start).
I have tried to disable those flags during editing though... with no effect.

Here is a simple code to demonstrate the problem, I hope somebody can have an idea.

mytextitem.h

#ifndef TEXTITEM_H
#define TEXTITEM_H
#include <QGraphicsTextItem>

class MyTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
    MyTextItem();
protected:
    virtual void focusOutEvent (QFocusEvent * event);
    virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event);
};
#endif // TEXTITEM_H

mytextitem.cpp

#include "mytextitem.h"
#include <QTextCursor>
#include <QAbstractTextDocumentLayout>
#include <QGraphicsSceneMouseEvent>
#include <QFont>

MyTextItem::MyTextItem()
{
    setHtml("ABCD");
    setFont(QFont("Arial", 50));
    setTextInteractionFlags(Qt::NoTextInteraction);
    setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
}

void MyTextItem::focusOutEvent(QFocusEvent *event)
{
    Q_UNUSED(event);
    setTextInteractionFlags(Qt::NoTextInteraction);
    QTextCursor _cursor = textCursor();
    _cursor.clearSelection();
    setTextCursor(_cursor);
}

void MyTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    setTextInteractionFlags(Qt::TextEditorInteraction);
    QGraphicsTextItem::mouseDoubleClickEvent(event);   // or the version in linked question
}

main.cpp

int main(int argc, char *argv[])
{

    QApplication app(argc, argv);
    QGraphicsScene s;
    QGraphicsView view(&s);
    s.setSceneRect(-20, -100, 800, 600);
    view.show();
    MyTextItem* t = new MyTextItem();
    s.addItem(t);
    return app.exec();
}

I have also considered editing text - not sure if that would work but I think it would affect the undo stack which I will have to deal with soon....

How can I get my caret to show up on first double-click action on the text item ?

(As a user, not seeing a caret would make me uncertain if I can type... even though it works... I would not have confidence in the object if I do not have feedback of my action. That's why I care about this problem.)


Solution

  • I can't explain it... after trying EVERYTHING to get the caret to show, the solution was so simple:
    I had to change the order of flags being set, in constructor.

    The QGraphicsTextItem flag must be set AFTER setting the QGraphicsItem flags.

    setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
    setTextInteractionFlags(Qt::NoTextInteraction);