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.