Ключевые события PySide2 QOpenGLWidget не работают - PullRequest
1 голос
/ 04 февраля 2020

Насколько я понимаю, QOpenGlWidget использует тот же контекст окна, что и любой другой виджет. Я подумал, что было бы неплохо использовать keyPressEvent для обработки команд рисования.

К сожалению, это не работает должным образом. Когда я обрабатываю Key_Escape для выхода из приложения, он работает, но когда я пытаюсь обработать Key_W или Key_F для функций рисования OpenGL, он не реагирует.

Это проблема с Функции 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_())

1 Ответ

1 голос
/ 04 февраля 2020

Прежде чем можно выполнить инструкцию OpenGL, [контекст OpenGL] (контекст OpenGL) должен быть актуальным. Система автоматически делает контекст текущим до paintGL или resizeGL, но не до keyPressEvent. Из-за этого инструкции OpebGL в keyPressEvent не действуют.

Используйте состояние для режима многоугольника и измените состояние в 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()
...