One of the key functions of a good IDE is the find function. This function is very important because based on my experience, I am having such a hard time searching for a particular word in a 1000+ lines of codes. There are many ways to implement this like highlight all found words with the syntax hilighter so that all found words can be immediately be seen or create a small pane that enumerates the location of each found word and when clicked, the cursor will be positioned to that found word, or a combination of both, and many others. In this post I just implemented a simple way of searching a word in a QTextEdit widget by pressing contrl+f to enter the searchstring and the program will position the cursor to the first found word and select it. It is a very simple implementation and can be further modified with tons of features.
Here is the screenshot:
Here is the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton, QShortcut, QInputDialog, QMessageBox from PyQt5.QtGui import QKeySequence, QTextCursor, QTextCharFormat, QTextDocument from PyQt5.QtCore import Qt class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): # Create a QTextEdit widget self.textEdit = QTextEdit(self) self.setCentralWidget(self.textEdit) # Create a shortcut for the "Find" action findShortcut = QShortcut(QKeySequence("Ctrl+F"), self) findShortcut.activated.connect(self.findText) # Show the main window self.show() def findText(self): # Show the find dialog box searchString, ok = QInputDialog.getText(self, "Find", "Find:") if not ok: return # Get the QTextCursor and QTextDocument cursor = self.textEdit.textCursor() document = self.textEdit.document() # Set the search options options = QTextDocument.FindFlags() options |= QTextDocument.FindCaseSensitively options |= QTextDocument.FindWholeWords # Add this line # Search for the text count = 0 #while True: cursor = document.find(searchString, cursor, options) #if cursor is None: # break count += 1 # Move the cursor to the beginning of the match and select the text cursor.movePosition(QTextCursor.StartOfWord) char_after_word = document.characterAt(cursor.position()) print(char_after_word) if searchString[0] != char_after_word: cursor.movePosition(QTextCursor.Left, QTextCursor.MoveAnchor, len(searchString)) cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) self.textEdit.setTextCursor(cursor) self.textEdit.setFocus() if count == 0: QMessageBox.information(self, "Find", "No match found.") #else: # QMessageBox.information(self, "Find", f"{count} matches found.") # Create the QApplication app = QApplication([]) # Create the MainWindow mainWindow = MainWindow() # Run the event loop app.exec_() |
In case where you just pressed the contro+v to paste a block of codes and you want the cursor to go back to the start(0,0) of the QTextEdit widget, you may add a keypress event. Here is the method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def onTextChanged(self): # Do something when the text changes global paste #print(paste) #pass if paste == 1: self.textEdit.moveCursor(QTextCursor.Start) paste = 0 def keyPressEvent(self, event): global paste # If Ctrl+V is pressed, move the cursor to the beginning of the QTextEdit widget if event.modifiers() == Qt.ControlModifier and event.key() == 16777249: self.textEdit.moveCursor(QTextCursor.Start) paste = 1 # Call the parent class's keyPressEvent to handle other key events super().keyPressEvent(event) |
The keypress event will not be able to move the cursor to the start position so I added another method ontextchanged to handle the cursor position and I used global variable paste to store the result in keypressevent.
No comments:
Post a Comment