📄 gnome-canvas-items.html
字号:
GnomeCanvasLine item can optionally have one arrowhead at the starting point and another at the ending point of the line. The Boolean first_arrowhead and last_arrowhead properties determine whether or not the line item should display an arrowhead at that position in the line. By default, the arrowheads are turned off. If a line item has more than one line segment (e.g., a line with four points and three line segments), the arrowheads will show up only at the first and last points. To support an arrowhead at every vertex, the Canvas item would in theory have to declare a variable-length array of Boolean nth_arrowhead properties, one for each point in the line. For reasons of simplicity, GnomeCanvasLine does not go this extra mile. If you want arrowheads at each point, you have to use a different GnomeCanvasLine item for each line segment. </P><P> The three remaining arrow_shape_* properties define the shape and size of all arrowheads on that line item. Each property determines a measurable distance, in world coordinates, that GnomeCanvasLine will trace when drawing the arrowheads. Starting from a point at the end of the line, arrow_shape_a runs straight out, parallel to the line, measuring how far forward the arrow will stretch. The arrow_shape_b property measures how far backward from the arrow's tip the arrowhead will extend. The final property, arrow_shape_c, measures how far perpendicularly from the line the arrow extends-that is, the arrowhead's width. Figure 11.5 illustrates what the shape properties look like in practice. </P><DIVCLASS="FIGURE"><ANAME="AEN1194"></A><P><B>Figure 11-5. Arrow Shapes for GnomeCanvasLine Item</B></P><DIVCLASS="MEDIAOBJECT"><P><IMGSRC="figures/11f5.png"></IMG></P></DIV></DIV></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1199">The Shape of the Item</A></H2><P> Of the four vector-based Canvas items-rectangle, ellipse, polygon, and line- we have covered all the available properties except for the most important ones: the coordinates that determine their locations on the Canvas. Table 11.4 lists these properties. </P><P> The rectangle and ellipse items both use the opposite corners of a bounding box to determine their size and location on the Canvas. The rectangle inscribes itself directly on the bounding box, so that the bounding box be- comes the rectangle. The ellipse item renders itself inside of a similar bounding box. If you created a rectangle item and an ellipse item with the same bounding box, the rectangle would completely enclose the ellipse; the ellipse would meet up with the rectangle at the midpoint of each of the rectangle's four sides (see Figure 11.6). </P><DIVCLASS="FIGURE"><ANAME="AEN1203"></A><P><B>Figure 11-6. Rectangle and Ellipse Canvas Items with the Same Bounding Box</B></P><DIVCLASS="MEDIAOBJECT"><P><IMGSRC="figures/11f6.png"></IMG></P></DIV></DIV><P> In fact, the rectangle and ellipse items are derived from the same abstract Canvas item, GnomeCanvasRE, which defines all the properties used by both derived items, along with quite a lot of shared code for handling the bounding box, the fill colors, the stippling, and all the other properties. Rectangles and ellipses both use the x1, y1, x2, and y2 properties to define their bounding boxes. These properties are all world coordinates, which means they must be passed in as gdouble types. As we learned earlier, one of the most common reasons for crash-causing bugs in Canvas applications is accidentally passing an integer here instead of a gdouble, so be careful! </P><P> The line and polygon Canvas items use similar properties to define their locations, although their free-form, variable-point nature dictates that they use a technique different from that of the rectangle and the ellipse. A line or polygon can have as few as two points (in the case of the line) or three (in the case of the polygon), and as many points as you care to render. If these items were to support the same style of properties as the rectangle, they would have to define a potentially infinite number of item properties, along the lines of x1, y1, x2, y2, x3, y3, . . ., xn, yn. These two Canvas items solve the problem by wrapping their variable-length coordinate arrays inside a GnomeCanvasPoints structure and passing a pointer to that structure as the points item property. The GnomeCanvasPoints structure looks like this: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">typedef struct{ int num_points; double *coords; int ref_count;} GnomeCanvasPoints; </PRE></TD></TR></TABLE><P> You can create the array and populate the structure with this function: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GnomeCanvasPoints *gnome_canvas_points_new (int num_points); </PRE></TD></TR></TABLE><P> The num_points field holds the number of points in the array rather than the total length of the array. Thus a pentagon would have a num_points value of 5 and an array of 10 doubles, dynamically allocated and stored in the coords field. The x coordinates are always in the even array elements, the y coordinates in the odd elements. After you create the GnomeCanvasPoints structure, you can fill the array by accessing the coords array directly. You must be very careful not to overrun this array, and it's up to you to make sure you don't. The simplest way to fill the array is to set each element explicitly: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GnomeCanvasPoints *points;points = gnome_canvas_points_new(3);points->coords[0] = 0.0; /* x1 */points->coords[1] = 100.0; /* y1 */points->coords[2] = 50.0; /* x2 */points->coords[3] = 0.0; /* y2 */points->coords[4] = 100.0; /* x3 */points->coords[5] = 100.0; /* y3 */ </PRE></TD></TR></TABLE><P> This method is not very scalable, however, and it can become rather messy for a complex polygon with lots of points. An alternative is to create your points in a static array, in which you can declare the series of points in a compact manner, and then use memcpy( ) to copy them to the existing coords array. This approach leads to leaner code but carries with it the dangers of pointer operations, which can increase the likelihood of crash-inducing bugs in your application. Keep your calls to memcpy( ) to a minimum, and pay particular attention to the difference between the number of points in the array (i.e., num_points), and the actual length of the array (i.e., num_points 2). Here's what the previous example would look like with the second approach: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GnomeCanvasPoints *points;gdouble pts_array[] = { 0.0, 100.0, 50.0, 0.0, 100.0, 100.0 };points = gnome_canvas_points_new(3);memcpy(points->coords, pts_array, sizeof(pts_array)); </PRE></TD></TR></TABLE><P> When you're done with your GnomeCanvasPoints structure, you call the unref function to release it. GnomeCanvasPoints keeps a reference count so that you can safely share a points array with other items if necessary. Call the _ref function instead of the _new function for each extra item that wants to use the same array, after the first one. Later, as each item finishes with the array, the item unreferences it, thereby decrementing the ref_count field. When ref_count reaches zero, the GnomeCanvasPoints array automatically cleans itself up. The _ref and _unref functions look like this: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GnomeCanvasPoints *gnome_canvas_points_ref( GnomeCanvasPoints *points);void gnome_canvas_points_unref(GnomeCanvasPoints *points); </PRE></TD></TR></TABLE><P> An alternative line-based Canvas item that is not included in the 1.2 version of gnome-libs is the GnomeCanvasBpath item, from the gnome-print package. This item is very similar to GnomeCanvasLine, except it uses an ArtBpath structure to describe its shape rather than a GnomeCanvasPoints structure, and it includes an extra property to describe its winding rules. It may or may not someday be included in the gnome-libs package. </P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1220">Widgets in the Canvas</A></H2><P> Although the Canvas is most commonly used as a buffered drawing surface, its object-oriented nature makes it easy to extend into new areas. One such area is the ability to embed a widget into the Canvas as a full-fledged Canvas item. Since the GnomeCanvasWidget item is just a wrapper for a widget, it doesn't need many properties (see Table 11.5). </P><P> The widget property holds a pointer to the widget itself. The x, y, width, and height properties determine the widget's placement inside the Canvas, in world coordinates. If you need to resize a GnomeCanvasWidget item, you should do it with these properties rather than trying to call gtk_widget_set_usize( ) on it. If you try to bypass the Canvas properties, the Canvas will just return the widget to whatever size it thinks the widget should be during the next repaint. </P><P> The x and y coordinates don't necessarily point to the upper left corner of the widget. By default, if you don't set the anchor property, that's where the anchor will end up. Sometimes, however, it's nice to be able to align widgets with a different corner, at the widget's center, or even at the midpoint of a side. The anchor property gives you this power, borrowing the GtkAnchorType enumeration from GTK+. Listing 11.5 lists the alignment possibilities. The anchor types are based on the compass points, and should be self-explanatory. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 11.5 GtkAnchorType Enumerationtypedef enum{ GTK_ANCHOR_CENTER, GTK_ANCHOR_NORTH, GTK_ANCHOR_NORTH_WEST, GTK_ANCHOR_NORTH_EAST, GTK_ANCHOR_SOUTH, GTK_ANCHOR_SOUTH_WEST, GTK_ANCHOR_SOUTH_EAST, GTK_ANCHOR_WEST, GTK_ANCHOR_EAST, GTK_ANCHOR_N = GTK_ANCHOR_NORTH, GTK_ANCHOR_NW = GTK_ANCHOR_NORTH_WEST, GTK_ANCHOR_NE = GTK_ANCHOR_NORTH_EAST, GTK_ANCHOR_S = GTK_ANCHOR_SOUTH, GTK_ANCHOR_SW = GTK_ANCHOR_SOUTH_WEST, GTK_ANCHOR_SE = GTK_ANCHOR_SOUTH_EAST, GTK_ANCHOR_W = GTK_ANCHOR_WEST, GTK_ANCHOR_E = GTK_ANCHOR_EAST} GtkAnchorType; </PRE></TD></TR></TABLE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1226">Text Canvas Items</A></H2><P> So far, we've discussed Canvas items for drawing lines and polygons and for embedding widgets. Another important feature you'll need sooner or later is the ability to render text into the Canvas. The GnomeCanvasText item provides this functionality. </P><P> The text item shares several of its properties with the other items. Its x, y, and anchor properties work in the same way as those for the GnomeCanvasWidget item; they specify where the text is attached to the Canvas. GnomeCanvasText also shares the fill_color, fill_color_gdk, and fill_stipple properties with the vector-based items (see Table 11.1), to define the color and stipple pattern of the text. Table 11.6 shows all the properties of the text item. </P><P> You can set the text itself with the text property, and the font of that text with one of the three font properties: font, fontset, and font_gdk. Like the fill color properties of the vector-based canvas items, the font properties all affect the same value within the item. This value resolves more or less to a GdkFont* pointer, regardless of which font property you use. Changing the font may also trigger some formatting and size recalculations because the text may lie differently in the new font, especially if the text is centered. You can change the text justification with the justification property, which takes a value of GtkJustification (see Listing 11.6). </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 11.6 GtkJustification Enumerationtypedef enum{ GTK_JUSTIFY_LEFT, GTK_JUSTIFY_RIGHT,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -