2011-11-26 10 views
6

Tengo un montón de áreas de dibujo (en realidad son superficies de cairo, pero no creo que importe demasiado) en una ventana desplazada, y me gustaría actualizar los dibujos. Sin embargo, cuando vuelvo a dibujar las imágenes, no se muestran hasta que muevo la ventana hacia arriba y hacia abajo. Después de eso, las cifras son correctas, así que tengo que concluir que la rutina de dibujo en sí es correcta. También he incluido unactualizar área de dibujo en gtk

while Gtk.events_pending(): 
     Gtk.main_iteration() 

loop para esperar todas las operaciones pendientes, pero eso no resuelve el problema. ¿Podría alguien indicarme qué más falta?

Gracias,

v923z

OK, por lo que los trozos más grandes del código. En primer lugar, una clase que define el área de un dibujo sobre el que voy a pintar (tenga en cuenta que el cuerpo no tiene sangría correctamente No sé cómo se va a sangrar códigos muy grandes aquí!):

class Preview: 
def __init__(self): 
    self.frame = Gtk.Frame() 
    self.frame.set_shadow_type(Gtk.ShadowType.IN) 
    self.frame.show() 
    self.da = Gtk.DrawingArea() 
    self.da.set_size_request(200, 300) 
    self.da.connect('configure-event', self.configure_event) 
    self.da.connect('draw', self.on_draw) 
    self.frame.add(self.da) 
    self.da.show() 

def configure_event(self, da, event): 
    allocation = da.get_allocation() 
    self.surface = da.get_window().create_similar_surface(cairo.CONTENT_COLOR, 
                  allocation.width, 
                  allocation.height) 
    cairo_ctx = cairo.Context(self.surface) 
    cairo_ctx.set_source_rgb(1, 1, 1) 
    cairo_ctx.paint() 
    return True 

def on_draw(self, da, cairo_ctx): 
    cairo_ctx.set_source_surface(self.surface, 0, 0) 
    cairo_ctx.paint() 
    return True 

pass 

A continuación, el punto donde realmente creo el área de dibujo. viewport_preview es una ventana gráfica creada en glade.

self.previews = [] 
    self.widget('viewport_preview').remove(self.vbox_preview) 
    self.vbox_preview = Gtk.VBox(homogeneous=False, spacing=8) 
    self.widget('viewport_preview').add(self.vbox_preview) 
    self.vbox_preview.show() 

    for page in self.pages: 
     preview = Preview() 
     self.vbox_preview.pack_start(preview.frame, False, False, 10) 
     self.previews.append(preview) 
     while Gtk.events_pending(): 
      Gtk.main_iteration() 

    self.draw_preview(None) 

    return True 

Luego, la función que dibuja las vistas previas. Esto es realmente solo un contenedor para la siguiente función, y lo necesitaba solo porque si eliminé una entrada en las vistas previas, entonces tengo que manejar ese caso. Creo que el ciclo while al final de esta función no es necesario, ya que de todos modos estará al final de la siguiente.

def draw_preview(self, counter=None): 
    if counter is not None: 
     self.vbox_preview.remove(self.previews[counter].frame) 
     self.previews.pop(counter) 
     self.pages.pop(counter) 
     self.vbox_preview.show() 
     while Gtk.events_pending(): 
      Gtk.main_iteration() 

    for i in range(len(self.pages)):  
     self.draw_note(self.previews[i].da, self.previews[i].surface, self.pages[i])    

    while Gtk.events_pending(): 
     Gtk.main_iteration() 

Por último, la función de dibujo en sí:

def draw_note(self, widget, surface, page): 
    list_pos = '%d/%d'%(self.page + 1, len(self.pages)) 
    self.widget('label_status').set_text(list_pos) 
    cairo_ctx = cairo.Context(surface) 
    cairo_ctx.set_source_rgb(page.background[0], page.background[1], page.background[2]) 
    cairo_ctx.paint() 

    width, height = widget.get_size_request() 
    xmin, xmax, ymin, ymax = fujitsu.page_size(page) 

    factor = min(height/(2.0 * self.margin + ymax - ymin), width/(2.0 * self.margin + xmax - xmin)) 
    factor *= 0.8 
    page.scale = factor 
    value = self.widget('adjustment_smooth').get_value() 
    #print value 

    for pen in page.pagecontent: 
     x = self.margin + pen.path[0][0] - xmin 
     y = self.margin + pen.path[0][1] - ymin 

     cairo_ctx.move_to(x * factor, y * factor) 
     if self.widget('checkbutton_smooth').get_active() == False: 
      [cairo_ctx.line_to((self.margin + x - xmin) * factor, 
         (self.margin + y - ymin) * factor) for x, y in pen.path] 
     else: 
      bezier_curve = bezier.expand_coords(pen.path, value) 
      x = self.margin + bezier_curve[0][0][0] - xmin 
      y = self.margin + bezier_curve[0][0][1] - ymin 
      cairo_ctx.move_to(x * factor, y * factor) 
      [cairo_ctx.curve_to((self.margin + control[1][0] - xmin) * factor, 
           (self.margin + control[1][1] - ymin) * factor, 
           (self.margin + control[2][0] - xmin) * factor, 
           (self.margin + control[2][1] - ymin) * factor, 
           (self.margin + control[3][0] - xmin) * factor, 
           (self.margin + control[3][1] - ymin) * factor) 
                for control in bezier_curve] 

     cairo_ctx.set_line_width(pen.thickness * self.zoom_factor) 
     cairo_ctx.set_source_rgba(pen.colour[0], pen.colour[1], pen.colour[2], pen.colour[3]) 
     cairo_ctx.stroke() 

    cairo_ctx.rectangle(0, height * 0.96, width, height) 
    cairo_ctx.set_source_rgba(page.banner_text[0][0], page.banner_text[0][1], page.banner_text[0][2], page.banner_text[0][3]) 
    cairo_ctx.fill() 
    cairo_ctx.move_to(width * 0.05, height * 0.99) 
    cairo_ctx.show_text(self.filename + ' ' + list_pos) 
    cairo_ctx.set_font_size(self.zoom_factor * 10.0) 
    xbearing, ybearing, twidth, theight, xadvance, yadvance = (cairo_ctx.text_extents(page.banner_text[3])) 
    cairo_ctx.move_to(width - 1.03 * twidth, height * 0.99) 
    cairo_ctx.show_text(page.banner_text[3]) 
    cairo_ctx.set_source_rgba(0, 0, 0.9, 0.90) 
    cairo_ctx.stroke() 
    rect = widget.get_allocation() 
    widget.get_window().invalidate_rect(rect, False) 
    while Gtk.events_pending(): 
     Gtk.main_iteration() 

creo que eso es todo.

Respuesta

3

Usted podría utilizar gtk_widget_queue_draw_area o gdk_window_invalidate_rect .Esta marcará el widget (o rectángulo) como sucia y una vez que el bucle principal está inactivo expose caso se recibirán en donde usted puede volver a dibujar. Según su descripción, parece que las actualizaciones están sucediendo en el evento expose, por lo que estas API podrían ser útiles. También puede marcar this sample desde el sitio de cairo donde puede ver el uso de gtk_widget_queue_draw_area.
No he utilizado pygtk sino de Google me encontré con que la correspondiente convocatoria de gtk_widget_queue_draw_areagtk.Widget.queue_draw_area es & para gdk_window_invalidate_rect es gtk.gdk.Window.invalidate_rect
Espero que esto ayude!

+0

Gracias por la respuesta! Desafortunadamente, eso no parece resolver el problema. De hecho, he tenido gtk.gdk.Window.invalidate_rect todo el tiempo, y es cierto que si lo dejo, el lienzo no se actualiza en absoluto. Lo que encuentro bastante extraño es que mi rutina de dibujo pinta el lienzo en blanco y luego dibuja líneas sobre él, y la pintura siempre está lista, pero las líneas solo se muestran si muevo las ventanas desplazadas. Por lo tanto, parece que el widget se actualiza al menos una vez. – v923z

+0

@ v923z: ¡Ah está bien! ¡Realmente parecía un caso de eventos de exposición perdidos! Suena extraño, sin embargo ... estás actualizando el lienzo en exponer devoluciones de eventos de eventos. Supongo que & canvas se está actualizando. Espera unos pocos dibujos de líneas faltantes, ¿es así? Si es posible, tal vez podría publicar algunos bits de código ... podríamos intentar ayudar –

+0

¡Gracias por los comentarios! He actualizado mi publicación original. – v923z