Graphics glitch when drawing to a Cairo context obtained from a gtk.DrawingArea inside a gtk.Viewport.
- by user410023
I am trying to redraw the part of the DrawingArea that is visible in the Viewport in the expose-event handler. However, it seems that I am doing something wrong with the coordinates that are passed to the event handler because there is garbage at the edge of the Viewport when scrolling. Can anyone tell what I am doing wrong? Here is a small example:
import pygtk
pygtk.require("2.0")
import gtk
from numpy import array
from math import pi
class Circle(object):
def init(self, position = [0., 0.], radius = 0., edge = (0., 0., 0.), fill = None):
self.position = position
self.radius = radius
self.edge = edge
self.fill = fill
def draw(self, ctx):
rect = array(ctx.clip_extents())
rect[2] -= rect[0]
rect[3] -= rect[1]
center = rect[2:4] / 2
ctx.arc(center[0], center[1], self.radius, 0., 2. * pi)
if self.fill != None:
ctx.set_source_rgb(*self.fill)
ctx.fill_preserve()
ctx.set_source_rgb(*self.edge)
ctx.stroke()
class Scene(object):
class Proxy(object):
directory = {}
def init(self, target, layers = set()):
self.target = target
self.layers = layers
Scene.Proxy.directory[target] = self
def __init__(self, viewport):
self.objects = {}
self.layers = [set()]
self.viewport = viewport
self.signals = {}
def draw(self, ctx):
x = self.viewport.get_hadjustment().value
y = self.viewport.get_vadjustment().value
ctx.set_source_rgb(1., 1., 1.)
ctx.paint()
ctx.translate(x, y)
for obj in self:
obj.draw(ctx)
def add(self, item, layer = 0):
item = Scene.Proxy(item, layers = set((layer,)))
assert(hasattr(item.target, "draw"))
assert(isinstance(layer, int))
item.layers.add(layer)
while not layer < len(self.layers):
self.layers.append(set())
self.layers[layer].add(item)
if not item in self.objects:
self.objects[item] = set()
self.objects[item].add(layer)
def remove(self, item, layers = None):
item = Scene.Proxy.directory[item]
if layers == None:
layers = self.objects[item]
for layer in layers:
layer.remove(item)
item.layers.remove(layer)
if len(item.layers) == 0:
self.objects.remove(item)
def __iter__(self):
for layer in self.layers:
for item in layer:
yield item.target
class App(object):
def init(self):
signals = {
"canvas_exposed": self.update_canvas,
"gtk_main_quit": gtk.main_quit
}
self.builder = gtk.Builder()
self.builder.add_from_file("graphics_glitch.glade")
self.window = self.builder.get_object("window")
self.viewport = self.builder.get_object("viewport")
self.canvas = self.builder.get_object("canvas")
self.scene = Scene(self.viewport)
signals.update(self.scene.signals)
self.builder.connect_signals(signals)
self.window.show()
def update_canvas(self, widget, event):
ctx = self.canvas.window.cairo_create()
self.scene.draw(ctx)
ctx.clip()
if name == "main":
app = App()
scene = app.scene
scene.add(Circle((0., 0.), 10.))
gtk.main()
And the Glade file "graphics_glitch.glade":
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="window">
<property name="width_request">200</property>
<property name="height_request">200</property>
<property name="visible">True</property>
<signal name="destroy" handler="gtk_main_quit"/>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hadjustment">h_adjust</property>
<property name="vadjustment">v_adjust</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkViewport" id="viewport">
<property name="visible">True</property>
<property name="resize_mode">queue</property>
<child>
<object class="GtkDrawingArea" id="canvas">
<property name="width_request">640</property>
<property name="height_request">480</property>
<property name="visible">True</property>
<signal name="expose_event" handler="canvas_exposed"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkAdjustment" id="h_adjust">
<property name="lower">-1000</property>
<property name="upper">1000</property>
<property name="step_increment">1</property>
<property name="page_increment">25</property>
<property name="page_size">25</property>
</object>
<object class="GtkAdjustment" id="v_adjust">
<property name="lower">-1000</property>
<property name="upper">1000</property>
<property name="step_increment">1</property>
<property name="page_increment">25</property>
<property name="page_size">25</property>
</object>
</interface>
Thanks!
--Dan