2011-11-26 12 views
6

Ho un sacco di aree di disegno (in realtà sono superfici del cairo, ma non credo che importi troppo) in una finestra a scorrimento, e vorrei aggiornare i disegni. Tuttavia, quando ridisegno le immagini, esse non vengono visualizzate finché non faccio scorrere la finestra su e giù. Dopo che le cifre sono corrette, quindi devo concludere che la stessa routine di disegno è corretta. Ho anche incluso unorinfrescare l'area di disegno in gtk

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

loop per attendere tutte le operazioni in sospeso, ma ciò non risolve il problema. Qualcuno potrebbe indicarmi cos'altro manca?

Grazie,

v923z

OK, in modo che i grandi blocchi di codice. In primo luogo, una classe che definisce l'area di un disegno su cui ho intenzione di dipingere (si noti che il corpo non è rientrato correttamente non so come rientrare più grandi pezzi di codice qui!):

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 

Avanti, il punto in cui effettivamente creo l'area di disegno. viewport_preview è una finestra creata in 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 

Quindi la funzione che traccia le anteprime. Questo è davvero solo un wrapper per la prossima funzione, e avevo bisogno di questo solo perché se elimino una voce nelle anteprime, allora devo gestire quel caso. Credo che il ciclo while alla fine di questa funzione non sia necessario, poiché sarà comunque alla fine di quello successivo.

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() 

Infine, la funzione disegno stesso:

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() 

penso che su di esso.

risposta

3

Si potrebbe utilizzare gtk_widget_queue_draw_area o gdk_window_invalidate_rect .Questo segnerà il widget (o rettangolo) come sporca e una volta che il ciclo principale è inattivo sarà ricevuto expose evento in cui è possibile ridisegnare. Dalla tua descrizione sembra che gli aggiornamenti stiano accadendo sull'evento expose, quindi queste API potrebbero essere utili. Inoltre è possibile controllare this sample dal sito cairo in cui è possibile vedere l'utilizzo di gtk_widget_queue_draw_area.
Non ho usato pygtk ma da Google ho scoperto che la chiamata corrispondente per gtk_widget_queue_draw_area è gtk.Widget.queue_draw_area & per gdk_window_invalidate_rect è gtk.gdk.Window.invalidate_rect
Spero che questo aiuti!

+0

Grazie per la risposta! Sfortunatamente, questo non sembra risolvere il problema. In effetti, ho sempre avuto gtk.gdk.Window.invalidate_rect, ed è vero che se lo lascio fuori la tela non viene affatto aggiornata. Quello che trovo piuttosto strano è che la mia routine di disegno dipinge la tela bianca e poi disegna linee su di essa, e il dipinto è sempre fatto, ma le linee sono mostrate solo se faccio scorrere le finestre a scorrimento. Quindi, sembra che il widget sia aggiornato almeno una volta. – v923z

+0

@ v923z: Ah ok! Sembrava davvero un caso di eventi mancati di esposizione! Suona strano però ... stai aggiornando la tela nel richiamo dell'evento expose Suppongo che la tela sia in fase di aggiornamento aspettati per alcuni disegni di linee mancanti, è così? Se possibile forse potresti postare qualche pezzetto di codice ... potremmo provare ad aiutare –

+0

Grazie per il feedback! Ho aggiornato il mio post originale. – v923z