How to avoid the processing, if an unnecessary key is pressed? For Example, In my code, I use Right Arrow and Left Arrowkey in keyPressEvent to move from one label to another label. and I assign keys F5, Alt+ A and ctrl+alt+p as shortcuts for labels. By default to print the First label “Accounts” is selected. Now if I press any key (like u,v,a,alt,ctrl etc), I get a result “Accounts is selected” as much as time, I pressed anyother keys. If I press F5, Label Manufacture is selected/print, But now I press any key then I get a print message “Manufacture is selected“
My intention is, If I press right, left arrow keys or assigned Qkeysequence keys, then only I got a response(print selected Item), If I press any other keys, Avoid processing and I don’t want to display anything. (Here, QKeySequence keys is a dynamic ones, not constant, it will differ form user to user)
import sys from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtGui import * class Dynamic_Widgets(QWidget): def __init__(self): super(). __init__() self.setWindowTitle("Dynamic Widget") self.vbox1 = QVBoxLayout() self.vbox2 = QVBoxLayout() self.hbox = QHBoxLayout() self.hbox.addLayout(self.vbox1),self.hbox.addLayout(self.vbox2) self.hbox.addSpacing(5),self.setLayout(self.hbox) self.lbl_1 = QLabel("Accounts") self.lbl_2 = QLabel("Inventory") self.lbl_3 = QLabel("Manufacture") self.lbl_1_sc = QLabel("Alt+A") self.lbl_2_sc = QLabel("alt+ctrl+P") self.lbl_3_sc = QLabel("F5") self.store_sc = {} self.item_list = [] self.item_list_sc = [] self.vbox1.addWidget(self.lbl_1) self.vbox1.addWidget(self.lbl_2) self.vbox1.addWidget(self.lbl_3) self.item_list.append(self.lbl_1.text()) self.item_list.append(self.lbl_2.text()) self.item_list.append(self.lbl_3.text()) self.vbox2.addWidget(self.lbl_1_sc) self.vbox2.addWidget(self.lbl_2_sc) self.vbox2.addWidget(self.lbl_3_sc) self.item_list_sc.append(self.lbl_1_sc.text()) self.item_list_sc.append(self.lbl_2_sc.text()) self.item_list_sc.append(self.lbl_3_sc.text()) self.active_part = 1 self.first_option = 0 self.first_option_result = "" self.first_option_result = self.item_list[self.first_option] self.func_final_result() for count,item in enumerate(self.item_list): self.store_sc[count] = QShortcut(QKeySequence(f'{(self.item_list_sc[count])}'),self) self.store_sc[count].activated.connect(self.result) def result(self): shortcut = self.sender() sc_key = QKeySequence(shortcut.key()).toString() sc_key_index = self.item_list_sc.index(sc_key) self.first_option = sc_key_index self.first_option_result = self.item_list[sc_key_index] self.func_final_result() def keyPressEvent(self, event): if self.active_part == 1: if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter) and self.first_option == 0: self.first_option = 0 if event.key() == Qt.Key_Right and self.first_option < len(self.item_list)-1: self.first_option = self.first_option + 1 if event.key() == Qt.Key_Left and self.first_option > 0: self.first_option = self.first_option - 1 if self.first_option != -1: self.first_option_result = self.item_list[self.first_option] self.func_final_result() def func_final_result(self): print(self.first_option_result, "is selected") def main(): app = QApplication(sys.argv) ex = Dynamic_Widgets() ex.show() sys.exit(app.exec_()) if __name__ == '__main__': main()
Advertisement
Answer
If you only want to process specific keys, then you either check if the event key is in the list of “handled” keys and proceed with its processing, or just ignore the event if it’s not.
Note that you must not compare the string representation of the key, but its QKeySequence instead.
class Dynamic_Widgets(QWidget): def __init__(self): # ... self.item_list_sc.append(QKeySequence(self.lbl_1_sc.text())) self.item_list_sc.append(QKeySequence(self.lbl_2_sc.text())) self.item_list_sc.append(QKeySequence(self.lbl_3_sc.text())) self.key_indexes = {} for i, key in enumerate(self.item_list_sc): shortcut = self.store_sc[i] = QShortcut(key, self) shortcut.activated.connect(self.result) self.key_indexes[key] = i def result(self): shortcut = self.sender() sc_key_index = self.key_indexes.get(shortcut.key()) if sc_key_index is None: return self.first_option = sc_key_index self.first_option_result = self.item_list[sc_key_index] self.func_final_result() def keyPressEvent(self, event): key = event.key() if key not in (Qt.Key_Return, Qt.Key_Enter, Qt.Key_Left, Qt.Key_Right): return if self.active_part == 1: if key in (Qt.Key_Return, Qt.Key_Enter): self.first_option = 0 elif (key == Qt.Key_Right and self.first_option < len(self.item_list) - 1): self.first_option += 1 elif key == Qt.Key_Left and self.first_option > 0: self.first_option -= 1 if self.first_option >= 0: self.first_option_result = self.item_list[self.first_option] self.func_final_result()
Alternatively, use an if/elif/else
block that always check only for the key, and eventually process the key according to the other conditions, otherwise return
since no key match has been found to that point:
def keyPressEvent(self, event): if self.active_part == 1: key = event.key() if key in (Qt.Key_Return, Qt.Key_Enter): self.first_option = 0 elif key == Qt.Key_Right: if self.first_option < len(self.item_list) - 1: self.first_option += 1 elif key == Qt.Key_Left: if self.first_option > 0: self.first_option -= 1 else: return if self.first_option >= 0: self.first_option_result = self.item_list[self.first_option] self.func_final_result()
Note: for such situations, you must always use a QGridLayout, otherwise items might become not properly aligned under certain circumstances; eventually, consider QFormLayout. Also, avoid putting multiple function calls in a single line, there is absolutely no benefit in that, and it only makes your code cumbersome and difficult to read (and, thus, to debug).