?? z147.html
字號:
Once a widget's parent container decides how much space is actually available, the widget receives a size allocation. The size allocation method should do the following: </p> <ul> <li> <p> Assign the new allocation to <span class= "STRUCTNAME">widget->allocation</span>; this does <i class="EMPHASIS">not</i> happen automatically, as it does for <span class="STRUCTNAME"> widget->requisition</span>. </p> </li> <li> <p> Divide the allocation among any child widgets. </p> </li> <li> <p> Resize any <span class="STRUCTNAME"> GdkWindow</span>s, if the widget is realized. </p> </li> <li> <p> Perform any widget-specific tasks; for example, <tt class="CLASSNAME">GtkEv</tt> updates the two <span class="STRUCTNAME">GdkRectangle</span>s representing its internal layout. </p> </li> </ul> <p> Here is the <tt class="CLASSNAME">GtkEv</tt> size allocation method; it should be self-explanatory: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static void gtk_ev_size_allocate (GtkWidget *widget, GtkAllocation *allocation){ static const gint spacing = 10; GtkEv* ev; g_return_if_fail(widget != NULL); g_return_if_fail(GTK_IS_EV(widget)); ev = GTK_EV(widget); widget->allocation = *allocation; ev->event_window_rect.width = MAX(allocation->width - spacing*2, 0); ev->event_window_rect.height = MAX(allocation->height / 5 - spacing / 2, 0); ev->event_window_rect.x = (allocation->width - ev->event_window_rect.width)/2; ev->event_window_rect.y = MIN(spacing, allocation->height); ev->description_rect.x = ev->event_window_rect.x; ev->description_rect.y = ev->event_window_rect.y + ev->event_window_rect.height + spacing; ev->description_rect.width = ev->event_window_rect.width; ev->description_rect.height = MAX((allocation->height - ev->event_window_rect.height - spacing*3), 0); if (GTK_WIDGET_REALIZED (widget)) { gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); gdk_window_move_resize (ev->event_window, ev->event_window_rect.x, ev->event_window_rect.y, ev->event_window_rect.width, ev->event_window_rect.height); }} </pre> </td> </tr> </table> </div> <div class="SECT2"> <h2 class="SECT2"> <a name="SEC-GTKEVDRAWING">Drawing</a> </h2> <p> There are three common situations that require a widget to redraw all or part of itself: </p> <ol type="1"> <li> <p> Expose events signal that all or part of a widget's <span class="STRUCTNAME">GdkWindow</span> has just become visible on the screen and needs repainting (see <a href="sec-gdkevent.html#SEC-EXPOSEEVENTS">the section called <i>Expose Events</i> in the chapter called <i>GDK Basics</i></a>). A widget's <span class="STRUCTNAME">expose_event</span> method performs these redraws. </p> </li> <li> <p> GTK+ sometimes determines that a widget should be redrawn. This might happen when a widget receives a new size allocation different from its previous size allocation, or when a new theme is loaded. A widget's <span class="STRUCTNAME">draw</span> method, usually invoked via <tt class="FUNCTION"> gtk_widget_queue_draw()</tt> or <tt class="FUNCTION"> gtk_widget_queue_clear()</tt>, handles this case. </p> </li> <li> <p> Widgets sometimes decide to redraw themselves. For example, if you change the text of a <tt class= "CLASSNAME">GtkLabel</tt>, the label will redraw itself to reflect the new text. Widget implementations are free to handle this case however they like, but most will use the <span class= "STRUCTNAME">draw</span> method. </p> </li> </ol> <p> There are two special cases of the second situation. The first occurs when a widget receives or loses the keyboard focus; the second occurs when the widget becomes (or unbecomes) the "default" widget. Widgets should indicate these states visually, but they can often do so without a complete redraw. Thus, there are special <span class= "STRUCTNAME">draw_focus</span> and <span class= "STRUCTNAME">draw_default</span> signals to handle them. These signals only have to be implemented if a widget can meaningfully receive the focus or default. </p> <p> Because there is typically little difference between a widget's draw and expose methods, a common convention is to write a static function to handle both of them. This function is standardly called <tt class="FUNCTION"> gtk_whatever_paint()</tt>. It's also possible to avoid implementing the draw method, because the default draw method synthesizes an expose event covering the widget's entire allocation and invokes the expose method. (Remember that a synthetic expose event will have its <span class="STRUCTNAME">send_event</span> flag set to <span class="STRUCTNAME">TRUE</span>; you can use this to distinguish synthetic events.) </p> <p> The primary reason for distinguishing expose events from other draws is that expose events are marked with the window they occurred on; for widgets with multiple windows such as <tt class="CLASSNAME">GtkEv</tt>, this can increase efficiency. <tt class="CLASSNAME">GtkEv</tt> implements two private functions, <tt class="CLASSNAME"> gtk_ev_paint()</tt> and <tt class="CLASSNAME"> gtk_ev_paint_event_window()</tt>, which it uses to implement the expose and draw methods. </p> <p> Here is the draw method: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static void gtk_ev_draw (GtkWidget *widget, GdkRectangle *area){ GdkRectangle event_window_area; GdkRectangle intersection; GtkEv* ev; g_return_if_fail(widget != NULL); g_return_if_fail(GTK_IS_EV(widget)); ev = GTK_EV(widget); gtk_ev_paint(ev, area); event_window_area = *area; if (gdk_rectangle_intersect(area, &ev->event_window_rect, &intersection)) { /* Make the intersection relative to the event window */ intersection.x -= ev->event_window_rect.x; intersection.y -= ev->event_window_rect.y; gtk_ev_paint_event_window(ev, &intersection); }} </pre> </td> </tr> </table> <p> And the expose method: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static gint gtk_ev_expose (GtkWidget *widget, GdkEventExpose *event){ if (event->window == widget->window) gtk_ev_paint(GTK_EV(widget), &event->area); else if (event->window == GTK_EV(widget)->event_window) gtk_ev_paint_event_window(GTK_EV(widget), &event->area); else g_assert_not_reached(); return TRUE;} </pre> </td> </tr> </table> <p> Both the draw and expose methods should be self-explanatory. All the work is done in the two paint functions. Here is <tt class="FUNCTION"> gtk_ev_paint()</tt>, which renders the main widget window: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static void gtk_ev_paint (GtkEv *ev, GdkRectangle *area){ GtkWidget* widget; g_return_if_fail(ev != NULL); g_return_if_fail(GTK_IS_EV(ev)); widget = GTK_WIDGET(ev); if (!GTK_WIDGET_DRAWABLE (widget)) return; gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); gdk_gc_set_clip_rectangle(widget->style->black_gc, area); /* Draw a black rectangle around the event window */ gdk_draw_rectangle(widget->window, widget->style->black_gc, FALSE, ev->event_window_rect.x - 1, ev->event_window_rect.y - 1, ev->event_window_rect.width + 2, ev->event_window_rect.height + 2); gdk_gc_set_clip_rectangle(widget->style->black_gc, NULL); /* Draw text in the description area, if applicable */ if (ev->buffer) { GdkRectangle intersection; if (gdk_rectangle_intersect(area, &ev->description_rect, &intersection)) { static const gint space = 2; gint line; gint step; gint first_baseline; GList* tmp; step = widget->style->font->ascent + widget->style->font->descent + space; first_baseline = ev->description_rect.y + widget->style->font->ascent + space; line = 0; tmp = ev->buffer; while (tmp != NULL) { gchar** this_event = tmp->data; gint i = 0; while (this_event[i]) { gtk_paint_string (widget->style, widget->window, widget->state, &intersection, widget, "ev", ev->description_rect.x, first_baseline + line*step, this_event[i]); ++i; ++line; } /* Bail out if we're off the bottom; the "- 2*step" is * needed because the next baseline may be outside the * redraw area but we are interested in the whole row of * text, not the baseline. The 2* is because line is one * larger than we've actually drawn. */ if ((first_baseline + line*step - 2*step) > (intersection.y + intersection.height)) break; tmp = g_list_next(tmp); } } }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -