我有两个PyQt5小部件,并且都需要键盘输入。最初,一个小部件的setFocusPolicy
设置为QtCore.Qt.StrongFocus
,但是当两个小部件都激活了此属性时,它们都将获得输入。我想首先在其中一个中设置输入,如果用户单击另一个小部件,则焦点将更改为单击的小部件,反之亦然。
MRE:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtWidgets import QOpenGLWidget, QWidget
import sys
class Renderizador(QOpenGLWidget):
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_W:
print("OpenGL")
super().keyPressEvent(event)
class Diedrico(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
def paintEvent(self, event):
qp = QPainter(self)
qp.setPen(QPen(Qt.black))
qp.drawRect(0, 0, 1000, 1000) # Marco
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_W:
print("Widget")
super().keyPressEvent(event)
class UiVentana(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UiVentana, self).__init__(parent)
self.resize(1500, 1015)
self.setFixedSize(1500, 1015)
self.statusBar().setSizeGripEnabled(False)
self.widget_central = QtWidgets.QWidget(self)
self.Renderizador = Renderizador(self.widget_central)
self.Renderizador.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
self.Renderizador.setFocusPolicy(QtCore.Qt.StrongFocus)
visor = QtWidgets.QWidget(self.widget_central)
visor.setGeometry(1010, 510, 470, 460)
self.scene = QtWidgets.QGraphicsScene(visor)
self.view = QtWidgets.QGraphicsView(self.scene)
self.diedrico = Diedrico(visor)
self.diedrico.setFixedSize(470, 460)
self.view.setFocusPolicy(QtCore.Qt.StrongFocus)
self.scene.addWidget(self.diedrico)
self.setCentralWidget(self.widget_central)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_W:
print("Ui")
super().keyPressEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
ui = UiVentana()
ui.show()
sys.exit(app.exec_())
答案 0 :(得分:1)
根据您的代码,我不会从Diedrico
小部件获取关键事件,而只是从Renderizador
和UiVentana
实例获取事件;在实现过程中,似乎不太可能同时从Renderizador
和Diedrico
小部件中获取键事件,因为它们的父级层次结构完全不同,并且它们实际上是不同“物理”窗口的成员。
如果您真的从单个键事件中获得了Widget
和OpenGL
的输出,则可能是一个错误,但是坦率地说,我对此表示怀疑,这主要是因为您的实现过程中存在一些问题,主要是由于父子关系混乱造成的。
如果不是这种情况(意味着您正在从Renderizador
和UiVentana
获取关键事件),说明很简单:与任何基本QWidget类一样,QOpenGLWidget不会处理也不“消费”关键事件;只要您使用super()
调用基本实现,事件就会传播到其父对象(在您的情况下为UiVentana
)。如果要停止事件传播,只需返回而无需调用keyPressEvent
的基本实现。
最后,关于您的示例的一些注释。
当您要将小部件添加到场景时,它必须具有已经嵌入到场景中的父级,或者它根本不应该具有父级 (如顶级小部件中一样)。在您的代码中,您创建了Diedrico小部件,将其父级设置为“ widget_central
”的子级,这时它是没有父级的小部件(这意味着它将是顶级小部件,如“窗口” ”):无论您随后做什么(将其设置为中央小部件),都不会嵌入最顶层的父级,并且无法将其任何子级添加到场景中。
Qt本身在执行代码时会对此发出警告:
StdErr: QGraphicsProxyWidget::setWidget: cannot embed widget 0x911ae78 which is not a toplevel widget, and is not a child of an embedded widget
然后,您创建了视图,但实际上从未将其添加到主窗口或其任何子窗口中。您只能看到Diedrico
实例是因为上述问题:该小部件是由于类初始化中的父集而添加到主小部件中的,但从未将其添加到场景中。
初始化小部件和设置父级时要特别小心,特别是当您将其嵌入QGraphicsScene中时:添加到场景中的Q小部件实际上是QGraphicsProxyWidget
个,而不是“实际”小部件,并且需要特别注意与他们打交道是必需的。