обновить область рисования в gtk - PullRequest
5 голосов
/ 26 ноября 2011

У меня есть несколько областей рисования (они на самом деле являются поверхностями Каира, но я не думаю, что это имеет большое значение) в прокручиваемом окне, и я хотел бы обновить рисунки. Однако, когда я перерисовываю изображения, они не отображаются, пока я не прокручиваю окно вверх и вниз. После этого цифры верны, поэтому я должен сделать вывод, что сама процедура рисования правильная. Я также включил

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

цикл ожидания всех ожидающих операций, но это не решает проблему. Может ли кто-нибудь указать мне, что еще не хватает?

Спасибо

v923z

ОК, так что большие куски кода. Во-первых, класс, определяющий область рисования, в которую я собираюсь рисовать (обратите внимание, что тело не имеет правильного отступа! Я не знаю, как сделать отступ для больших кусков кода здесь):

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

Далее, точка, где я на самом деле создаю область рисования. viewport_preview - видовой экран, созданный на поляне.

    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

Тогда функция рисования превью. На самом деле это просто оболочка для следующей функции, и мне нужно было это только потому, что если я удаляю одну запись в предварительном просмотре, то мне приходится обрабатывать этот случай. Я полагаю, что цикл while в конце этой функции не является необходимым, так как он все равно будет в конце следующего.

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

Наконец, сама функция рисования:

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

Я думаю, вот и все.

1 Ответ

3 голосов
/ 27 ноября 2011

Вы можете использовать gtk_widget_queue_draw_area или gdk_window_invalidate_rect. Это пометит виджет (или прямоугольник) как грязный, и когда основной цикл простаивает, событие expose будет получил где можно перерисовать. Из вашего описания видно, что обновления происходят при событии expose, поэтому эти API могут быть полезны. Также вы можете проверить этот образец на сайте в Каире, где вы можете увидеть использование gtk_widget_queue_draw_area.
Я не использовал pygtk, но из Google я обнаружил, что соответствующий вызов для gtk_widget_queue_draw_area равен gtk.Widget.queue_draw_area, а для gdk_window_invalidate_rect равен gtk.gdk.Window.invalidate_rect
Надеюсь, это поможет!

...