PDA

View Full Version : QGraphicsTextItem and text cursor position via QPoint



Lykurg
17th April 2009, 11:49
Hi,

I have a customized QGraphicsTextItem. By default the item is not editable. If one would like to change the content he has to double click the item:
void MyWordItem::mouseDoubleClickEvent(QGraphicsSceneMo useEvent */*event*/)
{
setTextInteractionFlags(Qt::TextEditorInteraction) ;
}
Now every time the blinking cursor is at the position 0, but I want the text cursor to be near the mouse double click position. (Like the result if one click the mouse button a third time.) Looking through QTextCursor, QTextDocument for a function like setTextCursorPos(QPoint) faild (I would like to use event->pos()). Even in the sources I don't figure out how the trolls do it in the mouse press reimp...

Passing the event to QGraphicsTextItem::mouseDoubleClickEvent(event); or QGraphicsTextItem::mousePressEvent(event); ends in a total selection of the content.


Any suggestions?
Thanks

mhennings
6th December 2012, 16:37
I know this thread is older than Saint Nicholas, but I had the exact same problem today and I found a solution that at least works for Qt 4.7.4.

Setup:

A customized QGraphicsTextItem class named TextItem.

In the constructor, it gets these settings:



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


This public function turns text editor mode on or off:



void SetTextInteraction(bool on, bool selectAll = false)
{
if(on && textInteractionFlags() == Qt::NoTextInteraction)
{
// switch on editor mode:
setTextInteractionFlags(Qt::TextEditorInteraction) ;
// manually do what a mouse click would do else:
setFocus(Qt::MouseFocusReason); // this gives the item keyboard focus
setSelected(true); // this ensures that itemChange() gets called when we click out of the item
if(selectAll) // option to select the whole text (e.g. after creation of the TextItem)
{
QTextCursor c = textCursor();
c.select(QTextCursor::Document);
setTextCursor(c);
}
}
else if(!on && textInteractionFlags() == Qt::TextEditorInteraction)
{
// turn off editor mode:
setTextInteractionFlags(Qt::NoTextInteraction);
// deselect text (else it keeps gray shade):
QTextCursor c = this->textCursor();
c.clearSelection();
this->setTextCursor(c);
clearFocus();
}
}


Now we want to turn on the editor mode on mouseDoubleClick:



void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *evt)
{
qDebug("mouseDoubleClickEvent '%s'", this->toPlainText().toStdString().c_str());
if(textInteractionFlags() == Qt::TextEditorInteraction)
{
// if editor mode is already on: pass double click events on to the editor:
QGraphicsTextItem::mouseDoubleClickEvent(evt);
return;
}

// if editor mode is off:
// 1. turn editor mode on and set selected and focused:
SetTextInteraction(true);

// 2. send a single click to this QGraphicsTextItem (this will set the cursor to the mouse position):
// create a new mouse event with the same parameters as evt
QGraphicsSceneMouseEvent *click = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMous ePress);
click->setButton(evt->button());
click->setPos(evt->pos());
QGraphicsTextItem::mousePressEvent(click);
delete click; // don't forget to delete the event
}


To leave the editor mode, it is sufficient to wait for the deselection event:



QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if(change == QGraphicsItem::ItemSelectedChange) qDebug("itemChange '%s', selected=%s", this->toPlainText().toStdString().c_str(), value.toString().toStdString().c_str());
if(change == QGraphicsItem::ItemSelectedChange
&& textInteractionFlags() != Qt::NoTextInteraction
&& !value.toBool())
{
// item received SelectedChange event AND is in editor mode AND is about to be deselected:
SetTextInteraction(false); // leave editor mode
}
return QGraphicsTextItem::itemChange(change, value);
}


That's all.

I left the qDebug() outputs in the code for your convenience. :-)

Since SetTextInteraction() is public, you can call it after creating a TextItem, so the user can start typing directly (you need to make sure that the view and the scene have the keyboard focus).

Rafe
10th July 2017, 19:38
Thanks for this!

Here is a near-verbatim refactor to Python that runs:
(Replace YOUR_CLASS with your class)


.
def setTextInteraction(self, state, selectAll=False):
if state and self.textInteractionFlags() == QtCore.Qt.NoTextInteraction:
# switch on editor mode:
self.setTextInteractionFlags(QtCore.Qt.TextEditorI nteraction)

# manually do what a mouse click would do else:
self.setFocus(QtCore.Qt.MouseFocusReason) # give the item keyboard focus
self.setSelected(True) # ensure itemChange() gets called when we click out of the item
if selectAll: # option to select the whole text (e.g. after creation of the TextItem)
c = self.textCursor()
c.select(QtGui.QTextCursor.Document)
self.setTextCursor(c)

elif not state and self.textInteractionFlags() == QtCore.Qt.TextEditorInteraction:
# turn off editor mode:
self.setTextInteractionFlags(QtCore.Qt.NoTextInter action)

# deselect text (else it keeps gray shade):
c = self.textCursor()
c.clearSelection()
self.setTextCursor(c)
self.clearFocus()

def mouseDoubleClickEvent(self, event):
log.warn("mouseDoubleClickEvent '%s'", self.toPlainText())

if self.textInteractionFlags() == QtCore.Qt.TextEditorInteraction:
# if editor mode is already on: pass double click events on to the editor:
super(YOUR_CLASS, self).mouseDoubleClickEvent(event)
return

# if editor mode is off:
# 1. turn editor mode on and set selected and focused:
self.setTextInteraction(True)

# 2. send a single click to this QGraphicsTextItem (will set the cursor to the mouse pos)
# create a mouse event with the same parameters as event
click = QtGui.QGraphicsSceneMouseEvent(QtCore.QEvent.Graph icsSceneMousePress)
click.setButton(event.button())
click.setPos(event.pos())
self.mousePressEvent(click)

def itemChange(self, change, value):
if change == QtGui.QGraphicsItem.ItemSelectedChange:
log.warn("itemChange '%s', selected=%s", self.toPlainText(), value)

if change == QtGui.QGraphicsItem.ItemSelectedChange \
and self.textInteractionFlags() != QtCore.Qt.NoTextInteraction \
and not value:

# item received SelectedChange event AND is in editor mode AND is about to be deselected
self.setTextInteraction(False) # leave editor mode

return super(YOUR_CLASS, self).itemChange(change, value)