python pyqt5 3. Text editing box pop-up window search and replace, highlighting the searched string

Function:

1. Click the Open Find and Replace button to pop up the Find and Replace window. After selecting the string, the window will open and the value will be automatically searched.

2. All found results are highlighted.

3. Display the number of results found and the number currently found

4. Implement batch replacement

Rendering:

Code:

import re
importsys

from PyQt5.QtCore import QRegExp, Qt
from PyQt5.QtGui import QTextCharFormat, QColor, QTextCursor, QPalette, QFont
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QLineEdit, QLabel, QWidget, QCheckBox, \
    QStatusBar, QToolBar, QComboBox, QTextEdit


class FindReplace(QMainWindow):
    def __init__(self, parent=None):
        super(FindReplace, self).__init__(parent)

    def setupUi(self, text_edit,find_text):
        # Set positioning and upper left corner coordinates
        self.setGeometry(1200, 200, 250, 300)
        self.setWindowTitle("Find/Replace")
        self.text_edit = text_edit
        self.find_replace_window_is_open = 1
        self.find_count = 0 #Number of searches

        self.find_label = QLabel("Find:")
        self.find_edit = QComboBox()
        self.find_edit.setEditable(True)
        self.find_edit.activated.connect(self.find_text)
        self.find_edit.editTextChanged.connect(self.find_text_edit)


        self.replace_label = QLabel("Replace:")
        self.replace_edit = QLineEdit()

        self.find_cb_case_sensitive = QCheckBox()
        self.find_cb_case_sensitive.setChecked(True)
        #self.find_cb_case_sensitive.stateChanged.connect(self.restore_checkbox_clicked)
        self.find_label_case_sensitive = QLabel()
        self.find_label_case_sensitive.setText("Case-insensitive:")

        self.find_cb_case_sensitive = QCheckBox()
        self.find_cb_case_sensitive.setChecked(True)
        #self.find_cb_case_sensitive.stateChanged.connect(self.restore_checkbox_clicked)
        self.find_label_case_sensitive = QLabel()
        self.find_label_case_sensitive.setText("Highlight all:")


        self.find_button = QPushButton('Find')
        self.find_button.clicked.connect(self.find_text)

        self.replace_button = QPushButton('replace')
        self.replace_button.clicked.connect(self.replace_text)
        self.replace_all_button = QPushButton('Replace all')
        self.replace_all_button.clicked.connect(self.replace_text_all)

        self.find_StatusBar1 = QToolBar()
        #self.find_StatusBar1 = QStatusBar()
        self.find_StatusBar1.setLayoutDirection(Qt.LeftToRight)
        self.find_StatusBar1_Label = QLabel()
        self.find_StatusBar1_Label.setStyleSheet("QLabel { color: blue; }")
        self.find_StatusBar1_Label.setFont(QFont("Microsoft YaHei", 8, 0))
        self.find_StatusBar1.addWidget(self.find_StatusBar1_Label)


        self.find_edit.addItem(find_text)

        layout = QVBoxLayout()
        layout.addWidget(self.find_label)
        layout.addWidget(self.find_edit)
        layout.addWidget(self.replace_label)
        layout.addWidget(self.replace_edit)
        layout.addWidget(self.find_button)
        layout.addWidget(self.replace_button)
        layout.addWidget(self.replace_all_button)
        layout.addWidget(self.find_StatusBar1)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def find_text_edit(self):
        self.position = self.text_edit.textCursor().position()
        text = self.text_edit.document().toPlainText()
        find_text = self.find_edit.currentText()
        text_edit_select = self.text_edit.textCursor().selectedText()
        if find_text == '':
            self.background_reset(text)
            return
        if text_edit_select:
            self.position = self.position - len(text_edit_select)
        self.find_and_highlight()
        if self.i > 0:
            self.find_and_select()
    def find_text(self):
        self.position = self.text_edit.textCursor().position()
        find_text = self.find_edit.currentText()
        text = self.text_edit.document().toPlainText()
        if find_text == '':
            self.background_reset(text)
            return
        self.find_and_highlight()
        if self.i > 0 :
            self.find_and_select()

    def find_and_select(self):
        text = self.text_edit.document().toPlainText()
        find_text = self.find_edit.currentText()
        re_search = QRegExp(find_text)
        matches = re.finditer(re_search.pattern(), text)
        length = len(find_text)
        format = QTextCharFormat()
        format.setBackground(QColor("yellow"))
        # Loop through documents
        j = 0
        for match in matches:
            if j == 0:
                self.start_match = match
            j+=1
            index = match.start()
            if index >= self.position:
                cursor = self.text_edit.textCursor()
                cursor.setPosition(index)
                cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, length)
                #self.text_edit.setFocus()
                self.text_edit.setTextCursor(cursor)
                cursor = self.text_edit.textCursor()
                cursor.mergeCharFormat(format) # Change the background color of the text
                self.find_StatusBar1_Label.setText(str(self.i) + 'result, current ' + str(j) + 'result)
                break
            #Judge if it reaches the end, then display the first one
            if self.i > 0 and self.i == j:
                index = self.start_match.start()
                cursor = self.text_edit.textCursor()
                cursor.setPosition(index)
                cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, length)
                # self.text_edit.setFocus()
                self.text_edit.setTextCursor(cursor)
                cursor = self.text_edit.textCursor()
                cursor.mergeCharFormat(format) # Change the background color of the text
                self.find_StatusBar1_Label.setText(str(self.i) + ' results, current 1')


    def find_and_highlight(self):
        text_edit_select = self.text_edit.textCursor().selectedText()
        text = self.text_edit.document().toPlainText()
        find_text = self.find_edit.currentText()
        re_search = QRegExp(find_text)
        matches = re.finditer(re_search.pattern(), text)
        length = len(find_text)

        #Set the background color to white
        self.background_reset(text)

        cursor = self.text_edit.textCursor()
        format = QTextCharFormat()
        format.setBackground(QColor("yellow"))

        self.i = 0
        # Loop through the document to select and display the value
        for match in re.finditer(re.escape(find_text), text):
            self.i + = 1
            start = match.start()
            end = match.end()
            cursor.setPosition(start)
            cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, end - start)
            cursor.mergeCharFormat(format)
        self.find_edit.setStyleSheet("QComboBox { color: black; }")
        self.find_StatusBar1_Label.setText(str(self.i) + 'results')
        if self.i == 0:
            self.find_edit.setStyleSheet("QComboBox { color: red; }")
            self.find_StatusBar1_Label.setStyleSheet("QLabel { color: red; }")
        else:
            self.find_StatusBar1_Label.setStyleSheet("QLabel { color: blue; }")
        #Judge the first time you enter. If the textedit selected string is equal to the search string, move the cursor to the initialization - search string length to facilitate the search for the first time it is selected.
        if self.find_count == 0 and text_edit_select == find_text:
            self.position = self.position - len(find_text)
        self.find_count + = 1



    def replace_text(self):
        text = self.text_edit.document().toPlainText()
        find_text = self.find_edit.currentText()
        replace_text = self.replace_edit.text()

        self.background_reset(text)
        if find_text:
            text = text.replace(find_text, replace_text)
            self.text_edit.setPlainText(text)
    def replace_text_all(self):
        text_edit_select = self.text_edit.textCursor().selectedText()
        text = self.text_edit.document().toPlainText()
        find_text = self.find_edit.currentText()
        replace_text = self.replace_edit.text()
        self.background_reset(text)
        if find_text == text_edit_select:
            text = text.replace(find_text, replace_text)
            self.text_edit.setPlainText(text)

    def background_reset(self,text):
        #Set the background color to white
        format = QTextCharFormat()
        format.setBackground(QColor("white"))
        cursor = self.text_edit.textCursor()
        cursor.setPosition(0)
        cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, len(text))
        cursor.mergeCharFormat(format) # Change the background color of the text

    def closeEvent(self, event):
        #Add here the action you want to perform when closing the window
        self.background_reset(self.text_edit.document().toPlainText())
        self.find_replace_window_is_open = 0
        #Set the background color to white
        text = self.text_edit.document().toPlainText()
        self.background_reset(text)
        print("Window closed")
        event.accept()

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("Main Window")
        self.setGeometry(400, 100, 1100, 800)
        self.text_edit = QTextEdit()


        self.button = QPushButton("Open the find and replace window")
        self.button.clicked.connect(self.open_find_replace_window)

        layout = QVBoxLayout()
        layout.addWidget(self.text_edit)
        layout.addWidget(self.button)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def open_find_replace_window(self):
        find_text = self.text_edit.textCursor().selectedText()
        self.find_replace_window = FindReplace(self)
        self.find_replace_window.setupUi(self.text_edit,find_text)
        self.find_replace_window.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())