def testRefcount(self): textedit = QTextEdit() textedit.setReadOnly(True) doc = textedit.document() cursor = QTextCursor(doc) cursor.insertText("PySide Rocks") ud = TestUserData({"Life": 42}) self.assertEqual(sys.getrefcount(ud), 2) cursor.block().setUserData(ud) self.assertEqual(sys.getrefcount(ud), 3) ud2 = cursor.block().userData() self.assertEqual(sys.getrefcount(ud), 4) self.udata = weakref.ref(ud, None) del ud, ud2 self.assertEqual(sys.getrefcount(self.udata()), 2)
def build_invoice(self, data): document = QTextDocument() self.setDocument(document) document.setPageSize(QSizeF(self.doc_width, self.doc_height)) document.setDefaultFont(font) cursor = QTextCursor(document) cursor.insertText(f"Customer Name: {data['c_name']}\n") cursor.insertText(f"Customer Address: {data['c_addr']}\n") cursor.insertText(f"Date: {data['i_date']}\n") cursor.insertText(f"Total Due: {data['total_due']}\n") # + return document # +++
def on_log_received(self, data): time_info = datetime.fromtimestamp((data['time'] / 1000)).isoformat() log_message = '%s: %s : %s' % (time_info, data['level'], data['message']) message_document = self.document() cursor_to_add = QTextCursor(message_document) cursor_to_add.movePosition(cursor_to_add.End) cursor_to_add.insertText(log_message + '\n') if data['level'] in COLORS: fmt = QTextCharFormat() fmt.setForeground(COLORS[data['level']]) cursor_to_add.movePosition(cursor_to_add.PreviousBlock) log_lvl_data = LogLevelData(log_levels[data['level'].upper()]) cursor_to_add.block().setUserData(log_lvl_data) cursor_to_add_fmt = message_document.find(data['level'], cursor_to_add.position()) cursor_to_add_fmt.mergeCharFormat(fmt) if log_levels[data['level']] > self.log_lvl: cursor_to_add.block().setVisible(False) self.ensureCursorVisible()
class MainWindow(QWidget): def __init__(self): super().__init__() self.signals = Signals() self.initUI() self.setSignals() self.decensor = Decensor(self) self.load_model() def initUI(self): grid_layout = QGridLayout() grid_layout.setSpacing(10) self.setLayout(grid_layout) #Tutorial self.tutorialLabel = QLabel() self.tutorialLabel.setText( "Welcome to DeepCreamPy!\n\nIf you're new to DCP, please read the README.\nThis program does nothing without the proper setup of your images.\n\nReport any bugs you encounter to me on Github or Twitter @deeppomf." ) self.tutorialLabel.setAlignment(Qt.AlignCenter) self.tutorialLabel.setFont(QFont('Sans Serif', 13)) #Censor type group self.censorTypeGroupBox = QGroupBox('Censor Type') barButton = QRadioButton('Bar censor') mosaicButton = QRadioButton('Mosaic censor') barButton.setChecked(True) censorLayout = QVBoxLayout() censorLayout.addWidget(barButton) censorLayout.addWidget(mosaicButton) # censorLayout.addStretch(1) self.censorTypeGroupBox.setLayout(censorLayout) #Variation count group self.variationsGroupBox = QGroupBox('Number of Decensor Variations') var1Button = QRadioButton('1') var2Button = QRadioButton('2') var3Button = QRadioButton('4') var1Button.setChecked(True) varLayout = QVBoxLayout() varLayout.addWidget(var1Button) varLayout.addWidget(var2Button) varLayout.addWidget(var3Button) # varLayout.addStretch(1) self.variationsGroupBox.setLayout(varLayout) #Decensor button self.decensorButton = QPushButton('Decensor Your Images') self.decensorButton.clicked.connect(self.decensorClicked) self.decensorButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) #Progress message # self.progressGroupBox = QGroupBox('Progress') self.progressMessage = QTextEdit() self.progressCursor = QTextCursor(self.progressMessage.document()) self.progressMessage.setTextCursor(self.progressCursor) self.progressMessage.setReadOnly(True) self.progressCursor.insertText( "After you prepared your images, click on the decensor button once to begin decensoring.\nPlease be patient.\nDecensoring will take time.\n" ) # Progress Bar self.statusBar = QStatusBar(self) self.progressBar = QProgressBar() self.progressBar.setMinimum(0) self.progressBar.setMaximum(100) self.progressBar.setValue(0) self.statusLabel = QLabel("Showing Progress") self.statusBar.addWidget(self.statusLabel, 1) self.statusBar.addWidget(self.progressBar, 2) #put all groups into grid # addWidget(row, column, rowSpan, columnSpan) grid_layout.addWidget(self.tutorialLabel, 0, 0, 1, 2) grid_layout.addWidget(self.censorTypeGroupBox, 1, 0, 1, 1) grid_layout.addWidget(self.variationsGroupBox, 1, 1, 1, 1) grid_layout.addWidget(self.decensorButton, 2, 0, 1, 2) grid_layout.addWidget(self.progressMessage, 3, 0, 1, 2) grid_layout.addWidget(self.statusBar, 4, 0, 1, 2) #window size settings self.resize(900, 600) self.center() self.setWindowTitle('DeepCreamPy v2.2.0-beta') self.show() def load_model(self): # load model to make able to decensor several times self.decensorButton.setEnabled(False) self.decensorButton.setText( "Loading Machine Learning Model (Please Wait...)") self.decensor.start() self.decensor.signals = self.signals self.progressCursor.insertText( "Loading Decensor app consumes 6 GB memory at maximum") def setSignals(self): self.signals.update_decensorButton_Text.connect( self.decensorButton.setText) self.signals.update_decensorButton_Enabled.connect( self.decensorButton.setEnabled) self.signals.update_statusLabel_Text.connect(self.statusLabel.setText) self.signals.update_ProgressBar_SET_VALUE.connect( self.progressBar.setValue) self.signals.update_ProgressBar_MAX_VALUE.connect( self.progressBar.setMaximum) self.signals.update_ProgressBar_MIN_VALUE.connect( self.progressBar.setMinimum) # self.signals.insertText_progressCursor.connect(self.progressCursor.insertText) self.signals.insertText_progressCursor.connect( self.progressMessage.append) self.signals.clear_progressMessage.connect(self.progressMessage.clear) self.signals.appendText_progressMessage.connect( self.progressMessage.append) def decensorClicked(self): self.decensorButton.setEnabled(False) self.progressMessage.clear() self.progressCursor.insertText("Decensoring has begun!\n") # for now, decensor is initiated when this app is started # self.decensor = Decensor(text_edit = self.progressMessage, text_cursor = self.progressCursor, ui_mode = True) #https://stackoverflow.com/questions/42349470/pyqt-find-checked-radiobutton-in-a-group #set decensor to right settings #censor type censorTypeElements = self.censorTypeGroupBox.children() censorButtons = [ elem for elem in censorTypeElements if isinstance(elem, QRadioButton) ] for cb in censorButtons: if cb.isChecked(): censorType = cb.text() if censorType == 'Bar censor': self.decensor.is_mosaic = False else: self.decensor.is_mosaic = True #variations count variationsElements = self.variationsGroupBox.children() variationsButtons = [ elem for elem in variationsElements if isinstance(elem, QRadioButton) ] for vb in variationsButtons: if vb.isChecked(): variations = int(vb.text()) self.decensor.variations = variations self.decensorButton.setEnabled(False) self.decensor.start() # decensor.decensor_all_images_in_folder() # #centers the main window def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
def testCase(self): editor = QTextEdit() cursor = QTextCursor(editor.textCursor()) cursor.movePosition(QTextCursor.Start) mainFrame = cursor.currentFrame() plainCharFormat = QTextCharFormat() boldCharFormat = QTextCharFormat() boldCharFormat.setFontWeight(QFont.Bold) cursor.insertText( """ Text documents are represented by the QTextDocument class, rather than by QString objects. Each QTextDocument object contains information about the document's internal representation, its structure, and keeps track of modifications to provide undo/redo facilities. This approach allows features such as the layout management to be delegated to specialized classes, but also provides a focus for the framework.""", plainCharFormat) frameFormat = QTextFrameFormat() frameFormat.setMargin(32) frameFormat.setPadding(8) frameFormat.setBorder(4) cursor.insertFrame(frameFormat) cursor.insertText( """ Documents are either converted from external sources or created from scratch using Qt. The creation process can done by an editor widget, such as QTextEdit, or by explicit calls to the Scribe API.""", boldCharFormat) cursor = mainFrame.lastCursorPosition() cursor.insertText( """ There are two complementary ways to visualize the contents of a document: as a linear buffer that is used by editors to modify the contents, and as an object hierarchy containing structural information that is useful to layout engines. In the hierarchical model, the objects generally correspond to visual elements such as frames, tables, and lists. At a lower level, these elements describe properties such as the style of text used and its alignment. The linear representation of the document is used for editing and manipulation of the document's contents.""", plainCharFormat) frame = cursor.currentFrame() items = [] #test iterator for i in frame: items.append(i) #test __iadd__ b = frame.begin() i = 0 while not b.atEnd(): self.assertEqual(b, items[i]) self.assertTrue(b.parentFrame(), items[i].parentFrame()) b.__iadd__(1) i += 1 #test __isub__ b = frame.end() i = 0 while i > 0: self.assertEqual(b, items[i]) self.assertTrue(b.parentFrame(), items[i].parentFrame()) b.__isub__(1) i -= 1
class MainWindow(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): grid_layout = QGridLayout() grid_layout.setSpacing(10) self.setLayout(grid_layout) #Tutorial self.tutorialLabel = QLabel() self.tutorialLabel.setText( "Welcome to DeepCreamPy!\n\nIf you're new to DCP, please read the README.\nThis program does nothing without the proper setup of your images.\n\nReport any bugs you encounter to me on Github or Twitter @deeppomf." ) self.tutorialLabel.setAlignment(Qt.AlignCenter) self.tutorialLabel.setFont(QFont('Sans Serif', 13)) #Censor type group self.censorTypeGroupBox = QGroupBox('Censor Type') barButton = QRadioButton('Bar censor') mosaicButton = QRadioButton('Mosaic censor') barButton.setChecked(True) censorLayout = QVBoxLayout() censorLayout.addWidget(barButton) censorLayout.addWidget(mosaicButton) # censorLayout.addStretch(1) self.censorTypeGroupBox.setLayout(censorLayout) #Variation count group self.variationsGroupBox = QGroupBox('Number of Decensor Variations') var1Button = QRadioButton('1') var2Button = QRadioButton('2') var3Button = QRadioButton('4') var1Button.setChecked(True) varLayout = QVBoxLayout() varLayout.addWidget(var1Button) varLayout.addWidget(var2Button) varLayout.addWidget(var3Button) # varLayout.addStretch(1) self.variationsGroupBox.setLayout(varLayout) #Decensor button self.decensorButton = QPushButton('Decensor Your Images') self.decensorButton.clicked.connect(self.decensorClicked) self.decensorButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) #Progress message # self.progressGroupBox = QGroupBox('Progress') self.progressMessage = QTextEdit() self.progressCursor = QTextCursor(self.progressMessage.document()) self.progressMessage.setTextCursor(self.progressCursor) self.progressMessage.setReadOnly(True) self.progressCursor.insertText( "After you prepared your images, click on the decensor button once to begin decensoring.\nPlease be patient.\nDecensoring will take time.\n" ) #put all groups into grid grid_layout.addWidget(self.tutorialLabel, 0, 0, 1, 2) grid_layout.addWidget(self.censorTypeGroupBox, 1, 0, 1, 1) grid_layout.addWidget(self.variationsGroupBox, 1, 1, 1, 1) grid_layout.addWidget(self.decensorButton, 2, 0, 1, 2) grid_layout.addWidget(self.progressMessage, 3, 0, 4, 2) #window size settings self.resize(500, 500) self.center() self.setWindowTitle('DeepCreamPy v2.2.0-beta') self.show() def decensorClicked(self): self.decensorButton.setEnabled(False) self.progressMessage.clear() self.progressCursor.insertText("Decensoring has begun!\n") decensor = Decensor(text_edit=self.progressMessage, text_cursor=self.progressCursor, ui_mode=True) #https://stackoverflow.com/questions/42349470/pyqt-find-checked-radiobutton-in-a-group #set decensor to right settings #censor type censorTypeElements = self.censorTypeGroupBox.children() censorButtons = [ elem for elem in censorTypeElements if isinstance(elem, QRadioButton) ] for cb in censorButtons: if cb.isChecked(): censorType = cb.text() if censorType == 'Bar censor': decensor.is_mosaic = False else: decensor.is_mosaic = True #variations count variationsElements = self.variationsGroupBox.children() variationsButtons = [ elem for elem in variationsElements if isinstance(elem, QRadioButton) ] for vb in variationsButtons: if vb.isChecked(): variations = int(vb.text()) decensor.variations = variations self.decensorButton.setEnabled(True) self.hide() self.progress = ProgressWindow(self, decensor=decensor) # decensor.decensor_all_images_in_folder() # self.progress.hide() # self.show() # def showAbout(self): # QMessageBox.about(self, 'About', "DeepCreamPy v2.2.0 \n Developed by deeppomf") # #centers the main window def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
def testCase(self): editor = QTextEdit() cursor = QTextCursor(editor.textCursor()) cursor.movePosition(QTextCursor.Start) mainFrame = cursor.currentFrame() plainCharFormat = QTextCharFormat() boldCharFormat = QTextCharFormat() boldCharFormat.setFontWeight(QFont.Bold); cursor.insertText(""" Text documents are represented by the QTextDocument class, rather than by QString objects. Each QTextDocument object contains information about the document's internal representation, its structure, and keeps track of modifications to provide undo/redo facilities. This approach allows features such as the layout management to be delegated to specialized classes, but also provides a focus for the framework.""", plainCharFormat) frameFormat = QTextFrameFormat() frameFormat.setMargin(32) frameFormat.setPadding(8) frameFormat.setBorder(4) cursor.insertFrame(frameFormat) cursor.insertText(""" Documents are either converted from external sources or created from scratch using Qt. The creation process can done by an editor widget, such as QTextEdit, or by explicit calls to the Scribe API.""", boldCharFormat) cursor = mainFrame.lastCursorPosition() cursor.insertText(""" There are two complementary ways to visualize the contents of a document: as a linear buffer that is used by editors to modify the contents, and as an object hierarchy containing structural information that is useful to layout engines. In the hierarchical model, the objects generally correspond to visual elements such as frames, tables, and lists. At a lower level, these elements describe properties such as the style of text used and its alignment. The linear representation of the document is used for editing and manipulation of the document's contents.""", plainCharFormat) frame = cursor.currentFrame() items = [] #test iterator for i in frame: items.append(i) #test __iadd__ b = frame.begin() i = 0 while not b.atEnd(): self.assertEqual(b, items[i]) self.assert_(b.parentFrame(), items[i].parentFrame()) b.__iadd__(1) i += 1 #test __isub__ b = frame.end() i = 0 while i > 0: self.assertEqual(b, items[i]) self.assert_(b.parentFrame(), items[i].parentFrame()) b.__isub__(1) i -= 1
class PlainTextFindReplaceDialog(QDialog): """ Modeless, stay-above-parent dialog that supports find and replace. Allows for searching case (in)sensitively, and whole-word. Find triggered by Enter / Shift+Enter, or corresponding button (Next / Previous), or if Replace clicked before Next / Previous. Find wraps. Highlights all matches, operating on the closest-to-user's-cursor selection first, in the user-selected direction (Next / Previous). Highlighting / found cursors retained on navigation back to text editor, and cleared on re-find/replace if user modified the document. Presents an info label (e.g. "x of y", "No matches found", ...) While no members have a leading underscore, the only explicit public interface is the static method `find_all`. I couldn't find a reason to need to interface with anything in here, so I didn't differentiate everything as "private". """ def __init__(self, plain_text_edit: QPlainTextEdit, parent=None): """ Sets up the dialog. :param plain_text_edit: Text Editor to operate on. :param parent: QWidget parent """ super().__init__(parent=parent, f=Qt.Tool) self.plain_text_edit = plain_text_edit self.cursors_needed = True self.find_flags = QTextDocument.FindFlags() self.found_cursors: List[QTextCursor] = [] self.current_cursor = QTextCursor() # UI layout = QVBoxLayout() find_and_replace_layout = QGridLayout() layout.addLayout( find_and_replace_layout ) # if QGL is sub-layout, add to parent layout before doing stuff. self.find_line_edit = QLineEdit() find_label = QLabel("&Find") find_label.setBuddy(self.find_line_edit) options_layout = QHBoxLayout() self.match_case_check_box = QCheckBox("Match Case") self.whole_word_check_box = QCheckBox("Whole Word") options_layout.addWidget(self.match_case_check_box) options_layout.addWidget(self.whole_word_check_box) options_layout.addStretch() self.found_info_label = QLabel() self.replace_line_edit = QLineEdit() replace_label = QLabel("&Replace") replace_label.setBuddy(self.replace_line_edit) find_and_replace_layout.addWidget(find_label, 0, 0) find_and_replace_layout.addWidget(self.find_line_edit, 0, 1) find_and_replace_layout.addLayout(options_layout, 1, 1) find_and_replace_layout.setRowMinimumHeight(2, 20) find_and_replace_layout.addWidget(self.found_info_label, 2, 1) find_and_replace_layout.addWidget(replace_label, 3, 0) find_and_replace_layout.addWidget(self.replace_line_edit, 3, 1) self.btn_box = QDialogButtonBox(QDialogButtonBox.Close) self.find_next_btn = QPushButton("Next") self.find_next_btn.setEnabled(False) self.find_prev_btn = QPushButton("Previous") self.find_prev_btn.setEnabled(False) self.replace_btn = QPushButton("Replace") self.replace_btn.setEnabled(False) self.replace_all_btn = QPushButton("Replace All") self.replace_all_btn.setEnabled(False) self.btn_box.addButton(self.replace_btn, QDialogButtonBox.ActionRole) self.btn_box.addButton(self.replace_all_btn, QDialogButtonBox.ActionRole) self.btn_box.addButton(self.find_prev_btn, QDialogButtonBox.ActionRole) self.btn_box.addButton(self.find_next_btn, QDialogButtonBox.ActionRole) layout.addWidget(self.btn_box) self.setLayout(layout) # End UI self.btn_box.rejected.connect(self.reject) self.find_line_edit.textEdited.connect(self.handle_text_edited) self.find_next_btn.clicked.connect(self.next) self.find_prev_btn.clicked.connect(self.prev) self.replace_btn.clicked.connect(self.replace) self.replace_all_btn.clicked.connect(self.replace_all) self.plain_text_edit.document().contentsChanged.connect( self.set_cursors_needed_true) self.whole_word_check_box.stateChanged.connect( self.toggle_whole_word_flag) self.match_case_check_box.stateChanged.connect( self.toggle_match_case_flag) # SLOTS def next(self): """ Finds all matches to the user's search. First highlight after cursor. Consecutive calls advance through matches. If there are matches or not, it says so. The user's cursor advances along with the current selection. Loops back to start after the last match. :return: Side effect: Highlights all matches, differentiating (maybe moving fwd) the current selection. """ if self.cursors_needed: self.init_find() if not self.found_cursors: self.found_info_label.setText("No matches found") self.found_info_label.repaint() return if self.current_cursor >= self.found_cursors[ -1]: # loop back to start. cursor equality based on position. self.current_cursor = self.found_cursors[0] else: for cur in self.found_cursors: if cur > self.current_cursor: # next in order self.current_cursor = cur break self.update_visuals() def prev(self): """ Finds all matches to user's search. First highlight before cursor. Consecutive calls retreat through matches. If there are matches or not, it says so. The user's cursor moves along with the current selection. Loops back to end after the last (first in doc) match. :return: Side effect: Highlights all matches, differentiating (maybe moving back) the current selection. """ if self.cursors_needed: self.init_find() if not self.found_cursors: self.found_info_label.setText("No matches found") self.found_info_label.repaint() return if self.current_cursor <= self.found_cursors[0]: # loop back to end. self.current_cursor = self.found_cursors[-1] else: for cur in reversed(self.found_cursors): if cur < self.current_cursor: # prev in order self.current_cursor = cur break self.update_visuals() def replace(self): """ Replaces the word under focus by `next`. Replaces with the Replace line edit's text, and advances to next word. If no word under focus via this dialog, calls `next`. :return: Side effect: replaces word in text edit """ if self.cursors_needed: self.next() return if not self.found_cursors: return self.plain_text_edit.document().contentsChanged.disconnect( self.set_cursors_needed_true) # don't dup work. self.current_cursor.insertText(self.replace_line_edit.text()) self.plain_text_edit.document().contentsChanged.connect( self.set_cursors_needed_true) self.found_cursors.remove(self.current_cursor) self.next() def replace_all(self): """ Replaces all instances of Find's text with Replace's text. :return: Side effect: replaces words in text edit. Indicates success to user via info label on dialog. """ if self.cursors_needed: self.init_find() for cur in self.found_cursors: cur.insertText(self.replace_line_edit.text()) self.found_info_label.setText("Made {} replacements".format( len(self.found_cursors))) self.found_info_label.repaint() def handle_text_edited(self, text): """ Modifies button states, clears info text, and sets self.cursors_needed to True. :param text: The find_line_edit's text. :return: Side effect: btn enabled / default """ self.found_info_label.clear() self.cursors_needed = True find_enabled = text != "" self.find_next_btn.setEnabled(find_enabled) self.find_prev_btn.setEnabled(find_enabled) self.replace_btn.setEnabled(find_enabled) self.replace_all_btn.setEnabled(find_enabled) self.find_next_btn.setDefault(find_enabled) self.btn_box.button( QDialogButtonBox.Close).setDefault(not find_enabled) def set_cursors_needed_true(self): self.cursors_needed = True def toggle_match_case_flag(self, state: int): self.found_info_label.clear( ) # User will be performing a new search upon toggle, so want this reset. self.cursors_needed = True if state == Qt.Unchecked: self.find_flags &= ~QTextDocument.FindCaseSensitively elif state == Qt.Checked: self.find_flags |= QTextDocument.FindCaseSensitively def toggle_whole_word_flag(self, state: int): self.found_info_label.clear( ) # User will be performing a new search upon toggle, so want this reset. self.cursors_needed = True if state == Qt.Unchecked: self.find_flags &= ~QTextDocument.FindWholeWords elif state == Qt.Checked: self.find_flags |= QTextDocument.FindWholeWords # END SLOTS def init_find(self): """Sets up internal state for the case when cursors are needed (e.g. first find, user modifies doc...)""" self.found_cursors = self.find_all(self.find_line_edit.text(), self.plain_text_edit.document(), self.find_flags) self.cursors_needed = False self.current_cursor = self.plain_text_edit.textCursor( ) # returns copy of self.plain_text_edit.setExtraSelections([]) def update_visuals(self): """ Moves text editor's cursor to match currently highlighted `find` word, performs `find` highlighting, indicates index on dialog. """ # x of y words indicator idx = self.found_cursors.index(self.current_cursor) + 1 self.found_info_label.setText("{} of {} matches".format( idx, len(self.found_cursors))) self.found_info_label.repaint() # move along text editor's viewport next_pte_cursor = QTextCursor(self.current_cursor) next_pte_cursor.clearSelection() self.plain_text_edit.setTextCursor(next_pte_cursor) #highlighting normal_color = QColor(Qt.yellow).lighter() current_color = QColor(Qt.magenta).lighter() extra_selections: List[QTextEdit.ExtraSelection] = [] for cur in self.found_cursors: selection = QTextEdit.ExtraSelection() selection.cursor = cur if cur == self.current_cursor: selection.format.setBackground(current_color) else: selection.format.setBackground(normal_color) extra_selections.append(selection) self.plain_text_edit.setExtraSelections(extra_selections) @staticmethod def find_all( text: str, document: QTextDocument, flags=QTextDocument.FindFlags() ) -> List[QTextCursor]: """ Finds all occurrences of `text` in `document`, in order. :param text: Text to find. :param document: Document to search. :param flags: Conditions to set on the search: none or (whole word and/or match case) :return: Ordered list of all found instances. """ cursor = QTextCursor(document) # default pos == 0 found: List[QTextCursor] = [] while True: cursor = document.find(text, cursor, flags) if cursor.isNull(): return found else: found.append(cursor) def done(self, arg__1: int): self.plain_text_edit.setExtraSelections([]) super().done(arg__1) def keyPressEvent(self, arg__1: QKeyEvent): # Shift+Enter triggers find previous, if the corresponding btn is enabled. if (arg__1.key() in [Qt.Key_Return, Qt.Key_Enter] and arg__1.modifiers() == Qt.ShiftModifier and self.find_prev_btn.isEnabled()): self.prev() else: super().keyPressEvent(arg__1)