Issue
I have two instances. The first instance, active_part value is 1 and the second instance active-part value is 2. Based on this active_part value, I need to print some strings,
If we check self.active_part value, outside the method, it works fine. But I don't know how to check inside the method "keypressEvent". Here is my code and suggest the best way to achieve it?
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Create_Instance(QWidget):
entery = pyqtSignal()
def __init__(self,label,dict_item,active_part):
super().__init__()
self.setFocusPolicy(Qt.StrongFocus)
self.dict_items = dict_item
self.label = label
self.active_part = active_part
self.lbl = QLabel()
self.lbl.setText(self.label)
self.vbox = QVBoxLayout()
self.vbox.addWidget(self.lbl)
self.setLayout(self.vbox)
print("active_part value is ",self.active_part)
if self.active_part == "1":
print("active_part value is( inside the active_part = 1)",self.active_part)
elif self.active_part == "2":
print("active_part value is( inside the active_part = 2)",self.active_part)
def keyPressEvent(self, event):
if self.active_part == "1" and event.key() == Qt.Key_A:
print(" you press A and active_part value is 1")
elif self.active_part == "2" and event.key() == Qt.Key_B:
print(" you press B and active_part value is 2")
class Main_Window(QWidget):
def __init__(self):
super(). __init__()
self.setWindowTitle("Main Window")
self.layout_main = QVBoxLayout()
self.firstmenu_container = Create_Instance(label="Press A",dict_item="1",active_part = "1")
self.secondmenu_container = Create_Instance(label="Press B",dict_item="2",active_part = "2")
self.layout_main.addWidget(self.firstmenu_container)
self.layout_main.addWidget(self.secondmenu_container)
self.setLayout(self.layout_main)
def main():
app = QApplication(sys.argv)
ex = Main_Window()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Edited code For more clearance, here is my edited code. My aim is if I press the right or left arrow keys, then print the corresponding Label value. And if I press the Up or Down arrow keys, then the active part will change from first to second or vice versa and print Labe values. For example, If I press the down arrow, now the second group of labels will get active and respond to left or right arrow keys and print second group label values.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Create_Instance(QWidget):
entery = pyqtSignal()
def __init__(self,label1,label2,label3,dict_item,active_part):
super().__init__()
self.setFocusPolicy(Qt.StrongFocus)
self.list = []
self.dict_items = dict_item
self.label1 = label1
self.label2 = label2
self.label3 = label3
self.active_part = active_part
self.lbl1 = QLabel()
self.lbl1.setText(self.label1)
self.lbl2 = QLabel()
self.lbl2.setText(self.label2)
self.lbl3 = QLabel()
self.lbl3.setText(self.label3)
self.hbox = QHBoxLayout()
self.hbox.setSpacing(5)
self.hbox.addWidget(self.lbl1)
self.hbox.addWidget(self.lbl2)
self.hbox.addWidget(self.lbl3)
self.list.append(self.lbl1.text())
self.list.append(self.lbl2.text())
self.list.append(self.lbl3.text())
self.vbox = QVBoxLayout()
self.vbox.addLayout(self.hbox)
self.setLayout(self.vbox)
self.temp_value = 0
def keyPressEvent(self, event):
if event.key() == Qt.Key_Left and self.temp_value >= 2:
self.temp_value = self.temp_value - 1
if event.key() == Qt.Key_Right and self.temp_value <= 2 :
self.temp_value = self.temp_value + 1
if event.key() == Qt.Key_Down and self.active_part == "1":
self.active_part = 2
print("you press down arrow and now active part is second ")
if event.key() == Qt.Key_Up and self.active_part == "2":
self.active_part = 1
print("you press up arrow and now active part is first ")
if self.active_part == "1":
if self.temp_value == 1:
print("you select :", self.list[self.temp_value-1])
if self.temp_value == 2:
print("you select :", self.list[self.temp_value-1])
if self.temp_value == 3:
print("you select :", self.list[self.temp_value-1])
if self.active_part == "2":
if self.temp_value == 1:
print("you select :", self.list[self.temp_value - 1])
if self.temp_value == 2:
print("you select :", self.list[self.temp_value - 1])
if self.temp_value == 3:
print("you select :", self.list[self.temp_value - 1])
class Main_Window(QWidget):
def __init__(self):
super(). __init__()
self.setWindowTitle("Main Window")
self.layout_main = QVBoxLayout()
self.firstmenu_container = Create_Instance(label1="Press A",label2 = "press B", label3 = "press C",dict_item="1",active_part = "1")
self.secondmenu_container = Create_Instance(label1="Press X",label2 = "press Y", label3 = "press Z",dict_item="2",active_part = "2")
self.layout_main.addWidget(self.firstmenu_container)
self.layout_main.addWidget(self.secondmenu_container)
self.setLayout(self.layout_main)
def main():
app = QApplication(sys.argv)
ex = Main_Window()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Solution
A "menu-like" widget should always consider a proper hierarchy of objects, each one only responsible of what that object can do, and without having access or control to its parent.
Considering this, a possible implementation should use 3 classes:
- an "item" class that will only trigger its own "shortcut" when focused;
- a "group" class that will allow switching between its items;
- a main "menu" class that will allow switching between groups;
Note that, interestingly enough, the above hierarchical strucure is quite similar to what Qt already provides for a standard menu bar (QMenuBar > QMenu > QAction). Also, the "action range" of a "child" object is quite important from the OOP perspective: a child should not actively nor directly do anything on any of its parents, but only "ask" (signal) them to do something about it (see my slightly related post on object hierarchy).
All these classes will override their keyPressEvent
and eventually ignore it (by calling the base implementation) whenever they don't handle their assigned keys:
- the item will only accept and handle its own "key", and ignore everything else;
- the group will only accept and handle right and left arrows, and ignore the others;
- the menu will only use the up and down arrows, while ignoring the rest;
class MenuItem(QLabel):
activated = pyqtSignal()
def __init__(self, key):
super().__init__('Press ' + key)
self.setFocusPolicy(Qt.StrongFocus)
self.key = getattr(Qt, 'Key_' + key.upper())
self.setStyleSheet('''
QLabel::focus {
border: 1px solid black;
}
''')
def keyPressEvent(self, event):
if event.key() == self.key:
self.activated.emit()
else:
super().keyPressEvent(event)
class MenuGroup(QWidget):
activated = pyqtSignal(object, object)
def __init__(self, active_part):
super().__init__()
self.active_part = active_part
QHBoxLayout(self)
self.items = []
def index(self, widget):
try:
return self.items.index(widget)
except ValueError:
return -1
def item(self, index):
index = max(0, min(len(self.items) - 1, index))
try:
return self.items[index]
except IndexError:
return None
def addItem(self, key):
item = MenuItem(key)
self.items.append(item)
self.layout().addWidget(item)
item.activated.connect(lambda: self.activated.emit(self, item))
return item
def keyPressEvent(self, event):
if event.key() in (Qt.Key_Left, Qt.Key_Right):
widget = self.focusWidget()
if widget:
index = self.items.index(widget)
if event.key() == Qt.Key_Left:
index = max(0, index - 1)
else:
index = min(len(self.items) - 1, index + 1)
newWidget = self.items[index]
if newWidget != widget:
newWidget.setFocus()
return
super().keyPressEvent(event)
class MenuWidget(QWidget):
activated = pyqtSignal(object, object)
def __init__(self):
super().__init__()
QVBoxLayout(self)
self.groups = []
def addGroup(self, active_part):
group = MenuGroup(active_part)
self.groups.append(group)
self.layout().addWidget(group)
group.activated.connect(self.activated)
return group
def keyPressEvent(self, event):
if event.key() in (Qt.Key_Up, Qt.Key_Down):
widget = self.focusWidget()
if widget:
parent = widget.parent()
groupIndex = self.groups.index(parent)
if event.key() == Qt.Key_Up:
groupIndex = max(0, groupIndex - 1)
else:
groupIndex = min(len(self.groups) - 1, groupIndex + 1)
itemIndex = parent.index(widget)
newWidget = self.groups[groupIndex].item(itemIndex)
if newWidget and newWidget != widget:
newWidget.setFocus()
return
super().keyPressEvent(event)
class Main_Window(QWidget):
def __init__(self):
super(). __init__()
self.setWindowTitle("Main Window")
self.layout_main = QVBoxLayout(self)
self.topMenu = MenuWidget()
self.layout_main.addWidget(self.topMenu)
self.firstGroup = self.topMenu.addGroup('1')
self.firstGroup.addItem('A')
self.firstGroup.addItem('B')
self.firstGroup.addItem('C')
self.secondGroup = self.topMenu.addGroup('2')
self.secondGroup.addItem('X')
self.secondGroup.addItem('Y')
self.secondGroup.addItem('Z')
self.topMenu.activated.connect(self.itemActivated)
def itemActivated(self, group, item):
print('activated', group.active_part, item.text())
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.