user595985
user595985

Reputation: 1583

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?

Upvotes: 1

Views: 2837

Answers (2)

ekhumoro
ekhumoro

Reputation: 120578

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.

Upvotes: 1

user764357
user764357

Reputation:

Short of profiling you're going to have trouble finding exactly what the slow down is, but its probably to do with a few factors: PyQT is really tied to its C libraries, handling data between the two might cause slow downs.

But of note is that you aren't just changing text in that code, you are also re-positioning the cursor as well within the text/window.

The biggest speed up I can suggest is if you are doing a global search and replace, pull all of the text into python, use python to replace and then reinsert back in:

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()

    text = self.editor.toPlainText()
    text = text.replace(old,new)
    self.editor.setPlainText(text)

    # Mark end of undo block
    cursor.endEditBlock()

Upvotes: 0

Related Questions