c++qtqplaintexteditqtextcursor

QPlainTextEdit - searches the document to the end and again from the beginning


I want to search in QPlainTextEdit for a string from the current cursor to the end. If nothing is found, I want to continue searching from the start. Only in this stage, if nothing is found, a message will appear.

void BasicEdit::findString(QString s, bool reverse, bool casesens, bool words) {

    QTextDocument::FindFlags flag;
    if (reverse) flag |= QTextDocument::FindBackward;
    if (casesens) flag |= QTextDocument::FindCaseSensitively;
    if (words) flag |= QTextDocument::FindWholeWords;
    
    QTextCursor cursor = this->textCursor();
    
    if (!find(s, flag)) {
        //nothing is found | jump to start/end
        cursor.movePosition(reverse?QTextCursor::End:QTextCursor::Start);
        setTextCursor(cursor); //!!!!!!
        if (!find(s, flag)) {
            //no match in whole document
            QMessageBox msgBox;
            msgBox.setText(tr("String not found."));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
        }
    }
}

The problem is in line setTextCursor(cursor);:

How do I search for a string in a document and not change the current position if none is found?


Based on this answer, I added value preservation for verticalScrollBar.

Even so, there is a short flickering when nothing is found generated by:

cursor.movePosition(reverse?QTextCursor::End:QTextCursor::Start);

How can we get rid of it? It is an idea to create another invisible QPlainTextEdit element to search in it?

void BasicEdit::findString(QString s, bool reverse, bool casesens, bool words)
{

    QTextDocument::FindFlags flag;
    if (reverse) flag |= QTextDocument::FindBackward;
    if (casesens) flag |= QTextDocument::FindCaseSensitively;
    if (words) flag |= QTextDocument::FindWholeWords;
    
    QTextCursor cursor = this->textCursor();
    // here we save the cursor position and the verticalScrollBar value
    QTextCursor cursorSaved = cursor;
    int scroll = verticalScrollBar()->value();
    
    if (!find(s, flag))
    {
        //nothing is found | jump to start/end
        cursor.movePosition(reverse?QTextCursor::End:QTextCursor::Start);
        setTextCursor(cursor);
    
        if (!find(s, flag))
        {
            // word not found : we set the cursor back to its initial position and restore verticalScrollBar value
            setTextCursor(cursorSaved);
            verticalScrollBar()->setValue(scroll);
            QMessageBox msgBox(this);
            msgBox.setText(tr("String not found."));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
        }
    }
}

Solution

  • The idea is to keep the cursor position you have before starting to search for the word. Then, after the research, you will set the cursor back to the position you saved.

    void BasicEdit::findString(QString s, bool reverse, bool casesens, bool words) 
    {
        QTextDocument::FindFlags flag;
        if (reverse) flag |= QTextDocument::FindBackward;
        if (casesens) flag |= QTextDocument::FindCaseSensitively;
        if (words) flag |= QTextDocument::FindWholeWords;
    
        QTextCursor cursor = this->textCursor();
        // here , you save the cursor position
        QTextCursor cursorSaved = cursor;
    
        if (!find(s, flag)) 
        {
            //nothing is found | jump to start/end
            cursor.movePosition(reverse?QTextCursor::End:QTextCursor::Start);
    
            /* following line :
            - the cursor is set at the beginning/end of the document (if search is reverse or not)
            - in the next "find", if the word is found, now you will change the cursor position
            */ 
            setTextCursor(cursor);
    
            if (!find(s, flag)) 
            {
                //no match in whole document
                QMessageBox msgBox;
                msgBox.setText(tr("String not found."));
                msgBox.setStandardButtons(QMessageBox::Ok);
                msgBox.setDefaultButton(QMessageBox::Ok);
                msgBox.exec();
    
                // word not found : we set the cursor back to its initial position
                setTextCursor(cursorSaved);
            }
        }
    }