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()
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:
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:
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())
This solution is based on your codes. The main idea is that the key press is handled by the Main_window
class.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Create_Instance(QWidget):
entery = pyqtSignal()
def __init__(self,label1,label2,label3,dict_item):
super().__init__()
self.setFocusPolicy(Qt.StrongFocus)
self.list = []
self.dict_items = dict_item
self.label1 = label1
self.label2 = label2
self.label3 = label3
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 change_and_print_selected(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 self.temp_value == 1:
print("you select :", self.list[self.temp_value-1])
elif self.temp_value == 2:
print("you select :", self.list[self.temp_value-1])
elif self.temp_value == 3:
print("you select :", self.list[self.temp_value-1])
else:
pass
return self.temp_value
class Main_Window(QWidget):
def __init__(self):
super(). __init__()
self.setWindowTitle("Main Window")
self.layout_main = QVBoxLayout()
self.active_part = "1"
self.temp_value = 0
self.firstmenu_container = Create_Instance(label1="Press A",label2 = "press B", label3 = "press C",dict_item="1")
self.secondmenu_container = Create_Instance(label1="Press X",label2 = "press Y", label3 = "press Z",dict_item="2")
self.layout_main.addWidget(self.firstmenu_container)
self.layout_main.addWidget(self.secondmenu_container)
self.setLayout(self.layout_main)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Down and self.active_part == "1":
self.active_part = "2"
self.secondmenu_container.temp_value = self.temp_value
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"
self.firstmenu_container.temp_value = self.temp_value
print("you press up arrow and now active part is first ")
if self.active_part == "1":
self.temp_value = self.firstmenu_container.change_and_print_selected(event)
elif self.active_part == "2":
self.temp_value = self.secondmenu_container.change_and_print_selected(event)
def main():
app = QApplication(sys.argv)
ex = Main_Window()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
In this implement
menu_container
s' states. This will be problematic if you don't want the key to take effect globally. Please refer to the comment by @musicamante.Press A
to be selected when the user press key A
on the keyboard. This function is not supported currently. I also considered about using QTableWidget . By handling the currentCellChanged()
signal, I get a window that may be similar to what you want.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Main_Window(QWidget):
def __init__(self):
super(). __init__()
self.setWindowTitle("Main Window")
self.layout_main = QVBoxLayout()
self.table_widget = QTableWidget(2, 3, self)
self.Press_A = QTableWidgetItem("Press A")
self.Press_B = QTableWidgetItem("Press B")
self.Press_C = QTableWidgetItem("Press C")
self.Press_X = QTableWidgetItem("Press X")
self.Press_Y = QTableWidgetItem("Press Y")
self.Press_Z = QTableWidgetItem("Press Z")
self.table_widget.setItem(0, 0, self.Press_A)
self.table_widget.setItem(0, 1, self.Press_B)
self.table_widget.setItem(0, 2, self.Press_C)
self.table_widget.setItem(1, 0, self.Press_X)
self.table_widget.setItem(1, 1, self.Press_Y)
self.table_widget.setItem(1, 2, self.Press_Z)
# self.layout_main.addWidget(self.firstmenu_container)
# self.layout_main.addWidget(self.secondmenu_container)
# make the table looks nicer
self.table_widget.horizontalHeader().hide()
self.table_widget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.table_widget.verticalHeader().hide()
self.table_widget.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
# prevent mouse to change selected item by disabling the delivery of all mouse events
self.table_widget.setAttribute(Qt.WA_TransparentForMouseEvents)
self.layout_main.addWidget(self.table_widget)
self.setLayout(self.layout_main)
self.table_widget.currentCellChanged.connect(self.on_select_changed)
def on_select_changed(self, currentRow, currentColumn, previousRow, previousColumn):
if currentRow > previousRow != -1: # != -1 is used to prevent printing when initializing the QTableWidget
print("you press down arrow and now active part is second ")
elif currentRow < previousRow != -1:
print("you press up arrow and now active part is first ")
else:
pass
current_text = self.table_widget.currentItem().text()
print("you select :" + current_text)
def main():
app = QApplication(sys.argv)
ex = Main_Window()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
In this implement
self.temp_value=1
, since the Press A
is selected when initialized. If you want no item to be selected until the key 'right' is pressed, I think extra efforts are needed to improve this solution.Press A
can not set to be selected when the user press key A
on the keyboard, either.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.