PySide2 QOpenGLWidget 按键事件不起作用
Posted
技术标签:
【中文标题】PySide2 QOpenGLWidget 按键事件不起作用【英文标题】:PySide2 QOpenGLWidget key events doesn't work 【发布时间】:2020-02-04 16:30:07 【问题描述】:据我了解,QOpenGlWidget
使用与任何其他小部件相同的窗口上下文。
我认为使用 keyPressEvent
来处理绘图命令是个好主意。
不幸的是,它没有按预期工作。当我处理 Key_Escape
以退出应用程序时,它可以工作,但是当我尝试为 OpenGL 绘图函数处理 Key_W
或 Key_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_())
【问题讨论】:
【参考方案1】:在执行 OpenGL 指令之前,必须将 [OpenGL Context](OpenGL Context) 设为最新。
系统会在paintGL
或resizeGL
之前自动使上下文成为当前上下文,但在keyPressEvent
之前不会如此。因此,keyPressEvent
中的 OpebGL 指令无效。
使用多边形模式的状态并在keyPressEvent
中更改状态,但在paintGL
中调用glPolygonMode
来解决问题。例如:
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()
【讨论】:
以上是关于PySide2 QOpenGLWidget 按键事件不起作用的主要内容,如果未能解决你的问题,请参考以下文章