Update drawing area in gtk

I have a bunch of drawing areas (they are actually cairo surfaces, but I don’t think it is too important) in a scrollable window, and I would like to update the drawings. However, when I redraw the images, they are not displayed until I scroll the window up and down. After that, the numbers are correct, so I must conclude that the drawing procedure itself is correct. I also included

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

to wait for all pending operations, but this does not solve the problem. Can someone point me to what is still missing?

Thanks,

v923z

OK, so big pieces of code. Firstly, the class that defines the drawing area I'm going to draw onto (note that the body is not indented correctly! I don’t know how indentation is more than code snippets here):

 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 

Next, the point where I actually create the drawing area. viewport_preview is a viewport created in a clearing.

  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 

The function then draws the previews. It really is just a wrapper for the next function, and I need it only because if I delete one entry in the previews, then I will have to handle this case. I believe the while loop at the end of this function is not needed, as it will be at the end of the next.

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

Finally, the drawing function itself:

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

I think about this.

+5
source share
1 answer

You can use gtk_widget_queue_draw_area or gdk_window_invalidate_rect This gdk_window_invalidate_rect widget (or rectangle) as dirty, and after the main loop is idle, an expose event will be received where you can redraw. You can see from your description that updates occur in the expose event so these APIs can be useful. You can also check this example on a website in Cairo, where you can see the use of gtk_widget_queue_draw_area .
I did not use pygtk, but from Google I found that the corresponding call for gtk_widget_queue_draw_area is gtk.Widget.queue_draw_area and for gdk_window_invalidate_rect is gtk.gdk.Window.invalidate_rect
Hope this helps!

+3
source

Source: https://habr.com/ru/post/902457/


All Articles