Skip to content
Advertisement

How to avoid the processing, if an unnecessary key is pressed (include or exclude user-defined, pre-defined keyss) in PyQt5?

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).

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement