Search code examples
pythonqtexteditpyside6

Is there a way to only change a part of the text in QTextEdit?


I want to change only a part of my text, basically I want it so that if a user makes a typo my program auto-corrects it. Now my code just resets the whole text to change the typo.

Here is my code

class MainEditor(QtWidgets.QTextEdit):
    def __init__(self):
        super().__init__()
        self.textChanged.connect(self.current_text)
        self.just_changed = False

    def current_text(self):
        if not self.just_changed:
            whole = self.toPlainText()
            whole = whole.split(' ')
            if len(whole) >= 2:
                last_word = whole[-2]
                # here was some logic I am just taking it as stop and assuming it was typo 
                correct_word = "stop"
                whole[-2] = correct_word
                self.just_changed = True
                self.setText(' '.join(whole))
        else:
            self.just_changed = False

As you see it retypes the whole text again to fix one typo is there a way to only change a part of the text in PySide6?

ADDITIONAL INFO:

This class object is then added to a QVBoxLayout and then the QVBoxLayout is added to the main QVBoxLayout and then it is added to QtWidgets.QWidget and I am also using the setHtml feature changing it to bold.


Solution

  • You have to use the QTextCursor to make the modifications, in the following demo if the user writes any of the words "tops", "sstop", "stoop" then it will be corrected to "stop"

    import re
    
    from PySide6 import QtWidgets, QtGui
    
    
    class MainEditor(QtWidgets.QTextEdit):
        WORD_REGEX = re.compile(
            r"\b[^\d\W]+\b"
        )  # https://stackoverflow.com/a/29375664/6622587
    
        def __init__(self):
            super().__init__()
            self.textChanged.connect(self.current_text)
    
        def current_text(self):
            position = 0
            text = self.toPlainText()
            res = self.WORD_REGEX.search(text[position:])
            while res:
                word = res.group()
                correct_word = self.fix_word(word)
                position += res.start()
                if correct_word:
                    self.replace_word(position, word, correct_word)
                    position += len(correct_word)
                else:
                    position += len(word)
                text = self.toPlainText()
                res = self.WORD_REGEX.search(text[position:])
    
        def replace_word(self, start, word, new_word):
            cursor = QtGui.QTextCursor(self.document())
            cursor.setPosition(start)
            cursor.movePosition(
                QtGui.QTextCursor.MoveOperation.Right,
                QtGui.QTextCursor.MoveMode.KeepAnchor,
                len(word),
            )
            cursor.deleteChar()
            cursor.insertText(new_word)
    
        def fix_word(self, word):
            if word in ("tops", "sstop", "stoop"):
                return "stop"
    
    
    def main():
        app = QtWidgets.QApplication()
    
        w = MainEditor()
        w.show()
    
        app.exec()
    
    
    if __name__ == "__main__":
        main()