PySide2 QOpenGLWidget键事件不起作用

问题描述 投票:0回答:1

据我了解,QOpenGlWidget使用的窗口上下文与任何其他小部件相同。我认为使用keyPressEvent处理绘图命令是个好主意。

不幸的是,它没有按预期工作。当我处理Key_Escape退出应用程序时,它可以工作,但是当我尝试处理OpenGL绘图功能的Key_WKey_F时,它没有反应。

是GL功能出现问题还是我以错误的方式进行事件处理?

UPD:我也尝试在事件中更新小部件,它完全弄乱了屏幕上的所有内容。我对GLFW项目也做过同样的工作,效果很好。

import numpy as np
from OpenGL.GL import *
from PySide2 import QtOpenGL, QtWidgets, QtCore, QtGui


class Viewport(QtWidgets.QOpenGLWidget):
    def __init__(self, width: int, height: int, title :str="Qt OpenGl Window", 
                 r: int=0.2, g: int=0.3, b: int=0.3, a: int=1.0):
        super().__init__()
        self.width = width
        self.height = height
        self.bg_color = (r, g, b, a)

        self.setWindowTitle(title)
        self.resize(self.width, self.height)

        self.bool_shaded = True

        self.vertices = np.array([], dtype=np.float32)

        # Should be OpenGL.GL.shaders.ShaderProgram
        self.shader_program = None
        # Should be int to be used in "layout (location = attr_position)..."
        self.attr_position = None

    def initializeGL(self):

        VBO = self.__createVBO(self.vertices)

        # Create and bind here once because we have only one VAO that there's no need to bind every time
        VAO = self.__createVAO()

        self.shader_program = self.__compileShaders(path_vertex="shaders/triangle.vs",
                                                path_fragment="shaders/triangle.fs")
        self.attr_position = self.createAttribute(self.shader_program, "a_position", 0)

    def paintGL(self):

        glClear(GL_COLOR_BUFFER_BIT)
        glClearColor(self.bg_color[0], self.bg_color[1],
                 self.bg_color[2], self.bg_color[3])
        glUseProgram(self.shader_program)
        glDrawArrays(GL_TRIANGLES, 0, 3)

    def resizeGL(self, w: int, h: int):
        glViewport(0, 0, w, h)

    def keyPressEvent(self, event: QtGui.QKeyEvent):
        if event.key() == QtCore.Qt.Key_Escape:
            app.exit()

        if event.key() == QtCore.Qt.Key_W:
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)

        if event.key() == QtCore.Qt.Key_F:
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

        if event.key() == QtCore.Qt.Key_P:
            glPolygonMode(GL_FRONT_AND_BACK, GL_POINT)

        event.accept()

    def __createVBO(self, vertices :np.ndarray):

        VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)

        return VBO

    def __createVAO(self):
        VAO = glGenVertexArrays(1)
        glBindVertexArray(VAO)

        return VAO

    def __compileShaders(self, path_vertex: str, path_fragment: str):
        with open(path_vertex, "r") as source:
            vertex = compileShader(source.read(), GL_VERTEX_SHADER)

        with open(path_fragment, "r") as source:
            fragment = compileShader(source.read(), GL_FRAGMENT_SHADER)

        shader_program = compileProgram(vertex, fragment)

        return shader_program

    def createAttribute(self, shader, attrib_name: str, stride: 
        attribute = glGetAttribLocation(shader, attrib_name)
        glEnableVertexAttribArray(attribute)
        glVertexAttribPointer(attribute, 3, GL_FLOAT, GL_FALSE, stride, ctypes.c_void_p(0))

        return attribute

    def setVertices(self, vertex_list: list):
        vertices = np.array(vertex_list, dtype=np.float32)
        self.vertices = vertices

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    window = Viewport(1280, 720)

    vertices = [-0.5, -0.5, 0.0,
                0.5, -0.5, 0.0,
                0.0, 0.5, 0.0]
    window.setVertices(vertices)

    window.show()
    window.printDebugInfo()

    sys.exit(app.exec_())
python pyside2 pyopengl
1个回答
0
投票

在执行OpenGL指令之前,必须使[OpenGL上下文](OpenGL上下文)为最新。系统会自动将上下文设为paintGLresizeGL之前的当前上下文,但不会自动设为keyPressEvent之前的上下文。因此,keyPressEvent中的OpebGL指令无效。

将状态用于多边形模式并在keyPressEvent中更改状态,但是在glPolygonMode中调用paintGL解决该问题。例如:]]

class Viewport(QtWidgets.QOpenGLWidget):
    # [...]

    def initializeGL(self):

        self.polygonmode = GL_FILL

        # [...]

    def paintGL(self):

        glPolygonMode(GL_FRONT_AND_BACK, self.polygonmode)

        # [...]

    def keyPressEvent(self, event: QtGui.QKeyEvent):
        if event.key() == QtCore.Qt.Key_Escape:
            app.exit()

        if event.key() == QtCore.Qt.Key_W:
            self.polygonmode = GL_LINE

        if event.key() == QtCore.Qt.Key_F:
            self.polygonmode = GL_FILL

        if event.key() == QtCore.Qt.Key_P:
             self.polygonmode = GL_POINT

        event.accept()
© www.soinside.com 2019 - 2024. All rights reserved.