PDA

View Full Version : QTextEdit::cursorForPosition() and character at mouse pointer?



miwarre
2nd November 2011, 17:42
Hello,

In a sub-classed QTextEdit widget, I need to locate the character underneath the mouse pointer both for showing a tool tip and to construct the contextual menu.

Following the Qt documentation (and as suggested in all the posts of these forums I could locate on the topic), I re-implemented event() (for tool tips) and contextMenuEvent() (for the menu) and used cursorForPosition( event->pos() ).position() to get the character at the mouse pointer (actually the index of character within the widget text string).

The code works correctly for all details, except one:

The range of mouse pointer positions returning a given character does not correspond to the bounding box of that character but it is shifted left by roughly half of the character width.

A practical example:

Assuming the widget contains the text "ABCD", cursorForPosition() returns:

* 'A' position when the mouse pointer is over the left half of the 'A';
* 'B' position when the mouse pointer is over the right half of the 'A' or the left half of the 'B';
* 'C' position when the mouse pointer is over the right half of the 'B' or the left half of the 'C';
* 'D' position when the mouse pointer is over the right half of the 'C' or the left half of the 'D';
* <nothing> (an invalid index) when the cursor is over the right half of the 'D'.

(I may assume these be the positions where a textual cursor would be placed by clicking 'there' with mouse). The UI result is puzzling!

The questions are:

1) Are there method(s) actually dealing with position(s) of textual units (characters) and not of cursors? (the two being different as shown above)

2) Can I translate cursorForPosition() returned value to a character without reconstructing character width(s) from the textual format and/or the font metrics? (cursorForPosition() is already doing this for me! Why do it again?)

Thanks,

M.

llev
3rd November 2011, 09:19
Documentation on QTextEdit::cursorForPosition says it accepts coordinates relative to viewport.
Do you pass mouse position in viewport coordinates?

miwarre
5th November 2011, 01:15
Documentation on QTextEdit::cursorForPosition says it accepts coordinates relative to viewport.
Do you pass mouse position in viewport coordinates?

Thank you for your reply. Initially I didn't pass position in viewport coordinates, but directly the event->pos(). However, converting to viewport coordinates (by re-implementing viewportEvent() rather than event()) hardly made any difference (1 pixel at most: there is no scrolling).

Actually, this shifting between the character(s) and the cursor position is consistent with what the documentation says about QTextCursor: "The cursor's current position() then is always either between two consecutive characters...".

QTextEdit::cursorForPosition() returns a cursor (rather obviously), the cursor is between two characters (plus special cases at text ends) and the position returned is the cursor position nearest to the mouse cursor. For far so good: everything is consistent ans reasonable.

The problem however remains: how to retrieve the character physically underneath the mouse pointer, regardless of where a text cursor would be placed by clicking 'there'?

Any hint about where to look for other API's more convenient for this task would be welcome (perhaps not passing via cursors at all): I could not find any.

Thanks,

M.

llev
5th November 2011, 09:32
Try the following:


// m_Edit - QTextEdit object
// ptViewport - mouse position in viewport coordinates
// docLPos - position of character under mouse
int docLPos = m_Edit->document()->documentLayout()->hitTest( QPointF( ptViewport.x(), ptViewport.y() ), Qt::ExactHit );

miwarre
4th February 2012, 10:59
Try the following:


int docLPos = m_Edit->document()->documentLayout()->hitTest( QPointF( ptViewport.x(), ptViewport.y() ), Qt::ExactHit );


Thanks for the reply and my apologies for the delay in acknowledging it: the project has been suspended and I completely forgot about this pending issue.

I was aware of the hitTest() function, but I assumed it was working the same as cursorForPosition() (oh, never, never assume anything!), so I did not even tried it.

When finally answering your post, in order to give a complete reply as possible, I tried it and, lo!, it works indeed!.

So, thanks for overriding my stubborness!

M.