?? z147.html
字號:
<p> If you aren't familiar with the concept of <i class= "FIRSTTERM">realizing</i> and <i class="FIRSTTERM"> mapping</i> a widget, go back and read <a href= "z57.html#SEC-REALIZINGSHOWING">the section called <i> Realizing, Mapping, and Showing</i> in the chapter called <i>GTK+ Basics</i></a> before reading this section. </p> <p> <tt class="CLASSNAME">GtkEv</tt> does not override the map or unmap method; the default <tt class="CLASSNAME"> GtkWidget</tt> methods suffice. The defaults set and unset the <span class="STRUCTNAME"> GTK_WIDGET_MAPPED</span> flag, and show or hide <span class="STRUCTNAME">widget->window</span>. </p> <p> Any widget with a <span class="STRUCTNAME"> GdkWindow</span> that has <tt class="CLASSNAME"> GtkWidget</tt> as its immediate parent will need to override the realize method; the default is only suitable for windowless widgets. <tt class="CLASSNAME">GtkEv</tt> is no exception. <tt class="CLASSNAME">GtkEv</tt> also overrides the unrealize method, in order to destroy the event window. </p> <p> Here is <tt class="CLASSNAME">GtkEv</tt>'s realize method: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static void gtk_ev_realize (GtkWidget *widget){ GdkWindowAttr attributes; gint attributes_mask; GtkEv* ev; GdkCursor* cursor; g_return_if_fail(widget != NULL); g_return_if_fail(GTK_IS_EV(widget)); ev = GTK_EV(widget); /* Set realized flag */ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); /* Main widget window */ attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, widget); /* Event window */ cursor = gdk_cursor_new(GDK_CROSSHAIR); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = ev->event_window_rect.x; attributes.y = ev->event_window_rect.y; attributes.width = ev->event_window_rect.width; attributes.height = ev->event_window_rect.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = GDK_ALL_EVENTS_MASK; attributes.cursor = cursor; attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR; ev->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); gdk_window_set_user_data (ev->event_window, widget); gdk_window_show(ev->event_window); gdk_cursor_destroy(cursor); /* Style */ widget->style = gtk_style_attach (widget->style, widget->window); gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); gdk_window_set_background (ev->event_window, &widget->style->base[GTK_STATE_NORMAL]);} </pre> </td> </tr> </table> <p> The first step in any realize method is to set the <span class="STRUCTNAME">GTK_REALIZED</span> flag; this is a small but important detail. After that, most of the realize method is concerned with creating the two <span class="STRUCTNAME">GdkWindow</span>s, as described in <a href="sec-gdkwindow.html">the section called <i><span class="STRUCTNAME">GdkWindow</span></i> in the chapter called <i>GDK Basics</i></a>. <span class="STRUCTNAME"> widget->window</span> should be created as a subwindow of the widget's parent's <span class="STRUCTNAME"> GdkWindow</span>; the parent window is obtained with <tt class="FUNCTION">gtk_widget_get_parent_window()</tt>. </p> <p> Notice that <i class="EMPHASIS">all</i> events are requested on the event window, for obvious reasons. Also, the event window has a special cursor, to give the user visual feedback when the pointer moves into it. The client-side cursor handle is destroyed immediately after attaching the cursor to the window; the X server will keep it around as long as it's in use. </p> <p> After creating each <span class="STRUCTNAME"> GdkWindow</span>, a pointer to the <tt class="CLASSNAME"> GtkEv</tt> is stored in the <span class="STRUCTNAME"> GdkWindow</span>'s "user data" field. GTK+ uses the contents of this field to determine which widget should receive events that occur on the window. Recall that GTK+ receives a stream of events from GDK, and that each <span class="STRUCTNAME">GdkEvent</span> has a <span class= "STRUCTNAME">window</span> field indicating the <span class="STRUCTNAME">GdkWindow</span> that received it. GTK+ forwards each event to the widget owning the event's <span class="STRUCTNAME">GdkWindow</span>. (<a href= "sec-gdkevent.html">the section called <i>Events</i> in the chapter called <i>GDK Basics</i></a> details this process if you don't remember.) </p> <p> The code calls <tt class="FUNCTION"> gdk_window_show()</tt> on the event window but not <span class="STRUCTNAME">widget->window</span>; <span class= "STRUCTNAME">widget->window</span> should not be shown until the widget is mapped. Because the event window is a child of <span class="STRUCTNAME"> widget->window</span>, it will remain offscreen until its parent is shown. Alternatively, <tt class= "CLASSNAME">GtkEv</tt> could implement a map method to show the child, but this way seems simpler. </p> <p> All widgets must take create their associated <span class="STRUCTNAME">GtkStyle</span> in their realize method, because a style contains X resources. (See <a href="sec-style.html">the section called <i><span class= "STRUCTNAME">GtkStyle</span> and Themes</i> in the chapter called <i>GDK Basics</i></a> for more information about <span class="STRUCTNAME">GtkStyle</span>.) Recall from <a href="z57.html#SEC-REALIZINGSHOWING">the section called <i>Realizing, Mapping, and Showing</i> in the chapter called <i>GTK+ Basics</i></a> that widgets allocate all X resources in their realize method. GTK+ provides a simple function to create a widget's style: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> widget->style = gtk_style_attach (widget->style, widget->window); </pre> </td> </tr> </table> <p> <i class="EMPHASIS">After</i> filling in <span class= "STRUCTNAME">widget->style</span>, <tt class= "CLASSNAME">GtkEv</tt> uses colors from the style to set window backgrounds. It sets the main window's background using <tt class="FUNCTION"> gtk_style_set_background()</tt>, which could do almost anything (it might invoke a routine from a dynamically loaded theme module). If the default theme is running, it simply sets the window's background to an appropriate color or pixmap tile. There is no special style function to set the background of the event window, so we set it to the "base" color (the base color is white by default; it's the background color for lists and text entries). Selecting a color from the style means that users will be able to customize the widget's color. It's also convenient to avoid allocating and deallocating a custom color. </p> <p> Notice that the realize method does not chain up to the default realize method, because the default isn't appropriate for <tt class="CLASSNAME">GtkEv</tt>. </p> <p> Unrealizing <tt class="CLASSNAME">GtkEv</tt> is relatively simple: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static void gtk_ev_unrealize (GtkWidget *widget){ GtkEv* ev; g_return_if_fail(widget != NULL); g_return_if_fail(GTK_IS_EV(widget)); ev = GTK_EV(widget); /* Hide all windows */ if (GTK_WIDGET_MAPPED (widget)) gtk_widget_unmap (widget); GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); /* Destroy our child window */ if (ev->event_window) { gdk_window_set_user_data(ev->event_window, NULL); gdk_window_destroy(ev->event_window); ev->event_window = NULL; } /* This destroys widget->window and unsets the realized flag */ if (GTK_WIDGET_CLASS(parent_class)->unrealize) (* GTK_WIDGET_CLASS(parent_class)->unrealize) (widget);} </pre> </td> </tr> </table> <p> First, the unrealize method ensures that the widget is unmapped. This is essential: GTK+ maintains the invariant that mapped widgets are also realized. Next, the unrealize method destroys the event window. It sets the window's user data to <span class="STRUCTNAME"> NULL</span> before destroying it; otherwise <tt class= "CLASSNAME">GtkEv</tt> would receive a useless destroy event. Finally, <tt class="CLASSNAME">GtkEv</tt> chains up to the default unrealize method, which unsets the <span class="STRUCTNAME">GTK_WIDGET_REALIZED</span> flag and destroys <span class="STRUCTNAME"> widget->window</span>. Unrealize implemenations are <i class="EMPHASIS">required</i> to chain up to their base class's implementation. </p> <p> When writing your realize and unrealize methods, keep in mind that they can be called multiple times, but they are always paired. That is, a widget can be unrealized and re-realized over and over, but it will never be realized twice without an intervening unrealize. The pairing is guaranteed; that is, if a widget is realized it will definitely be unrealized sooner or later, unless the program exits. </p> </div> <div class="SECT2"> <h2 class="SECT2"> <a name="SEC-GTKEVSIZENEG">Size Negotiation</a> </h2> <p> <a href="sec-containers.html#SEC-SIZENEGOTIATION">the section called <i>Size Allocation</i> in the chapter called <i>GTK+ Basics</i></a> describes the size negotiation process; be sure you're familiar with it before reading this section. </p> <p> There's no obvious "right" size for <span class= "STRUCTNAME">GtkEv</span>, so the size request method requests an arbitrary size that looks nice: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static void gtk_ev_size_request (GtkWidget *widget, GtkRequisition *requisition){ g_return_if_fail(widget != NULL); g_return_if_fail(GTK_IS_EV(widget)); /* * GtkEv always wants to be the same fixed size. */ requisition->width = 450; requisition->height = 300;} </pre> </td> </tr> </table> <p> GTK+ takes care of storing a widget's last size request in <span class="STRUCTNAME"> widget->requisition</span>. </p> <p> If <tt class="CLASSNAME">GtkEv</tt> were a real-life widget rather than an illustrative example, it would be unnecessary to implement a size request method. The default <tt class="CLASSNAME">GtkWidget</tt> method simply returns the current value of <span class= "STRUCTNAME">widget->requisition</span>, so <tt class= "CLASSNAME">GtkEv</tt> could initialize <span class= "STRUCTNAME">widget->requisition</span> in <tt class= "FUNCTION">gtk_ev_init()</tt> and use the default method. </p> <p> Alternatively, the size request method could be implemented more elaborately; <tt class="CLASSNAME"> GtkEv</tt> could attempt to predict the maximum width of the text to be displayed, for example. </p> <p>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -