Reputation: 597
As far as I understand, QOpenGlWidget
uses the same window context as any other widget.
I thought it would be a good idea to use keyPressEvent
to handle drawing commands.
Unfortunately, it doesn't work as expected. When I handle a Key_Escape
to exit app then it works, but when I try to handle Key_W
or Key_F
for OpenGL drawing functions, it doesn't react.
Is that a problem with a GL functions or I'm doing event handling in a wrong way?
UPD: I also try to update widget in event, It totally mess up everything on a screen. I've done the same with my GLFW project, works fine.
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_())
Upvotes: 2
Views: 1773
Reputation: 211277
Before an OpenGL instruction can be executed, the [OpenGL Context](OpenGL Context) has to be made current.
The system automatically makes the context current before the paintGL
or resizeGL
but it does not so before keyPressEvent
. Because of that the OpebGL instructions in keyPressEvent
have no effect.
Use a state for the polygon mode and change the state in keyPressEvent
, but call glPolygonMode
in paintGL
to solve the issue. e.g.:
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()
Upvotes: 2