问题
The documentation for use of the python wrappers for GTk3 are somewhat limited. I have found several of the common widget examples. I am trying to use the Gtk.GLArea widget. The API documentation is for C and I have not had much luck guessing the equivalent python calls to use this widget. In the example the widget is created using the following C code:
// create a GtkGLArea instance
GtkWidget *gl_area = gtk_gl_area_new ();
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
Then the render function has openGL commands in it:
static gboolean
render (GtkGLArea *area, GdkGLContext *context)
{
// inside this function it's safe to use GL; the given
// #GdkGLContext has been made current to the drawable
// surface used by the #GtkGLArea and the viewport has
// already been set to be the size of the allocation
// we can start by clearing the buffer
glClearColor (0, 0, 0, 0);
glClear (GL_COLOR_BUFFER_BIT);
// draw your object
draw_an_object ();
// we completed our drawing; the draw commands will be
// flushed at the end of the signal emission chain, and
// the buffers will be drawn on the window
return TRUE;
}
My question is how do you do the equivalent in python?
This is my attempt:
class RootWidget(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GL Example')
self.set_default_size(800,500)
gl = Gtk.GLArea()
gl.connect("render", self.gl_render)
self.add(gl)
def gl_render(self, gl):
print(gl)
Gtk.glClearColor(0,0,0,1)
Gtk.glClear(Gtk.GL_COLOR_BUFFER_BIT)
return True
You'll notice I added Gtk. to the gl commands. Not sure if this is correct but python has no idea what a glClearColor is in the function. I'm not super familiar with C namespaces but I can't figure out how the C function would understand what the gl commands are, either. The program does run and I receive the following errors in the console:
fb setup not supported
(python.exe:120048): Gdk-WARNING **: Compile failure in fragment shader:
ERROR: 0:5: 'gl_FragColor' : undeclared identifier
ERROR: 0:5: 'texture2D' : no matching overloaded function found (using implicit conversion)
Any input on this would be useful. My hope is to be able to use opengl commands to draw in a fixed widget area.
edit:
This is my latest attempt. In the on_render()
function I print the context and I do see the context property is set to a <gtk.gdk.Win32GLContext object at 0x3f133f0>
and debugging does show that that is the current context. Problem is I still get the same shader, Frag_Color, and texture errors and I'm not even calling any gl commands.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GLU import *
class MyGLArea(Gtk.GLArea):
def __init__(self):
Gtk.GLArea.__init__(self)
self.connect("realize", self.on_realize)
def on_realize(self, area):
ctx = self.get_context()
ctx.make_current()
print("The context is {}".format(self.get_property("context")))
err = self.get_error()
if err:
print(err)
return
class RootWidget(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GL Example')
self.set_default_size(800,500)
gl_area = MyGLArea()
self.add(gl_area)
win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
edit 2: Seems as if I am just having a installation issue with the GLArea widget. Seems odd since I'm using over 30 different Gtk widgets without issue. I have errors just adding the widget and not even sending commands. I ran code in Ubuntu python interpreter and it doesn't have any error creating the widget. I am having some issues with certain GL commands but may be from the python wrapper I installed. I'm still looking for the widget equivalent to pygame's or glut's init and set projection functions to setup the viewport. If anyone got ideas I'd love to hear them. The following code does run without errors:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GLU import *
class MyGLArea(Gtk.GLArea):
def __init__(self):
Gtk.GLArea.__init__(self)
self.connect("realize", self.on_realize)
self.connect("render", self.render)
def on_realize(self, area):
ctx = self.get_context()
ctx.make_current()
err = self.get_error()
if err:
print("The error is {}".format(err))
def render(self, area, ctx):
glClearColor(1,0,0,1)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
return True
class RootWidget(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GL Example')
self.set_default_size(800,500)
gl_area = MyGLArea()
self.add(gl_area)
win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
回答1:
Using the All-In-One installer for windows I noticed there is an option for OpenGL Extentions to GTK+. Now it works as expected. Here's some working code:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GL import shaders
import numpy as np
FRAGMENT_SOURCE ='''
#version 330
in vec4 inputColor;
out vec4 outputColor;
void main(){
outputColor = vec4(1.0,0.0,0.0,1.0);//constant red. I know it's a poor shader
};'''
VERTEX_SOURCE = '''
#version 330
in vec4 position;
void main(){
gl_Position = position;
}'''
class MyGLArea(Gtk.GLArea):
def __init__(self):
Gtk.GLArea.__init__(self)
self.connect("realize", self.on_realize)
self.connect("render", self.on_render)
def on_realize(self, area):
ctx = self.get_context()
print("realized", ctx)
def on_render(self, area, ctx):
ctx.make_current()
glClearColor(0, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
VERTEX_SHADER_PROG = shaders.compileShader(VERTEX_SOURCE, GL_VERTEX_SHADER)
FRAGMENT_SHADER_PROG = shaders.compileShader(FRAGMENT_SOURCE, GL_FRAGMENT_SHADER)
self.shader_prog = shaders.compileProgram(VERTEX_SHADER_PROG, FRAGMENT_SHADER_PROG)
self.create_object()
def create_object(self):
# Create a new VAO (Vertex Array Object) and bind it
vertex_array_object = glGenVertexArrays(1)
glBindVertexArray(vertex_array_object)
# Generate buffers to hold our vertices
vertex_buffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)
# Get the position of the 'position' in parameter of our shader and bind it.
position = glGetAttribLocation(self.shader_prog, 'position')
glEnableVertexAttribArray(position)
# Describe the position data layout in the buffer
glVertexAttribPointer(position, 3, GL_FLOAT, False, 0, ctypes.c_void_p(0))
# Send the data over to the buffer
vertices = np.array([-0.6, -0.6, 0.0,
0.0, 0.6, 0.0,
0.6, -0.6, 0.0,
0.7, -0.1, 0.0,
0.8, 0.1, 0.0,
0.9, -0.1, 0.0
], dtype=np.float32)
glBufferData(GL_ARRAY_BUFFER, 96, vertices, GL_STATIC_DRAW)
# Unbind the VAO first (Important)
glBindVertexArray(0)
# Unbind other stuff
glDisableVertexAttribArray(position)
glBindBuffer(GL_ARRAY_BUFFER, 0)
self.display(vertex_array_object)
def display(self, vert):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUseProgram(self.shader_prog)
glBindVertexArray(vert)
glDrawArrays(GL_TRIANGLES, 0, 3)
glDrawArrays(GL_TRIANGLES, 4, 3)
glBindVertexArray(0)
glUseProgram(0)
class RootWidget(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GL Example')
self.set_default_size(800, 500)
gl_area = MyGLArea()
gl_area.set_has_depth_buffer(False)
gl_area.set_has_stencil_buffer(False)
self.add(gl_area)
win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
回答2:
I am not sure if this works for you, but it did work for me.
The Python file:
#!/usr/bin/env python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, Gdk
from OpenGL.GL import glClearColor, glClear, glFlush, GL_COLOR_BUFFER_BIT
import os, sys
UI_FILE = "pygtk_gtkglarea.ui"
class GUI:
def __init__(self):
self.builder = Gtk.Builder()
self.builder.add_from_file(UI_FILE)
self.builder.connect_signals(self)
gl_area = Gtk.GLArea()
gl_area.connect('render', self.area_render)
gl_area.connect('realize', self.area_realize)
#gl_area.connect('create-context', self.area_context)
box = self.builder.get_object('box1')
box.pack_end(gl_area, True, True, 0)
window = self.builder.get_object('window')
window.show_all()
def area_realize (self, gl_area):
error = gl_area.get_error()
if error != None:
print("your graphics card is probably too old : ", error)
else:
print(gl_area, "realize... fine so far")
def area_context(self, gl_area):
# not needed except for special instances, read the docs
c = gl_area.get_context()
print(c , "context")
return c
def area_render(self, area, context):
#print gl_area
#print gl_context
glClearColor (0.5, 0.5, 0.5, 1.0)
glClear (GL_COLOR_BUFFER_BIT)
glFlush()
print("rendering... done")
return True
def on_window_destroy(self, window):
Gtk.main_quit()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
And the pygtk_gtkglarea.ui file:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkWindow" id="window">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">window</property>
<property name="default_width">500</property>
<property name="default_height">400</property>
<signal name="destroy" handler="on_window_destroy" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</interface>
来源:https://stackoverflow.com/questions/47565884/use-of-the-gtk-glarea-in-pygobject-gtk3