Important: Please read the Qt Code of Conduct -

Implement text selection with QTextDocument-based component

  • Although I am working in a QML context, I believe the crux of my question is general Qt API so I am asking it here.

    I am trying to implement a relatively simple custom text display component, intended for a read only scrollable display of a log from a background process. The number of lines of text can potentially become large and must be updated dynamically as more output is generated. I tried to use the built-in TextArea component but it performs very poorly once the text length gets to a moderate size.

    Following a hint in a Qt bug report that I happened across, I have made good progress using QTextDocument to manage and store the text, and using QTextDocument::drawContents to paint it. Based on my experiments, the performance issues are overcome and I have scrolling working and so on.

    One missing piece of functionality that I would like to add is selection of text (via mouse and keyboard) so that I can provide a "copy selected text" facility. I am completely new to the QTextDocument (and related classes) API and am stuck at the first step. Having pored over the documentation, I can't see how to identify the text at a particular point in the rectangle in which the text is drawn.

    So, let's say that I detect a mouse click at point (x, y) in the rectangle, how do I relate that to the document content so that I can use it as the start of selection? I am not even worrying about complications arising from the case where the text is too large to fit in the rectangle - let's assume all of the text is visible. How do I map from the display position to the corresponding position in the text? How to do this is my main question at the moment.

    A secondary question relates to the QTextCursor interface. I note that this supports selection as a concept but I am not sure if exactly corresponds to what I am trying to do. In particular it supports a number of "selection types" (QTextDocument::SelectionType) but none of these seem to correspond to the case where one might want to start a selection at an arbitrary position in the text and end it at another arbitrary position. Is this selection concept even relevant to what I am trying to do?

    Finally, if anyone is aware of any example code that demonstrates how to implement text selection in the context of QTextDocument I would be immensely grateful for a pointer to it.

    Thank you.

  • So, I think I have it:

    Given QPointF pt derived from mouse position,

    auto layout = m_textDoc.documentLayout();
    int pos = layout->hitTest(pt, Qt::FuzzyHit); // or maybe Qt::ExactHit?

    Here, pos refers to the character position, starting at the beginning of the document.

    If the document does not fit in the view rectangle, then pt here needs to be adjusted by the same offsets that were used to draw the document (as used in QPainter::translate and the clip rect for QTextDocument::drawContents.

Log in to reply