通过单击小部件更改小部件焦点

时间:2019-09-10 20:31:35

标签: python-3.x user-interface pyqt5

我有两个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_())

1 个答案:

答案 0 :(得分:1)

根据您的代码,我不会从Diedrico小部件获取关键事件,而只是从RenderizadorUiVentana实例获取事件;在实现过程中,似乎不太可能同时从RenderizadorDiedrico小部件中获取键事件,因为它们的父级层次结构完全不同,并且它们实际上是不同“物理”窗口的成员。

如果您真的从单个键事件中获得了WidgetOpenGL的输出,则可能是一个错误,但是坦率地说,我对此表示怀疑,这主要是因为您的实现过程中存在一些问题,主要是由于父子关系混乱造成的。

如果不是这种情况(意味着您正在从RenderizadorUiVentana获取关键事件),说明很简单:与任何基本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个,而不是“实际”小部件,并且需要特别注意与他们打交道是必需的。

相关问题