刷新gtk中的绘图区域
我在滚动窗口中有一堆绘图区域(它们实际上是开罗表面,但我认为这并不重要),我想刷新绘图。但是,当我重新绘制图像时,直到上下滚动窗口后才会显示它们。之后数字是正确的,所以我必须得出结论,绘图例程本身是正确的。我还包括一个
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()
我想仅此而已。
I have a bunch of drawing areas (they are actually cairo surfaces, but I don't think it matters too much) in a scrolled window, and I would like to refresh the drawings. However, when I redraw the images, they are not shown till I scroll the window up and down. After that the figures are correct, so I have to conclude that the drawing routine itself is proper. I have also included a
while Gtk.events_pending():
Gtk.main_iteration()
loop to wait for all pending operations, but that does not solve the problem. Could someone point out to me what else is missing?
Thanks,
v923z
OK, so the larger chunks of the code. First, a class defining the a drawing area onto which I am going to paint (note that the body is not indented properly! I don't know how to indent larger pieces of code 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 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
Then the function drawing the previews. This is really just a wrapper for the next function, and I needed this only because if I delete one entry in the previews, then I have to handle that case. I believe, the while loop at the end of this function is not necessary, for it will be at the end of the next one anyway.
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 that's about it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以使用
gtk_widget_queue_draw_area
或gdk_window_invalidate_rect
这会将小部件(或矩形)标记为脏,并且一旦主循环空闲,将在您可以重绘的位置接收expose
事件。从您的描述来看,更新似乎是在expose
事件上发生的,因此这些 API 可能有用。您还可以从 cairo 站点查看此示例,您可以在其中看到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
希望这有帮助!
You could use
gtk_widget_queue_draw_area
orgdk_window_invalidate_rect
.This will mark the widget (or rectangle) as dirty and once the main loop is idleexpose
event will be received where in you can redraw. From you description it appears the updates are happening onexpose
event so these APIs might be of use. Also you can check this sample from the cairo site where in you can see the usage ofgtk_widget_queue_draw_area
.I have not used pygtk but from Google I found that the corresponding call for
gtk_widget_queue_draw_area
isgtk.Widget.queue_draw_area
& forgdk_window_invalidate_rect
isgtk.gdk.Window.invalidate_rect
Hope this helps!