Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Manipulating selection with QTextCursor and QTextEdit [SOLVED]
QtWS25 Last Chance

Manipulating selection with QTextCursor and QTextEdit [SOLVED]

Scheduled Pinned Locked Moved General and Desktop
qtextcursorqtextedit
7 Posts 3 Posters 6.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F Offline
    F Offline
    frankiefrank
    wrote on last edited by frankiefrank
    #1

    I'm working with a subclass of QTextEdit - but because of my project's requirements, I only display one "screen" of text at a time. The very large complete text is stored elsewhere, and I have my own scrollbar to know which subset of it to display.

    Now I'm trying to achieve a very "natural" behavior that I lost because of the way I work with the QTextEdit - the user selects text, keeps the button pressed, then drags the mouse up (or down) outside the boundaries of the text box, which causes scrolling and the extension of selection.

    I got the scrolling part working (based on QTextEdit's source code) but I'm having a hard time with getting the right selection behavior. After my text is replaced, I want to update the selection to reflect the extended one.

    My specific question is how to achieve the following state in code: get to a selection "in progress" that starts (or ends) with a position I choose? I want to "fake" the selection as if the user momentarily let go of the mouse button, selected the text from the previous position and got back to where his mouse cursor was.

    I hope this is clear, if not I'll try to provide a screenshot. Appreciate any feedback!

    "Roads? Where we're going, we don't need roads."

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      I think some images would indeed be a good thing to show what you want to achieve

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • F Offline
        F Offline
        frankiefrank
        wrote on last edited by
        #3

        I prepared some screenshots to show the wanted behavior, using a standard text box:

        Step 1 - user starts selecting some lines, dragging cursor up

        Step 2 - user continues to select all the way to the currently-top-displayed-line

        Step 3 - user continues to drag up, the text scrolled one line up, selection extended to include newly displayed line

        This (step 3) is the behavior I want to imitate. In my code, the scrolling up causes a replacement of the text. Once that happens, the previous selection is (naturally) forgotten. I want to write code that - immediately after replacement of text and while user is still with mouse button pressed - causes selection to restart from the position it was in before the scroll.

        I hope this is more clear with the screenshots.

        "Roads? Where we're going, we don't need roads."

        1 Reply Last reply
        0
        • F Offline
          F Offline
          frankiefrank
          wrote on last edited by
          #4

          If there are any ideas still I'll appreciate it.

          "Roads? Where we're going, we don't need roads."

          1 Reply Last reply
          0
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by Chris Kawa
            #5

            I guess you need to track the selection yourself ie. on click calculate the "real" or "absolute" cursor position, similar on mouse move and select the "local" or "relative" block yourself.

            Sounded like a nice exercise, so here's my coffee-break try at this.
            I didn't bother to implement the scroll bar so use mouse scroll to move around.
            Pardon the rough edges and napkin quality code, but I hope you can extract the basic idea out of it:

            #include <QApplication>
            #include <QMouseEvent>
            #include <QWheelEvent>
            #include <QTextEdit>
            
            class TextEdit : public QTextEdit
            {
            public:
                TextEdit(QWidget* parent = nullptr) : QTextEdit(parent),
                    startPos(0), endPos(0), absCursorStart(0), absCursorEnd(0) {}
            
                void mouseMoveEvent(QMouseEvent* evt) {
                    if(!(evt->buttons() & Qt::LeftButton))
                        return;
            
                    auto cfp = cursorForPosition(evt->pos());
                    absCursorEnd = cfp.position() + startPos * 11;
            
                    if(evt->pos().y() < 0 && startPos > 0)
                        --startPos;
                    if(evt->pos().y() >= height() && endPos < textData.size())
                        ++startPos;
            
                    adjust();
                }
            
                void wheelEvent(QWheelEvent* evt) {
                    auto lines = evt->delta() / 100;
                    startPos = qBound(0, startPos - lines, textData.size());
                    adjust();
                }
            
                void mousePressEvent(QMouseEvent* evt) {
                    auto cfp = cursorForPosition(evt->pos());
                    setTextCursor(cfp);
                    absCursorStart = absCursorEnd = cfp.position() + startPos * 11;
                }
                void adjust() {
                    auto numLines = height() / fontMetrics().height() - 1;
                    auto size = qMin(textData.size(), numLines);
                    auto subText = QStringList(textData.mid(startPos, size)).join("\n");
                    setText(subText);
                    endPos = startPos + numLines;
            
                    auto numVisibleChars = (endPos - startPos) * 11 - 1;
            
                    auto localCursorStart = qBound(0, absCursorStart - startPos * 11, numVisibleChars);
                    auto localCursorEnd   = qBound(0, absCursorEnd - startPos * 11, numVisibleChars);
            
                    auto tc = textCursor();
                    tc.setPosition(localCursorEnd);
                    tc.setPosition(localCursorStart, QTextCursor::KeepAnchor);
                    setTextCursor(tc);
                }
            
                void resizeEvent(QResizeEvent* evt) {
                    QTextEdit::resizeEvent(evt);
                    adjust();
                }
            
                QStringList textData;
                int startPos;
                int endPos;
                int absCursorStart;
                int absCursorEnd;
            };
            
            int main(int argc, char *argv[])
            {
                QApplication a(argc, argv);
            
                QStringList stuff;
                for(int i = 0; i < 100; ++i)
                    stuff << QString(10, QChar('a' + (i % 30)));
            
                TextEdit te;
                te.textData = stuff;
                te.show();
            
                return a.exec();
            }
            

            Of course you need to be careful about copy/paste. You should copy the whole selected block manually, as the built in mechanism will only copy the visible portion of the selection this way.

            1 Reply Last reply
            0
            • F Offline
              F Offline
              frankiefrank
              wrote on last edited by
              #6

              Chris, thank you, that's really helpful. I admit I'm having trouble with the rough edges but basic idea extraction is definitely in progress.

              I already had something similar in my code, but I think there was something wrong about the way I reapplied my selection after updating the data.

              Again, huge thanks!

              "Roads? Where we're going, we don't need roads."

              1 Reply Last reply
              0
              • F Offline
                F Offline
                frankiefrank
                wrote on last edited by
                #7

                Applied to my code, marked as [SOLVED]. Thank you once again!

                "Roads? Where we're going, we don't need roads."

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved