2011-11-26 2 views
6

스크롤 영역에 무리가 있습니다 (실제로 카이로 표면이지만 너무 중요하지는 않습니다). 스크롤 된 창에서 그림을 새로 고침하고 싶습니다. 그러나 이미지를 다시 그릴 때 창을 위아래로 스크롤 할 때까지 이미지가 표시되지 않습니다. 그 후 수치가 정확하므로 드로잉 루틴 자체가 적절하다고 결론을 내려야합니다. 또한 모든 보류중인 작업을 기다리는 루프가 포함되어 있지만 문제가 해결되지는 않습니다. 누군가 나에게 누락 된 것이 무엇인지를 지적 할 수 있습니까?새로 고침 빈 영역이 gtk입니다.

감사합니다,

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

는 나는 그것에 대해 생각합니다.

답변

3

당신은 더러운 등의 위젯 (또는 사각형)을 표시합니다 gtk_widget_queue_draw_area 또는 gdk_window_invalidate_rect .This를 사용할 수 있으며, 메인 루프가 유휴 상태 일 후에는 다시 그릴 수있는 곳에서 expose 이벤트를 수신 할 수 있습니다. 귀하의 설명에 따르면 업데이트가 expose 이벤트에서 발생하므로 이러한 API가 유용 할 수 있습니다. 또한 의 사용법을 볼 수있는 카이로 사이트에서 this sample을 확인할 수 있습니다.
내가 pygtk를 사용하지 않은 그러나 구글에서 나는 gtk_widget_queue_draw_area에 해당하는 전화가 gdk_window_invalidate_rect에 대한 gtk.Widget.queue_draw_area &이 도움이 gtk.gdk.Window.invalidate_rect
희망입니다 것으로 나타났습니다!

+0

답장을 보내 주셔서 감사합니다. 불행히도 문제가 해결되지 않는 것 같습니다. 사실, 나는 gtk.gdk.Window.invalidate_rect를 모두 가지고 있었고, 내가 버리면 캔버스가 전혀 업데이트되지 않는다는 것이 사실이다. 제가 상당히 이상한 점은 드로잉 루틴이 캔버스를 흰색으로 칠한 다음 선을 그립니다. 그리고 그림은 항상 끝났지 만 스크롤 된 창을 굴릴 때만 선이 표시된다는 것입니다. 따라서 위젯은 적어도 한 번 업데이트됩니다. – v923z

+0

@ v923z : 아! 정말 노출 이벤트가 누락 된 것처럼 보였습니다! 그래도 이상하게 들리니 ... 당신은 이벤트 콜백을 공개하는 캔버스를 업데이트하고 있습니다. 캔버스가 몇 줄의 드로잉이 누락 될 것으로 예상됩니다. 그렇습니까? 가능한 경우 코드 몇 줄을 게시 할 수 있습니다. 우리는 도울 수 있습니다 –

+0

의견을 보내 주셔서 감사합니다! 원래 게시물을 업데이트했습니다. – v923z