Search code examples
python-2.7pyqtqt4qtextedit

QTextedit find and replace performance


I am working on a text editor I'm using Qt4.8/Pyqt specifically the QTextedit object, on Windows 7 & using python 2.7 Consider the following code(not orignal)

def doReplaceAll(self):
    # Replace all occurences without interaction

    # Here I am just getting the replacement data
    # from my UI so it will be different for you
    old=self.searchReplaceWidget.ui.text.text()
    new=self.searchReplaceWidget.ui.replaceWith.text()

    # Beginning of undo block
    cursor=self.editor.textCursor()
    cursor.beginEditBlock()

    # Use flags for case match
    flags=QtGui.QTextDocument.FindFlags()
    if self.searchReplaceWidget.ui.matchCase.isChecked():
        flags=flags|QtGui.QTextDocument.FindCaseSensitively

    # Replace all we can
    while True:
        # self.editor is the QPlainTextEdit
        r=self.editor.find(old,flags)
        if r:
            qc=self.editor.textCursor()
            if qc.hasSelection():
                qc.insertText(new)
        else:
            break

    # Mark end of undo block
    cursor.endEditBlock()

This works well for a few hundred lines of text. But when I have a lot of text say 10000 to 100000 lines of text replace all is EXTREMELY slow to the point of not being usable as the Editor slows right down. Am I doing something wrong. Why is QTextEdit so slow, I tried QplaingTextEdit as well not much luck there either. Any suggestions?


Solution

  • According to QTBUG-3554, QTextEdit is just inherently slow, and there is no hope of fixing that in Qt4 now.

    However, the bug report comments do show an alternative way of doing find and replace that may give better performance. Here's a PyQt4 port of it:

        def doReplaceAll(self):
            ...
            self.editor.textCursor().beginEditBlock()
            doc = self.editor.document()
            cursor = QtGui.QTextCursor(doc)
            while True:
                cursor = doc.find(old, cursor, flags)
                if cursor.isNull():
                    break
                cursor.insertText(new)
            self.editor.textCursor().endEditBlock()
    

    In my tests, this was 2-3 times faster when making about 600 replacements in a 10k-line file, or about 4000 replacements in a 60k-line file. The general performance is still pretty mediocre, though.