【问题标题】:refresh drawing area in gtk刷新gtk中的绘图区域
【发布时间】:2012-01-07 00:32:40
【问题描述】:

我在滚动窗口中有一堆绘图区域(它们实际上是 cairo 表面,但我认为这并不重要),我想刷新绘图。但是,当我重绘图像时,直到我上下滚动窗口才会显示它们。之后数字是正确的,所以我必须得出结论,绘图程序本身是正确的。我还包括了一个

    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 是在 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

然后是绘制预览的函数。这实际上只是下一个函数的包装,我需要它只是因为如果我在预览中删除一个条目,那么我必须处理这种情况。我相信,这个函数末尾的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()

我想就是这样。

【问题讨论】:

    标签: gtk drawing refresh pygtk area


    【解决方案1】:

    您可以使用gtk_widget_queue_draw_areagdk_window_invalidate_rect。这会将小部件(或矩形)标记为脏,并且一旦主循环空闲expose 事件将在您可以重绘的位置收到。根据您的描述,更新似乎是在 expose 事件上发生的,因此这些 API 可能有用。您也可以从 cairo 站点查看this sample,在该站点中您可以看到gtk_widget_queue_draw_area 的用法。
    我没有使用 pygtk,但从谷歌我发现 gtk_widget_queue_draw_area 的相应调用是 gtk.Widget.queue_draw_areagdk_window_invalidate_rect 的相应调用是 gtk.gdk.Window.invalidate_rect
    希望这会有所帮助!

    【讨论】:

    • 感谢您的回复!不幸的是,这似乎并不能解决问题。事实上,我一直都有 gtk.gdk.Window.invalidate_rect ,如果我把它排除在外,那么画布根本不会更新。我觉得很奇怪的是,我的绘图例程将画布涂成白色,然后在上面画线,并且画总是完成,但只有当我滚动滚动窗口时才会显示线条。因此,小部件似乎至少更新了一次。
    • @v923z: 好吧!这确实看起来像是缺少暴露事件的情况!虽然听起来很奇怪......你正在更新我认为的公开事件回调中的画布并且画布正在更新,期待一些缺少的线条图,是这样吗?如果可能的话,也许你可以发布一些代码......我们可以尝试提供帮助
    猜你喜欢
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-28
    • 1970-01-01
    • 1970-01-01
    • 2014-02-09
    相关资源
    最近更新 更多