Get XY Coordinates of QTextCursor
-
wrote 28 days ago last edited by
I am using PySide6 and wondering how I can get a QRect or a QPoint of the QTextCursor's position in a QTextDocument. My QTextDocument is painted on a QWidget using the QAbstractTextDocumentLayout.draw() function. Using a QTextEdit you can get the QRect of the QTextCursor by using the QTextEdit.cursorRect() function. My need for this is that when you enter text into my simple word processing app (see screenshot), you have to manually scroll the QScrollArea to keep the text cursor in view. I want to use the QScrollArea.ensureVisible() function to keep the text cursor in the viewport, but I seemingly have no way of getting any X/Y coordinates of the QTextCursor. I have experimented using the blockBoundingRect and frameBoundingRect and while the blockBoundingRect gets close, it is still too large an area for that to work. I've exhausted my ideas and I hope someone has a suggestion for me. Maybe someone understands the source code of QTextEdit.cursorRect well enough to help me create an equivalent in PySide6.
-
wrote 28 days ago last edited by
Hi @DonJS and welcome.
Assuming you are using the standard Qt implementation of
QAbstractTextDocumentLayout
and not implementing your own, it is very roughly something like this:- Get the
QTextBlock
for the cursor, and take the block'sQTextLayout
via thelayout
method. - Get the specific actual
QTextLine
that has that position by calling the layout'slineForTextPosition
with the cursor's position relative to its' block start. - If result is valid, use
cursorToX
to get the x-position relative to the line. - Consider the line and block layout positions to get the (x,y) coordinates relative to document.
- Convert from document coordinates to viewport coordinates based on whatever margin or such you are using.
Probably needs a bit of trial and error to get exactly right.
- Get the
-
Hi @DonJS and welcome.
Assuming you are using the standard Qt implementation of
QAbstractTextDocumentLayout
and not implementing your own, it is very roughly something like this:- Get the
QTextBlock
for the cursor, and take the block'sQTextLayout
via thelayout
method. - Get the specific actual
QTextLine
that has that position by calling the layout'slineForTextPosition
with the cursor's position relative to its' block start. - If result is valid, use
cursorToX
to get the x-position relative to the line. - Consider the line and block layout positions to get the (x,y) coordinates relative to document.
- Convert from document coordinates to viewport coordinates based on whatever margin or such you are using.
Probably needs a bit of trial and error to get exactly right.
wrote 27 days ago last edited by@IgKh
Thanks so much for your direction. That was exactly what I needed! Here is the code I used:#####determine the cursor position to scroll the scrollArea as needed #get the blockBoundingRect of the block that holds the QTextCursor blockRect = self.doc.documentLayout().blockBoundingRect(self.cur.block()) #get the QTextLine that holds the QTextCursor cursorLine = self.cur.block().layout().lineForTextPosition(self.cur.positionInBlock()) #get the QTextLine's naturalTextRect so we can get the Y center of the QTextCursor self.cursorLineRect = cursorLine.naturalTextRect() #translate the cursorLineRect to the blockRect self.cursorLineRect.translate(blockRect.x(),blockRect.y()) #get the approximate X position of the cursor cursorToX = cursorLine.cursorToX(self.cur.positionInBlock(), QTextLine.Edge.Leading) #create a QPointF from the cursorToX posistion and the center of the CursorLineRect self.cursorPoint=QPointF(float(cursorToX[0])+blockRect.x(),self.cursorLineRect.center().y()) #instruct the QScrollArea to keep the QPointF visible with 100px padding self.main_window.scrollArea.ensureVisible(self.cursorPoint.x(), self.cursorPoint.y(),100,100)
Then to confirm my computation was correct I painted
self.cursorPoint
usingpainter.drawPoint(self.cursorPoint)
. You can see the little red dot following the text cursor in the screenshot below. Your guidance solved my problem 100% - Get the
-
1/3