?? cha-gtk.html
字號:
</p> <p> Once you have a <span class="STRUCTNAME"> GtkWidget*</span> representing an object, you can manipulate the object using its methods. All GTK+ widget functions begin with the name of the type they operate on, and accept a pointer to that type as the first argument. In the above code, <tt class= "FUNCTION">gtk_container_add()</tt> accepts a <span class="STRUCTNAME">GtkContainer*</span> as the first argument. The macro <tt class="FUNCTION"> GTK_CONTAINER()</tt> casts the <span class= "STRUCTNAME">GtkWidget*</span>, and also performs a runtime type check. Casting is required because C does not understand the inheritance relationship. </p> <p> As you might imagine, <tt class="CLASSNAME"> GtkButton</tt> and <tt class="CLASSNAME"> GtkWindow</tt> are both subclasses of <tt class= "CLASSNAME">GtkContainer</tt>. A <tt class= "CLASSNAME">GtkContainer</tt> can hold any other widget inside. The code creates a toplevel window, places a button inside it, and places a label (line of text) inside the button. Then it sets the window title, and adds a small cosmetic border around the button. </p> </div> <div class="SECT3"> <h3 class="SECT3"> <a name="Z44">Signals</a> </h3> <p> Next, you'll want to arrange to respond when users manipulate the widgets. In this simple application, there are two interesting things that can happen: the user can click the button, or close the window using a window manager decoration. Widgets (actually, all <span class="STRUCTNAME">GtkObject</span>s) emit <i class="FIRSTTERM">signals</i> when something interesting happens a program might want to respond to. To respond to a signal, you "connect a callback" to it---i.e., register a function to be called when the signal is emitted. Here's that code again: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event_cb), NULL); gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(button_click_cb), label); </pre> </td> </tr> </table> <p> <tt class="FUNCTION">gtk_signal_connect()</tt> specifies the <span class="STRUCTNAME"> GtkObject</span> to monitor, which signal to connect to, the callback to connect, and finally a <span class="STRUCTNAME">user_data</span> argument---this is an arbitrary <span class="STRUCTNAME"> gpointer</span> which will be passed to the callback. The macro <tt class="FUNCTION">GTK_SIGNAL_FUNC()</tt> casts the callback to a standard function signature; since callbacks have a variety of type signatures, the alternative would be dozens of <tt class= "FUNCTION">gtk_signal_connect()</tt> variants. </p> <p> GTK+ performs copious runtime sanity checking; the <tt class="FUNCTION">GTK_OBJECT()</tt> macro includes a runtime type check in addition to a C cast, and <tt class="FUNCTION">gtk_signal_connect()</tt> will verify that the object can actually emit the signal you've specified. </p> </div> <div class="SECT3"> <h3 class="SECT3"> <a name="Z45">Entering the Main Loop</a> </h3> <p> Once everything is set up, two steps remain: you need to show the window on the screen, and wait for user input. </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> gtk_widget_show_all(window); gtk_main(); return 0; </pre> </td> </tr> </table> <p> <tt class="FUNCTION">gtk_widget_show_all()</tt> recursively calls <tt class="FUNCTION"> gtk_widget_show()</tt> on a container and its children. The following code would have the same effect in this case: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> gtk_widget_show(label); gtk_widget_show(button); gtk_widget_show(window); </pre> </td> </tr> </table> <p> It's necessary to show each and every widget that you want to appear on the screen. The opposite operation is called <tt class="FUNCTION"> gtk_widget_hide()</tt>; widgets start their life hidden, and can be re-hidden/re-shown any number of times. It's good practice to show all child widgets before showing the outermost container; otherwise, the user will see the container appear first, followed by its children. Widgets are not actually visible on the screen until their parent container is shown---the exception to the rule is <tt class= "CLASSNAME">GtkWindow</tt>, since it has no parent. </p> <p> Once your widgets have been shown, you want to wait for the user to do something with them. <tt class= "FUNCTION">gtk_main()</tt> enters the GTK+ main loop; the main loop is event-driven. That is, user actions trigger <i class="FIRSTTERM">events</i> which generally result in signals being emitted and your callbacks being called. <tt class="FUNCTION"> gtk_main()</tt> blocks indefinitely, waiting for and responding to user input. The main loop is described in more detail in <a href="sec-mainloop.html">the section called <i>The Main Loop</i></a>. Events and their relation to the main loop are described in <a href="sec-gdkevent.html">the section called <i> Events</i> in the chapter called <i>GDK Basics</i></a>. </p> </div> <div class="SECT3"> <h3 class="SECT3"> <a name="Z46">More on Signals and Callbacks</a> </h3> <p> If either of the signals the program connects to is emitted, the corresponding callback is called. Our <span class="SYMBOL">"delete_event"</span> callback ends the <tt class="FUNCTION">gtk_main()</tt> event loop by calling <tt class="FUNCTION"> gtk_main_quit()</tt>; this causes <tt class= "FUNCTION">gtk_main()</tt> to return, ending the program. The <span class="SYMBOL">"clicked"</span> callback replaces the text from the label with the same text in reverse. Notice that the label was passed to the callback as the <span class= "STRUCTNAME">user_data</span> parameter to <tt class= "FUNCTION">gtk_signal_connect()</tt>. </p> <p> A common mistake is to assume that all signals use the same kind of callback---not true. Each signal requires a callback with a particular type signature and particular behavior. The <span class="SYMBOL"> "clicked"</span> signal has a very common callback type; its callback receives a pointer to the widget emitting the signal and any <span class="STRUCTNAME"> user_data</span> provided by the programmer. This callback <i class="EMPHASIS">must</i> return <span class="STRUCTNAME">void</span> or memory corruption is likely to occur. </p> <p> <span class="SYMBOL">"delete_event"</span>, on the other hand, is something of a special case. It accepts three arguments; the first and last are analagous to <span class="SYMBOL">"clicked"</span>, while the second is a pointer to the event which triggered the signal (<i class="FIRSTTERM">events</i> are messages from X to the application, reporting mouse movements, key presses, and the like). The <span class="SYMBOL">"delete_event"</span> callback returns a "magic" value---if <span class= "STRUCTNAME">FALSE</span> is returned, GTK+ will destroy the window; if <span class="STRUCTNAME"> TRUE</span> is returned, GTK+ will do nothing. Return <span class="STRUCTNAME">TRUE</span> if you need to do something other than destroy the window; for example, you might want to warn the user about an unsaved document. </p> <p> Widget header files are the best quick reference for callback signatures. The "class structure" for the widget will have a space for a default signal handler; your handler should be modeled on the default one. For example, in <tt class="FILENAME"> gtk/gtkbutton.h</tt> the <tt class="CLASSNAME"> GtkButton</tt> class struct looks like this: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> struct _GtkButtonClass{ GtkBinClass parent_class; void (* pressed) (GtkButton *button); void (* released) (GtkButton *button); void (* clicked) (GtkButton *button); void (* enter) (GtkButton *button); void (* leave) (GtkButton *button);}; </pre> </td> </tr> </table> <p> <a href="cha-objects.html">the chapter called <i>The GTK+ Object and Type System</i></a> explains exactly what a class struct is for; for now, just pay attention to the function pointers, and note that they correspond to signals. To get from this: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> void (* clicked) (GtkButton *button); </pre> </td> </tr> </table> <p> to this: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static void button_click_cb(GtkWidget* w, gpointer data); </pre> </td> </tr> </table> <p> simply add a <span class="STRUCTNAME">gpointer data</span> to the class struct function's signature. In Hello, World I've also changed the type from <span class="STRUCTNAME">GtkButton*</span> to <span class= "STRUCTNAME">GtkWidget*</span>; this is common, since it can be more convenient to have a <span class= "STRUCTNAME">GtkWidget*</span>. The argument will always be the <tt class="CLASSNAME">GtkButton</tt> emitting the signal. </p> <p> Another example may be useful; here is <span class= "SYMBOL">"delete_event"</span> from <tt class= "FILENAME">gtk/gtkwidget.h</tt>: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> gint (* delete_event) (GtkWidget *widget, GdkEventAny *event); </pre> </td> </tr> </table> <p> and the callback from Hello, World: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static gint delete_event_cb(GtkWidget* w, GdkEventAny* e, gpointer data); </pre> </td> </tr> </table> <p> That's all there is to it. You can write simple GTK+ applications using only the information presented in this section. GTK+ and Gnome are powerful application development tools because you can think about real functionality, instead of struggling to get a window on the screen. </p> </div> </div> </div> </div> <div class="NAVFOOTER"> <br> <br> <table width="100%" border="0" bgcolor="#ffffff" cellpadding= "1" cellspacing="0"> <tr> <td width="25%" bgcolor="#ffffff" align="left"> <a href="z35.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="sec-containers.html"><font color="#0000ff" size="2"><b>Next >>></b></font></a> </td> </tr> <tr> <td colspan="2" align="left"> <font color="#000000" size="2"><b>Other Features</b></font> </td> <td colspan="2" align="right"> <font color="#000000" size="2"><b>Containers And Widget Layout</b></font> </td> </tr> </table> </div> </body></html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -