-2

I have two PyQt5 widgets and both need keyboard input. Initially, one widget has the setFocusPolicy set to QtCore.Qt.StrongFocus, but when both widgets has this property activated, both of them get the input. I would like to initially set the input in one of them and if the user clicks in the other widget, the focus would be changed to the clicked widget or vice versa.

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_())
Jaime02
  • 299
  • 7
  • 21

1 Answers1

1

Based on your code, I'm not getting key events from the Diedrico widget, but only from the Renderizador and UiVentana instancies; with your implementation it seems very unlikely that you get key events from both the Renderizador and Diedrico widgets, since their parent hierarchy is completely different and they actually are members of different "physical" windows.

If you really get the Widget and OpenGL outputs from a single key event, it might be a bug, but, frankly, I doubt that, and that's mostly because there are some issues in your implementation, mostly due to confusing parent/child relationship.

If that's not the case (meaning that you're getting the key events from Renderizador and UiVentana), the explanation is simple: a QOpenGLWidget, as any basic QWidget class, doesn't process nor "consume" a key event; as soon as you call the base implementation with super() the event is propagated to its parents (UiVentana, in your case). If you want to stop the event propagation, just return without calling the base implementation of keyPressEvent.

Finally, some notes about your example. When you want to add a widget to a scene, it must have a parent that is already embedded in the scene or it shouldn't have a parent at all (as in a top level widget). In your code you created the Diedrico widget setting its parent to a child of the "widget_central", which at that point is a widget without no parent (meaning that it would be a top level widget, as in a "window"): no matter what you do afterwards (setting it as the central widget), the topmost parent has not been embedded, and you can't add any of its child to a scene.
Qt itself warns about this when executing your code:

StdErr: QGraphicsProxyWidget::setWidget: cannot embed widget 0x911ae78 which is not a toplevel widget, and is not a child of an embedded widget

Then, you created the view, but you never actually add it to the main window or any of its children. You can see the Diedrico instance only because of the aforementioned problem: the widget is added to the main widget because of the parent set in the class initialization, but it's never added to the scene.

Be very careful when initializing widgets and setting parents, expecially when you're going to embed them into a QGraphicsScene: QWidgets added to a scene are actually QGraphicsProxyWidgets, not "actual" widgets, and some special care is required when dealing with them.

musicamante
  • 41,230
  • 6
  • 33
  • 58