?? z186.html
字號:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html> <head> <title> Drawing Methods </title> <meta name="GENERATOR" content= "Modular DocBook HTML Stylesheet Version 1.45"> <link rel="HOME" title="GTK+ / Gnome Application Development" href="ggad.html"> <link rel="UP" title="Writing a GnomeCanvasItem" href= "cha-canvasitem.html"> <link rel="PREVIOUS" title="Writing a GnomeCanvasItem" href= "cha-canvasitem.html"> <link rel="NEXT" title="Other Methods" href="z192.html"> </head> <body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink= "#840084" alink="#0000FF"> <div class="NAVHEADER"> <table width="100%" border="0" bgcolor="#ffffff" cellpadding= "1" cellspacing="0"> <tr> <th colspan="4" align="center"> <font color="#000000" size="2">GTK+ / Gnome Application Development</font> </th> </tr> <tr> <td width="25%" bgcolor="#ffffff" align="left"> <a href="cha-canvasitem.html"><font color="#0000ff" size="2"><b><<< Previous</b></font></a> </td> <td width="25%" colspan="2" bgcolor="#ffffff" align= "center"> <font color="#0000ff" size="2"><b><a href="ggad.html"> <font color="#0000ff" size="2"><b> Home</b></font></a></b></font> </td> <td width="25%" bgcolor="#ffffff" align="right"> <a href="z192.html"><font color="#0000ff" size="2"><b> Next >>></b></font></a> </td> </tr> </table> </div> <div class="SECT1"> <h1 class="SECT1"> <a name="Z186">Drawing Methods</a> </h1> <p> The most important task of any canvas item is rendering itself onto the canvas. Rendering is a two-stage process for efficiency reasons. The first stage, implemented in a <span class="STRUCTNAME">GnomeCanvasItem</span>'s <span class="STRUCTNAME">update</span> method, is guaranteed to happen only once per item per rendering cycle; the idea is to do any expensive affine transformations or other calculations in the update method. In the second stage, the canvas item renders itself to some region on the screen. The <span class="STRUCTNAME">render</span> method implements stage two for antialiased items, while the <span class="STRUCTNAME">draw</span> method implements stage two for GDK items. An item's render or draw method may be invoked multiple times during a canvas repaint. </p> <p> Rendering occurs in a one-shot idle function. That is, whenever the canvas receives an expose event or otherwise determines that a redraw is needed, it adds an idle function which removes itself after a single invocation. (An idle function runs when no GTK+ events are pending and the flow of execution is in the GTK+ main loop---see <a href="sec-mainloop.html">the section called <i>The Main Loop</i> in the chapter called <i>GTK+ Basics</i></a> for details.) The canvas maintains a list of redraw regions and adds to it whenever a redraw request is received, so it knows which areas to repaint when the idle handler is finally invoked. </p> <p> Canvas items carry a flag indicating whether they need to be updated. Whenever a canvas item "changes" (for example, if you set a new fill color for <span class="STRUCTNAME"> GnomeCanvasRect</span>), it will call <tt class="FUNCTION"> gnome_canvas_item_request_update()</tt> to set the "update needed" flag for itself and the groups that contain it, up to and including the root canvas group. (The <tt class= "CLASSNAME">GnomeCanvas</tt> widget is only aware of a single canvas item, the root group---all other items are handled recursively when methods are invoked on the root group.) In its one-shot idle function, the canvas invokes the update method of the root canvas item if its update flag is set, then clears the flag so the update method will not be run next time. The <span class="STRUCTNAME"> GnomeCanvasGroup</span> update method does the same for each child item. </p> <p> Once all canvas items have been updated, the rendering process begins. The canvas creates an RGB or <span class= "STRUCTNAME">GdkPixmap</span> buffer, converts its list of redraw regions into a list of buffer-sized rectangles, then invokes the render or draw method of the root canvas group once per rectangle. After each rectangle is rendered, the buffer is copied to the screen. </p> <div class="SECT2"> <h2 class="SECT2"> <a name="Z187">The Update Method</a> </h2> <p> The update method is primarily used by antialiased canvas items. <tt class="APPLICATION">libart_lgpl</tt> can prebuild a vector path to be rendered, performing clipping and affine transformation in advance. The render method stamps the pre-assembled path into the RGB buffer. </p> <p> The update method is one of the two that <span class= "STRUCTNAME">GnomeCanvasRect</span> and <span class= "STRUCTNAME">GnomeCanvasEllipse</span> have to implement differently. Here is the <span class="STRUCTNAME"> GnomeCanvasRect</span> implementation: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static voidgnome_canvas_rect_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags){ GnomeCanvasRE *re; ArtVpath vpath[11]; ArtVpath *vpath2; double x0, y0, x1, y1; double dx, dy; double halfwidth; int i; gnome_canvas_re_update_shared (item, affine, clip_path, flags); re = GNOME_CANVAS_RE (item); if (item->canvas->aa) { x0 = re->x1; y0 = re->y1; x1 = re->x2; y1 = re->y2; gnome_canvas_item_reset_bounds (item); if (re->fill_set) { vpath[0].code = ART_MOVETO; vpath[0].x = x0; vpath[0].y = y0; vpath[1].code = ART_LINETO; vpath[1].x = x0; vpath[1].y = y1; vpath[2].code = ART_LINETO; vpath[2].x = x1; vpath[2].y = y1; vpath[3].code = ART_LINETO; vpath[3].x = x1; vpath[3].y = y0; vpath[4].code = ART_LINETO; vpath[4].x = x0; vpath[4].y = y0; vpath[5].code = ART_END; vpath[5].x = 0; vpath[5].y = 0; vpath2 = art_vpath_affine_transform (vpath, affine); gnome_canvas_item_update_svp_clip (item, &re->fill_svp, art_svp_from_vpath (vpath2), clip_path); art_free (vpath2); } else gnome_canvas_item_update_svp (item, &re->fill_svp, NULL); if (re->outline_set) { if (re->width_pixels) halfwidth = re->width * 0.5; else halfwidth = re->width * item->canvas->pixels_per_unit * 0.5; if (halfwidth < 0.25) halfwidth = 0.25; i = 0; vpath[i].code = ART_MOVETO; vpath[i].x = x0 - halfwidth; vpath[i].y = y0 - halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x0 - halfwidth; vpath[i].y = y1 + halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x1 + halfwidth; vpath[i].y = y1 + halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x1 + halfwidth; vpath[i].y = y0 - halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x0 - halfwidth; vpath[i].y = y0 - halfwidth; i++; if (x1 - halfwidth > x0 + halfwidth && y1 - halfwidth > y0 + halfwidth) { vpath[i].code = ART_MOVETO; vpath[i].x = x0 + halfwidth; vpath[i].y = y0 + halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x1 - halfwidth; vpath[i].y = y0 + halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x1 - halfwidth; vpath[i].y = y1 - halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x0 + halfwidth; vpath[i].y = y1 - halfwidth; i++; vpath[i].code = ART_LINETO; vpath[i].x = x0 + halfwidth; vpath[i].y = y0 + halfwidth; i++; } vpath[i].code = ART_END; vpath[i].x = 0; vpath[i].y = 0; vpath2 = art_vpath_affine_transform (vpath, affine); gnome_canvas_item_update_svp_clip (item, &re->outline_svp, art_svp_from_vpath (vpath2), clip_path); art_free (vpath2); } else gnome_canvas_item_update_svp (item, &re->outline_svp, NULL); } else { get_bounds (re, &x0, &y0, &x1, &y1); gnome_canvas_update_bbox (item, x0, y0, x1, y1); }} </pre> </td> </tr> </table> <p> As you can see, the first thing this function does is invoke an update function shared by <span class= "STRUCTNAME">GnomeCanvasRect</span> and <span class= "STRUCTNAME">GnomeCanvasEllipse</span>; here is that function: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static voidgnome_canvas_re_update_shared (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags){ GnomeCanvasRE *re; re = GNOME_CANVAS_RE (item); if (re_parent_class->update) (* re_parent_class->update) (item, affine, clip_path, flags); if (!item->canvas->aa) { set_gc_foreground (re->fill_gc, re->fill_pixel); set_gc_foreground (re->outline_gc, re->outline_pixel); set_stipple (re->fill_gc, &re->fill_stipple, re->fill_stipple, TRUE); set_stipple (re->outline_gc, &re->outline_stipple, re->outline_stipple, TRUE); set_outline_gc_width (re); } } </pre> </td> </tr> </table> <p> There is a lot of code involved here; the update method is almost always the most complicated one, since it does all the work of preparing to render a canvas item. Also, the update method is different for GDK and antialiased mode; notice the code which depends on the <span class= "STRUCTNAME">item->canvas->aa</span> flag. </p> <p> The first thing <span class="STRUCTNAME"> GnomeCanvasRE</span> does during an update is invoke the update method of its parent class. The <span class= "STRUCTNAME">GnomeCanvasItem</span> default update method does nothing whatsoever in Gnome 1.0, but it is good practice to chain up for future robustness. Then, <span class="STRUCTNAME">GnomeCanvasRE</span> calls a series of utility routines to fill in its graphics contexts with their correct values. These are straightforward functions, so their implementations are omitted here. </p> <p> Next <tt class="FUNCTION">gnome_canvas_rect_update()</tt> continues with <span class="STRUCTNAME"> GnomeCanvasRect</span>-specific details. Several tasks are accomplished: </p> <ul> <li> <p> The bounding box of the canvas item is updated. Every canvas item has an associated bounding box; the <span class="STRUCTNAME">GnomeCanvasGroup</span> draw and render methods use this box to determine which items are in the redraw region. The bounding box must be updated in both GDK and antialiased mode. </p> </li> <li> <p> In antialiased mode, a <i class="FIRSTTERM">sorted vector path</i> is created. A sorted vector path is simply a series of drawing instructions, similar to primitive PostScript operations, that <tt class= "APPLICATION">libart_lgpl</tt> can render to an RGB
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -