Re: [gtk-list] boring GtkTutorial stuff..
- From: Pavel Greenfield <pavel riskdevel ml com>
- To: gtk-list redhat com
- Subject: Re: [gtk-list] boring GtkTutorial stuff..
- Date: Mon, 4 Aug 1997 09:34:07 -0400 (EDT)
On Sat, 2 Aug 1997, Ian Main wrote:
>
> Hi again,
>
> Yes, I stayed up half the night writing more on the tutorial, and yes, my
> wife hates me :) (just kidding.. she's actually very nice about it :)
I didn't know that married folks worked on GIMP/GTK...
>
> I've included the SGML source here again.. hopefuly no one has problems
> doing ye old sgml2html or what have you on it.
>
> How does one go about getting more people to help out ?
>
The more tutorials the better... What I would personally like is a
POSTSCRIPT version of all tutorials since I like printing stuff out,
stapling it, and reading it in a relaxed manner over a cup of tea (and
making notes to myself on the margins). HTML is acceptable, too, provided
it's a one-pager. I don't know how difficult it is to convert everything
to .ps but what does everyone else think?
(Perhaps sgml can be printed on the fly, too... How?)
Pavel
PS: I erased by mistake the post with that new gtk-tutorial page. What was
that page, again?
> Maybe we should have a competition to see who can write the
most > documentation over the course of the weekend ? Whatya think ?
>
> If you can write more than me, I'll umm.. umm... umm.. well.. you name it
>:)
>
> As usual, any comments are appreciated. Even better would be additions!
>:) hint hint, nudge, nudge...
>
>
> Ian
>
>
> ------------------------------------------------------------------------
>
>
>
> <!-- This is the tutorial marked up in SGML
> (just to show how to write a comment)
> -->
>
>
> <!doctype linuxdoc system>
> <article>
> <title>GTK Tutorial
> <author>Ian Main, <tt><htmlurl url="mailto:slow@intergate.bc.ca"
> name="slow@intergate.bc.ca"></tt>
> <date>July 1997
>
>
> <sect>Introduction
> <p>
> GTK (GIMP Toolkit) was originally developed as a toolkit for the GIMP
> (General Image Manipulation Program). GTK is built on top of GDK (GIMP
> Drawing Kit) which is basically wrapper around the Xlib functions. It's
> called the GIMP toolkit because it was original written for developing
> the GIMP, but has now been used in several free software projects. The
> authors are
> <itemize>
> <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
> name="petm@xcf.berkeley.edu"></tt>
> <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
> name="spencer@xcf.berkeley.edu"></tt>
> <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
> name="jmacd@xcf.berkeley.edu"></tt>
> </itemize>
>
> <p>
> GTK is essentially an object oriented API. Although written completely in
> C, it is implemented using the idea of classes, and callback functions
> (pointers to functions).
> <p>
> There is also a third component called glib which contains a few
> replacements for printf, malloc etc. These are used to increase gtk's
> portability, as some of the functions implemented here are not available or
> nonstandard on other Unicies such as g_strerror(). Some also contain
> enhancements to the libc versions such as
> g_malloc will test for errors for you.
> <p>
> This tutorial is an attempt to document as much as possible of gtk, t is by
> no means complete. This
> tutorial assumes a good understanding of C, and how to create C programs.
> It would be a great benifit for the reader to have previous X programming
> experience, but it shouldn't be necessary. If you are learning gtk as your
> first widget set, please comment on how you found this tutorial, and what
> you had troubles with.
> Note that there is also a C++ API for gtk (gtk--) in the works, so if you
> prefer to use C++, you should look into this instead.
> <p>
> I would very much like to hear any problems you have learning gtk from this
> document, and would appreciate input as to how it may be improved.
>
> <sect>Getting Started
> <p>
> The first thing to do of course, is download the gtk source and install
> it. You can either get the distro with GIMP, or d/l it from Peter
> Mattis's home dir ftp.xcf.berkely.edu/pub/pmattis (Hope this is ok :) ..
> may change ?).
> <p>
> We'll start with the simplest GTK program possible. This program will
> create a 200x200 pixel window and has no way of exiting except to be
> killed using the shell or window manager.
>
> <tscreen><verb>
> #include <gtk/gtk.h>
>
> int main (int argc, char *argv[])
> {
> GtkWidget *window;
>
> gtk_init (&argc, &argv);
>
> window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
> gtk_widget_show (window);
>
> gtk_main ();
>
> return 0;
> }
> </verb></tscreen>
>
> All programs will of course include the gtk/gtk.h which declares the
> variables and functions used in your gtk application.
> <p>
> The next line
>
> <tscreen><verb>
> gtk_init (&argc, &argv);
> </verb></tscreen>
>
> calls the function gtk_init(gint *argc, gchar ***argv) which will be
> called in all gtk applications. This sets up a few things for us such
> as the default visual and colormap and then proceeds to call
> gdk_init(gint *argc, gchar ***argv). This function initializes the
> library for use, sets up default signal handlers, and checks the
> arguements passed to your application on the command line, looking for one
> of the following:
> <itemize>
> <item> <tt/--display/
> <item> <tt/--debug-level/
> <item> <tt/--no-xshm/
> <item> <tt/--sync/
> <item> <tt/--show-events/
> <item> <tt/--no-show-events/
> </itemize>
> It removes these from the arguement list, leaving anything it does
> not recognize for your application to parse or ignore. This creates a set
> of standard arguments excepted by all gtk applications.
> <p>
> The next two lines of code create and display a window.
>
> <tscreen><verb>
> window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
> gtk_widget_show (window);
> </verb></tscreen>
>
> The GTK_WINDOW_TOPLEVEL argument specifies that we want the window to
> undergo window manager decoration and placement. Rather than create a
> window of 0x0 size, a window without children is set to 200x200 by default
> so you can still manipulate it.
> <p>
> The last line enters the GTK main processing loop.
>
> <tscreen><verb>
> gtk_main ();
> </verb></tscreen>
>
> gtk_main() is another call you will see in every gtk application. When
> control reaches this point, gtk will sleep waiting for X events (such as
> button or keypresses) to occur.
> In our simple example however, no events will be registered.
>
>
> <sect1>Hello World in GTK
> <p>
> OK, now for a program with a widget (a button). It's the classic hello
> world ala gtk. This would make a good base for a new gtk application.
>
> <tscreen><verb>
>
> #include <gtk/gtk.h>
>
> /* this is a callback function. the data arguments are ignored in this example..
> * More on callbacks below. */
> void hello (GtkWidget *widget, gpointer *data)
> {
> g_print ("Hello World\n");
> }
>
> /* another callback */
> void destroy (void)
> {
> gtk_main_quit ();
> }
>
> int main (int argc, char *argv[])
> {
> /* GtkWidget is the storage type for widgets */
> GtkWidget *window;
> GtkWidget *button;
>
> /* this is called in all gtk applications. Arguements are parsed from
> * the command line and are returned to the application. */
> gtk_init (&argc, &argv);
>
> /* create a new window */
> window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
>
> /* when the window is given the "destroy" signal (this can be given
> * by the application, or the window manager, the function destroy
> * will be called as defined above. The NULL passed to this function
> * is used to pass optional data into this "callback" function. */
> gtk_signal_connect (GTK_OBJECT (window), "destroy",
> GTK_SIGNAL_FUNC (destroy), NULL);
>
> /* sets the border width of the window. */
> gtk_container_border_width (GTK_CONTAINER (window), 10);
>
> /* creates a new button with the label "Hello World". */
> button = gtk_button_new_with_label ("Hello World");
>
> /* When the button receives the "clicked" signal, it will call the
> * function hello() passing it NULL as it's arguement. The hello() function is
> * defined above. */
> gtk_signal_connect (GTK_OBJECT (button), "clicked",
> GTK_SIGNAL_FUNC (hello), NULL);
>
> /* This will cause the window to be destroyed by calling
> * gtk_widget_destroy(window) when "clicked. Again, the destroy
> * signal could come from here, or the window manager. */
> gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
> GTK_SIGNAL_FUNC (gtk_widget_destroy),
> GTK_OBJECT (window));
>
> /* this packs the button into the window (a gtk container). */
> gtk_container_add (GTK_CONTAINER (window), button);
>
> /* the final step is to display this newly created widget... */
> gtk_widget_show (button);
>
> /* and the window */
> gtk_widget_show (window);
>
> /* all gtk applications must have a gtk_main(). Control ends here
> * and waits for an event to occur (like a key press or mouse event). */
> gtk_main ();
>
> return 0;
> }
> </verb></tscreen>
>
>
> To compile use:
>
> <tscreen><verb>
> gcc -Wall -g -lgtk -lgdk -lglib -lX11 -lXext -lm hello_world.c -o hello_world
> </verb></tscreen>
>
> The libraries above must all be in your default search paths, if not, add
> -L<library directory> and gcc will look in these directories for
> the needed
> libraries. For instance, on my Debian Linux box, I have to add
> <tt>-L/usr/X11R6/lib</> for it to find the X11 libraries.
> <p>
> Now the explanation:
> <p>
> As you can see from this example, it is quite easy to build a simple gtk
> application. GTK is an event driven toolkit, which means it will sleep in
> gtk_main until an event occurs and control is passed to the appropriate
> function. By passing in a pointer to the function to be called when the
> appropriate event occurs (by connecting a "signal") we tell the
> application what we want to have done with when a given event occurs.
> <p>
> (You may also add timeout functions and IO checks to take control from
> gtk_main, this is described in the approprate section.)
> <p>
> The general steps to creating a widget in gtk are:
> <enum>
> <item> gtk_*_new - one of various functions to create a new widget.
>
> <item> connect all signals we wish to use to the appropriate handlers.
>
> <item> set the attributes of the widget.
>
> <item> pack the widget into a container using gtk_container_add() or
> gtk_box_pack_start() (are there others ?).
>
> <item> gtk_widget_show()
> </enum>
>
> gtk_widget_show lets gtk know that we are done setting the attributes
> of the widget, and it is ready to be displayed. You may also use
> gtk_widget_hide to make it disappear again. The order in which you
> show the widgets is not important, but I suggest showing the window
> last so that it all pops up at once rather than seeing the individual
> widgets come up on the screen as they're formed.
>
>
> <sect>Events
> <p>
> When setting up a signal handler (better term ?) we use a call to
> gtk_signal_connect(). The deceleration of this function is:
>
> <tscreen><verb>
> gint gtk_signal_connect (GtkObject *object, gchar *name,
> GtkSignalFunc func, gpointer func_data);
> </verb></tscreen>
>
> There are a few things you'll notice right away from this example. The
> gint, gchar etc. are typedefs to int and char respectively. This is done
> for portabilities sake. A good example is "gint32" which will be
> typedef'd to a 32 bit integer for any platform, whether it be the 64 bit
> alpha (int (or short int?)), or the 32 bit Intel (long int or int). The
> typedefs are very straight forward and intuitive. They are all defined in
> glib/glib.h (which gets included from gtk.h).
> <p>
> The fist arguement to gtk_signal_connect is the object which will generate
> the signal, usually a widget (always?). The second of course is the
> signal name, followed by the function you wish to be called. This function
> is called a "callback" function. Then last arguement is a
> pointer to the data you wish to pass to the callback function.
> <p>
> The callback function you specify should be of the form:
>
> <tscreen><verb>
> void callback_func(GtkWidget *widget, gpointer *callback_data);
> </verb></tscreen>
>
> Generally, the GtkWidget arguement in the callback is unused.
> <p>
> So, if we wanted to pass the above function some data when a button is
> pressed, we use:
>
> <tscreen><verb>
> gtk_signal_connect (GTK_OBJECT (button), "clicked",
> GTK_SIGNAL_FUNC (callback_func), (gpointer) callback_data);
> </verb></tscreen>
>
> This assumes of course that you have already created a button. The
> GTK_OBJECT, GTK_SIGNAL_FUNC are just macros that perform type casting while
> adding readability.
> <p>
> Let's take a look at a slightly improved hello world with better examples
> of callbacks. This will also introduce us to our next topic, packing
> widgets.
>
> <tscreen><verb>
> #include <gtk/gtk.h>
>
> /* Our new improved callback. The data passed to this function is printed
> * to stdout. */
> void callback (GtkWidget *widget, gpointer *data)
> {
> g_print ("Hello again - %s was pressed\n", (char *) data);
> }
>
> /* another callback */
> void destroy (void)
> {
> gtk_main_quit ();
> }
>
> int main (int argc, char *argv[])
> {
> /* GtkWidget is the storage type for widgets */
> GtkWidget *window;
> GtkWidget *button;
> GtkWidget *box1;
>
> /* this is called in all gtk applications. Arguements are parsed from
> * the command line and are returned to the application. */
> gtk_init (&argc, &argv);
>
> /* create a new window */
> window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
>
> /* this is a new call, this just sets the title of our
> * new window to "Hello Buttons!" */
> gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
>
> /* It's a good idea to do this for all windows. */
> gtk_signal_connect (GTK_OBJECT (window), "destroy",
> GTK_SIGNAL_FUNC (destroy), NULL);
>
>
> /* sets the border width of the window. */
> gtk_container_border_width (GTK_CONTAINER (window), 10);
>
> /* we create a box to pack widgets into. this is described in detail
> * in the "packing" section below. The box is not really visible, it
> * is just used as a tool to arrange widgets. */
> box1 = gtk_hbox_new(FALSE, 0);
>
> /* put the box into the main window. */
> gtk_container_add (GTK_CONTAINER (window), box1);
>
> /* creates a new button with the label "Button 1". */
> button = gtk_button_new_with_label ("Button 1");
>
> /* Now when the button is clicked, we call the "callback" function
> * with a pointer to "button 1" as it's arguement */
> gtk_signal_connect (GTK_OBJECT (button), "clicked",
> GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
>
> /* instead of gtk_container_add, we pack this button into the invisible
> * box, which has been packed into the window. */
> gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
>
> /* always remember this step, this tells gtk that our preparation for
> * this button is complete, and it can be displayed now. */
> gtk_widget_show(button);
>
> /* do these same steps again to create a second button */
> button = gtk_button_new_with_label ("Button 2");
>
> /* call the same callback function with a different arguement,
> * passing a pointer to "button 2" instead. */
> gtk_signal_connect (GTK_OBJECT (button), "clicked",
> GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
>
> gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
>
> /* we show the widgets in the reverse order we created them,
> * someone want to explain to me why ?? :) or is it even
> * necessary ? */
> gtk_widget_show(button);
>
> gtk_widget_show(box1);
>
> gtk_widget_show (window);
>
> /* rest in gtk_main and wait for the fun to begin! */
> gtk_main ();
>
> return 0;
> }
> </verb></tscreen>
> <p>
> Compile this program using the same linking arguements as above. You'll notice in
> this example there is no easy way to exit the program, you have to use
> your window manager or command line to kill it. A good exercise for the
> reader would be to insert a third "Quit" button that will exit the
> program. Try playing with resizing the window.
> <p>
> Just as a side note, there is another useful define for gtk_window_new() -
> GTK_WINDOW_DIALOG. This interacts with the window manager a little
> differently and should be used for transient windows.
>
> <sect>Packing Widgets
> <p>
> When creating an application, you'll want to put more than one button
> inside a window. Our first hello world example only used one widget so we
> could simply use a gtk_container_add call to "pack" the widget into the
> window. But when you want to put more than one widget into a window, how
> do you control where that widget is positioned ? This is where packing
> comes in.
> <p>
> Most packing is done by creating boxes as in the example above. These are
> invisible widget containers that we can pack our widgets into and come in
> two forms, a horizontal box, and a vertical box. When packing widgets
> into a horizontal box, the objects are inserted horizontally from left to
> right or right to left depending on the call used. In a vertical box,
> widgets are packed from top to bottom or vice versa. You may use any
> combination of boxes inside or beside other boxes to create the desired
> effect.
> <p>
> To create a new horizontal box, we use a call to gtk_hbox_new(), and for
> vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
> gtk_box_pack_end() functions are used to place objects inside of these
> containers. The gtk_box_pack_start() function will start at the top and
> work its way down in a vbox, and pack left to right in an hbox.
> gtk_box_pack_end() will do the opposite, packing from bottom to top in a
> vbox, and right to left in an hbox. Using these functions allow us to
> right justify or left justify our widgets and may be mixed in any way to
> achieve the desired effect. We will use gtk_box_pack_start() in most of
> our examples. An object may be another container or a widget. And in
> fact, many widgets are actually containers themselves including the
> button, but we usually only use a label inside a button.
> <p>
> By using these calls, gtk knows where you want to place your widgets so it
> can do automatic resizing and other nifty things. there's also a number
> of options as to how your widgets should be packed. As you can imagine,
> this method gives us a quite a bit of flexibility when placing and
> creating widgets.
> <p>
> Because of this flexibility, packing boxes in GTK+ can be confusing at
> first. There are a lot of options, and it's not immediately obvious how
> they all fit together. In the end however, there are basically five
> different styles you can get.
>
> <tscreen><verb> <!-- Don't know the tag for images, but there is one -->
> <p align=center> <img src="packbox1.gif" width=528 height=235> </p>
> </verb></tscreen>
>
> Each line contains one horizontal box (hbox) with several buttons. The
> call to gtk_box_pack is shorthand for the call to pack each of the buttons
> into the hbox. Each of the buttons is packed into the hbox the same way
> (i.e. same arguments to the gtk_box_pack_start () function).
> <p>
> This is the declaration of the gtk_box_pack_start function.
>
> <tscreen><verb>
> void gtk_box_pack_start (GtkBox *box,
> GtkWidget *child,
> gint expand,
> gint fill,
> gint padding);
> </verb></tscreen>
>
> The first arguement is the box you are packing the object into, the second
> is this object. The objects will all be buttons for now, so we'll be
> packing buttons into boxes.
> <p>
> The expand argument to gtk_box_pack_start() or gtk_box_pack_end() controls
> whether the widgets are laid out in the box to fill in all the extra space
> in the box so the box is expanded to fill the area alloted to it (TRUE).
> Or the box is shrunk to just fit the widgets (FALSE). Setting expand to
> FALSE will allow you to do right and left
> justifying of your widgets. Otherwise, they will all expand to fit in the
> box, and the same effect could be achieved by using only one of
> gtk_box_pack_start or pack_end functions.
> <p>
> The fill argument to the gtk_box_pack functions control whether the extra
> space is allocated to the objects themselves (TRUE), or as extra padding
> in the box around these objects (FALSE). It only has an effect if the
> expand argument is also TRUE.
> <p>
> [does the above sound right to you ?]
> <p>
> When creating a new box, the function looks like this:
>
> <tscreen><verb>
> GtkWidget * gtk_hbox_new (gint homogeneous,
> gint spacing);
> </verb></tscreen>
>
> The homogeneous argument to gtk_hbox_new (and the same for gtk_vbox_new)
> controls whether each object in the box has the same size (i.e. the same
> width in an hbox, or the same height in a vbox). If it is set, the expand
> argument to the gtk_box_pack routines is always turned on.
> <p>
> What's the difference between spacing (set when the box is created) and
> adding (set when elements are packed)? Spacing is added between objects,
> and padding is added on either side of an object. The following figure
> should make it clearer:
>
> <tscreen><verb> <!-- Don't know the tag for images, but there is one -->
> <p align=center> <img src="packbox2.gif" width=509 height=213> </p>
> </verb></tscreen>
>
> <p>
> Someone write about table widgets! :)
>
> <sect>Widget Overview
> <p>
> We'll further our exploration of gtk by examining each widget in turn,
> creating a few simple functions to display them. Another good source is
> the testgtk.c program that comes with gtk. It can be found in
> gtk/testgtk.c.
> <p>
> For your reference, here is the class hierarchy tree used to implement widgets.
>
> <tscreen><verb>
> GtkObject
> +-- GtkData
> | \-- GtkAdjustment
> |
> \-- GtkWidget
> +-- GtkContainer
> | +-- GtkBin
> | | +-- GtkAlignment
> | | +-- GtkFrame
> | | | *-- GtkAspectFrame
> | | |
> | | +-- GtkItem
> | | | +-- GtkListItem
> | | | +-- GtkMenuItem
> | | | | +-- GtkCheckMenuItem
> | | | | *-- GtkRadioMenuItem
> | | | |
> | | | *-- GtkTreeItem
> | | |
> | | +-- GtkViewport
> | | \-- GtkWindow
> | | +-- GtkDialog
> | | \-- GtkFileSelection
> | |
> | +-- GtkBox
> | | +-- GtkHBox
> | | \-- GtkVBox
> | | +-- GtkColorSelection
> | | \-- GtkCurve
> | |
> | +-- GtkButton
> | | +-- GtkOptionMenu
> | | \-- GtkToggleButton
> | | \-- GtkCheckButton
> | | \-- GtkRadioButton
> | |
> | +-- GtkList
> | +-- GtkMenuShell
> | | +-- GtkMenu
> | | \-- GtkMenuBar
> | |
> | +-- GtkNotebook
> | +-- GtkScrolledWindow
> | +-- GtkTable
> | \-- GtkTree
> |
> +-- GtkDrawingArea
> +-- GtkEntry
> +-- GtkMisc
> | +-- GtkArrow
> | +-- GtkImage
> | +-- GtkLabel
> | \-- GtkPixmap
> |
> +-- GtkPreview
> +-- GtkProgressBar
> +-- GtkRange
> | +-- GtkScale
> | | +-- GtkHScale
> | | \-- GtkVScale
> | |
> | \-- GtkScrollbar
> | +-- GtkHScrollbar
> | \-- GtkVScrollbar
> |
> +-- GtkRuler
> | +-- GtkHRuler
> | \-- GtkVRuler
> |
> \-- GtkSeparator
> +-- GtkHSeparator
> \-- GtkVSeparator
>
> </verb></tscreen>
>
> <sect1>The Button Widget
> <p>
> We've almost seen all there is to see of the button widget. It's pretty
> simple. There is however two ways to create a button. You can use the
> gtk_button_new_with_label() to create a button with a label, or use
> gtk_button_new() to create a blank button. It's then up to you to pack a
> label or pixmap into this new button. To do this, create a new box, and
> then pack your objects into this box using the usual gtk_box_pack_start,
> and then use gtk_container_add to pack the box into the button.
> <p>
> Here's an example of using gtk_button_new to create a button with a
> picture and a label in it. I've broken the code to create a box up from
> the rest so you can use it in your programs.
>
>
> <tscreen><verb>
> #include <gtk/gtk.h>
>
>
> /* create a new hbox with an image and a label packed into it
> * and return the box.. */
>
> GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
> {
> GtkWidget *box1;
> GtkWidget *label;
> GtkWidget *pixmapwid;
> GdkPixmap *pixmap;
> GdkBitmap *mask;
> GtkStyle *style;
>
> /* create box for xpm and label */
> box1 = gtk_hbox_new (FALSE, 0);
> gtk_container_border_width (GTK_CONTAINER (box1), 2);
>
> /* get style of button.. I assume it's to get the background color.
> * if someone knows the real reason, please enlighten me. */
> style = gtk_widget_get_style(parent);
>
> /* now on to the xpm stuff.. load xpm */
> pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
> &style->bg[GTK_STATE_NORMAL],
> xpm_filename);
> pixmapwid = gtk_pixmap_new (pixmap, mask);
>
> /* create label for button */
> label = gtk_label_new (label_text);
>
> /* pack the pixmap and label into the box */
> gtk_box_pack_start (GTK_BOX (box1),
> pixmapwid, FALSE, FALSE, 3);
>
> gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
>
> gtk_widget_show(pixmapwid);
> gtk_widget_show(label);
>
> return (box1);
> }
>
> /* our usual callback function */
> void callback (GtkWidget *widget, gpointer *data)
> {
> g_print ("Hello again - %s was pressed\n", (char *) data);
> }
>
>
> int main (int argc, char *argv[])
> {
> /* GtkWidget is the storage type for widgets */
> GtkWidget *window;
> GtkWidget *button;
> GtkWidget *box1;
>
> gtk_init (&argc, &argv);
>
> /* create a new window */
> window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
>
> gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
>
> /* It's a good idea to do this for all windows. */
> gtk_signal_connect (GTK_OBJECT (window), "destroy",
> GTK_SIGNAL_FUNC (gtk_exit), NULL);
>
>
> /* sets the border width of the window. */
> gtk_container_border_width (GTK_CONTAINER (window), 10);
>
> /* create a new button */
> button = gtk_button_new ();
>
> /* You should be getting used to seeing most of these functions by now */
> gtk_signal_connect (GTK_OBJECT (button), "clicked",
> GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
>
> /* this calls our box creating function */
> box1 = xpm_label_box(window, "info.xpm", "cool button");
>
> /* pack and show all our widgets */
> gtk_widget_show(box1);
>
> gtk_container_add (GTK_CONTAINER (button), box1);
>
> gtk_widget_show(button);
>
> gtk_container_add (GTK_CONTAINER (window), button);
>
> gtk_widget_show (window);
>
> /* rest in gtk_main and wait for the fun to begin! */
> gtk_main ();
>
> return 0;
> }
> </verb></tscreen>
>
> The xpm_label_box function can be used to put xpm's and labels in many
> different widgets (I think :-).
>
>
> <sect1> Toggle Buttons
> <p>
> Toggle buttons are very similar to normal buttons, except they will always
> be in one of two states, alternated by a click. They may be depressed, and
> when you click again, they will pop back up. Click again, and they will pop
> back down.
>
> Toggle buttons are the basis for check buttons and radio buttons, as such,
> many of the calls used for toggle buttons are inhereted by radio and check
> buttons. I will point these out when we come to them.
>
> Creating a new toggle button:
>
> <tscreen><verb>
> GtkWidget* gtk_toggle_button_new (void);
>
> GtkWidget* gtk_toggle_button_new_with_label (gchar *label);
> </verb></tscreen>
> <p>
> As you can imagine, these work identically to the normal button widget
> calls. The first creates a blank toggle button, and the second, one with a
> label widget already packed into it.
> <p>
> To retreive the state of the toggle widget, including radio and check
> buttons, we use a macro as shown in our example below. This tests the state
> of the toggle in a callback. The signal of interest emitted to us by toggle
> buttons (the toggle button, check button, and radio button widgets), is the
> "toggled" signal. To check the state of these buttons, use a callback to
> catch this signal that looks something like this:
>
> <tscreen><verb>
> void toggle_button_callback (GtkWidget *widget, gpointer data)
> {
> if (GTK_TOGGLE_BUTTON (widget)->active)
> {
> /* If control reaches here, the toggle button is depressed. */
> }
> }
> </verb></tscreen>
>
> The above is in need of testing.. It's just a guess..
>
> <tscreen><verb>
> guint gtk_toggle_button_get_type (void);
> </verb></tscreen>
> <p>
> No idea... they all have this, but I dunno what it is :)
>
> <tscreen><verb>
> void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
> gint draw_indicator);
> </verb></tscreen>
> <p>
> No idea.
>
> <tscreen><verb>
> void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
> gint state);
> </verb></tscreen>
> <p>
> The above call can be used to set the state of the toggle button, and it's
> children the radio and check buttons. Passing
> in your created button as the first arguement, and a TRUE or FALSE
> for the second state arguement to specify whether it should be up (released) or
> down (depressed). Default is up, or FALSE.
>
> <tscreen><verb>
> void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
> </verb></tscreen>
> <p>
> Hmm.. judging from the gtk code, it toggles the button, and emits the
> "toggled" signal..
>
> <sect1> Check Buttons
> <p>
> Check buttons inherent many properties and functions from the the toggle buttons above,
> but look a little
> different. Rather than being buttons with text inside them, they are small
> squares with the text to the right of them. These are often seen for
> toggling options on and off in applications.
>
> The two creation functions are the same as for the normal button.
>
> <tscreen><verb>
> GtkWidget* gtk_check_button_new (void);
>
> GtkWidget* gtk_check_button_new_with_label (gchar *label);
> </verb></tscreen>
>
> The new_with_label function creates a check button with a label beside it.
>
> Checking the state of the check button is identical to that of the toggle
> button.
>
> <sect1> Radio Buttons
> <p>
> Radio buttons are similar to check buttons except they are grouped so that
> only one may be selected/depressed at a time. This is good for places in
> your application where you need to select from a short list of options.
>
> Creating a new radio button is done with one of these calls:
>
> <tscreen><verb>
> GtkWidget* gtk_radio_button_new (GSList *group);
>
> GtkWidget* gtk_radio_button_new_with_label (GSList *group,
> gchar *label);
> </verb></tscreen>
> <p>
> You'll notice the extra arguement to these calls. They require a group to
> perform they're duty properly. The first call should pass NULL as the first
> arguement. You then create a group using:
>
> <tscreen><verb>
> GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
> </verb></tscreen>
>
> <p>
> You then pass this group as the first arguement to each subsequent call to
> gtk_radio_button_new or new_with_label. It is also a good idea to
> explicitly set which button should be the default depressed button with:
>
> <tscreen><verb>
> void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
> gint state);
> </verb></tscreen>
> <p>
> This is described in the section on toggle buttons, and works in exactly the
> same way.
> <p>
> [Insert an example here of how to use these guys cause I think it could do a
> lot of good at this point.]
>
> <sect1>The Tooltips Widget
> <p>
> These are the little text strings that pop up when you leave your pointer
> over a button or other widget for a few seconds. They are easy to use, so I
> will just explain them without giving an example. If you want to see some
> code, take a look at the testgtk.c program distributed with gtk.
> <p>
> The first call you will use to create a new tooltip. You only need to do
> this once in a given function. The GtkTooltip this function returns can be
> used to create multiple tooltips.
>
> <tscreen><verb>
> GtkTooltips *gtk_tooltips_new (void);
> </verb></tscreen>
>
> Once you have created a new tooltip, and the widget you wish to use it on,
> simply use this call to set it.
>
> <tscreen><verb>
> void gtk_tooltips_set_tips (GtkTooltips *tooltips,
> GtkWidget *widget,
> gchar *tips_text);
> </verb></tscreen>
>
> The first arguement is the tooltip you've already created, followed by the
> widget you wish to have this tooltip pop up for, and the text you wish it to
> say.
> <p>
> Here's a short example:
>
> <tscreen><verb>
> GtkTooltips *tooltips;
> GtkWidget *button;
> ...
> tooltips = gtk_tooltips_new ();
> button = gtk_button_new_with_label ("button 1");
> ...
> gtk_tooltips_set_tips (tooltips, button, "This is button 1");
> </verb></tscreen>
>
>
>
> There are other calls used with tooltips. I will just list them with a
> brief description of what they do.
>
> <tscreen><verb>
> void gtk_tooltips_destroy (GtkTooltips *tooltips);
> </verb></tscreen>
>
> Destroy the created tooltips.
>
> <tscreen><verb>
> void gtk_tooltips_enable (GtkTooltips *tooltips);
> </verb></tscreen>
>
> Enable a disabled set of tooltips.
>
> <tscreen><verb>
> void gtk_tooltips_disable (GtkTooltips *tooltips);
> </verb></tscreen>
>
> Disable an enabled set of tooltips.
>
> <tscreen><verb>
> void gtk_tooltips_set_delay (GtkTooltips *tooltips,
> gint delay);
> void gtk_tooltips_set_tips
> (GtkTooltips *tooltips,
> GtkWidget *widget,
> gchar *tips_text);
> </verb></tscreen>
>
> Sets how many milliseconds you have to hold you pointer over the widget before the
> tooltip will pop up. The default is 1000 milliseconds or 1 second.
>
> <tscreen><verb>
> void gtk_tooltips_set_colors (GtkTooltips *tooltips,
> GdkColor *background,
> GdkColor *foreground);
> </verb></tscreen>
>
> Set the foreground and background color of the tooltips. Again, I have no
> idea how to specify the colors.
> <p>
> And that's all the functions associated with tooltips. More than you'll
> ever want to know :)
>
>
>
> <sect1> Scrolled Windows
> <p>
> Please write about me :)
>
> <sect1> Text Entries
> <p>
> Please write about me :)
>
> <sect1> Lists
> <p>
> Please write about me :)
>
> <sect1> Color Selections
> <p>
> Please write about me :)
>
> <sect1> File Selections
> <p>
> Please write about me :)
>
> <sect1> Dialogs
> <p>
> Please write about me :)
>
> <sect1> Range Controls
> <p>
> Please write about me :)
>
> <sect1> Rulers
> <p>
> Please write about me :)
>
> <sect1> Text Boxes
> <p>
> Please write about me :)
>
> <sect1> Notebooks
> <p>
> Please write about me :)
>
> <sect1> Progress Bars
> <p>
> Please write about me :)
>
> <sect1> Color Previews
> <p>
> Please write about me :)
>
> <sect1> Grey Previews
> <p>
> Please write about me :)
>
> <sect1> Curves
> <p>
> Please write about me :)
>
> <sect1> Pixmaps
> <p>
> Please write about me :)
>
>
> <sect1>Menu Widgets
> <p>
> There are two ways to create menus, there's the easy way, and there's the
> hard way. Both have their uses, but you can usually use the menu_factory
> (the easy way). The "hard" way is to create all the menus using the calls
> directly. The easy way is to use the gtk_menu_factory calls. This is
> much simpler, but I've had problems because of the '/' that is used to
> seperated menus. Other than this, there is no real reason to use the
> manual method (is this true ??)
> <p>
> In the true tradition of teaching, we'll show you the hard
> way first. <tt>:)</>
> <p>
> Let's look at the functions that are used to create menus.
> This first function is used to create a new menu.
>
> <tscreen><verb>
> GtkWidget *gtk_menu_bar_new()
> </verb></tscreen>
>
> This rather self explanatory function creates a new menu bar. You use
> gtk_container_add to pack this into a window, or the box_pack functions to
> pack it into a box - the same as buttons.
>
> <tscreen><verb>
> GtkWidget *gtk_menu_new();
> </verb></tscreen>
>
> This function returns a pointer to a new menu, it is never actually shown
> (with gtk_widget_show), it just holds the menu items. Hopefully this will
> become more clear when you look at the example below.
> <p>
> The next two calls are used to create menu items that are packed into
> the menu.
>
> <tscreen><verb>
> GtkWidget *gtk_menu_item_new()
> </verb></tscreen>
>
> and
>
> <tscreen><verb>
> GtkWidget *gtk_menu_item_new_with_label(const char *label)
> </verb></tscreen>
>
> These calls are used to create the menus that are to be displayed.
> Remember to differentiate between a "menu" as created with gtk_menu_new
> and a "menu item" as created by the gtk_menu_item_new functions. The
> menu item will be an actual button with an associated action,
> whereas a menu will be a container holding these
>
> <tscreen><verb>
> gtk_menu_item_append()
>
> gtk_menu_item_set_submenu()
> </verb></tscreen>
>
> The gtk_menu_new_with_label and plain gtk_menu_new functions are just as you'd expect after
> reading about the buttons. One creates a new menu item with a label
> already packed into it, and the other just creates a blank menu item.
> <p>
> The steps to create a menu are outlined below:
> <itemize>
> <item> Create a new menu using gtk_menu_new()
> <item> Create a menu item using gtk_menu_item_new(). This will be the root of
> the menu, the text appearing here will be on the menu bar itself.
> <item> Use multiple calls to gtk_menu_item_new for each item you wish to have on
> your menu. And use gtk_menu_item_append() to put each of these new items on
> together. This creates a list of menu items.
> <item> Use gtk_menu_item_set_submenu() to attach the newly created menu_items to
> the root menu item (The one created in the second step).
> <item> Create a new menu bar using gtk_menu_bar_new. This step only needs
> to be done once when creating a series of menus on one menu bar.
> <item> Use gtk_menu_bar_append to put the root menu onto the menubar.
> </itemize>
> And that should about do it. Let's take a look at an example to help clarify.
>
>
> <tscreen><verb>
> #include <gtk/gtk.h>
>
> int main (int argc, char *argv[])
> {
>
> GtkWidget *window;
> GtkWidget *menu;
> GtkWidget *menu_bar;
> GtkWidget *root_menu;
> GtkWidget *menu_items;
> char buf[128];
> int i;
>
> gtk_init (&argc, &argv);
>
> /* create a new window */
> window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
> gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
> gtk_signal_connect(GTK_OBJECT (window), "destroy",
> (GtkSignalFunc) gtk_exit, NULL);
>
> /* Init the menu-widget, and remember -- never
> * gtk_show_widget() the menu widget!! */
> menu = gtk_menu_new();
>
> /* This is the root menu, and will be the label will be the menu name displayed on
> * the menu bar. There won't be
> * a signal handler attached, as it only pops up the rest of the menu when pressed. */
> root_menu = gtk_menu_item_new_with_label("Root Menu");
>
> gtk_widget_show(root_menu);
>
> /* Next we make a little loop that makes three menu-entries for "test-menu".
> * Notice the call to gtk_menu_append. Here we are adding a list of menu items
> * to our menu. Normally, we'd also catch the "clicked" signal on each of the
> * menu items and setup a callback for it, but it's omitted here to save space. */
>
> for(i = 0; i < 3; i++)
> {
> /* Copy the names to the buf. */
> sprintf(buf, "Test-undermenu - %d", i);
>
> /* Create a new menu-item with a name... */
> menu_items = gtk_menu_item_new_with_label(buf);
>
> /* ...and add it to the menu. */
> gtk_menu_append(GTK_MENU (menu), menu_items);
>
> /* Show the widget */
> gtk_widget_show(menu_items);
> }
>
> /* Now we specify that we want our newly created "menu" to be the menu for the "root menu" */
> gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
>
> /* Create a menu-bar to hold the menus and add it to our main window*/
> menu_bar = gtk_menu_bar_new();
> gtk_container_add(GTK_CONTAINER(window), menu_bar);
> gtk_widget_show(menu_bar);
>
> /* And finally we append the menu-item to the menu-bar -- this is the "root"
> * menu-item I have been raving about =) */
> gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
>
> /* always display the window as the last step so it all splashes on the screen at once. */
> gtk_widget_show(window);
>
> gtk_main ();
>
> return 0;
> }
> </verb></tscreen>
>
> You may also set a menu item to be insensitive or, using an accelerator
> table, bind keys to menu functions.
> <p>
> [ maybe insert a few calls or something ]
> <p>
> Now that we've shown you the hard way, here's how you do it using the
> gtk_menu_factory calls.
> <p>
> [ gtk_menu_factory example and explanation ]
>
> <sect>Timeouts, IO and Idle Functions
> <p>
> <sect1>Timeouts
> <p>
> You may be wondering how you make gtk do useful work when in gtk_main.
> Well, you have several options. Using the following functions you can
> create a timeout function.
>
> <tscreen><verb>
> gint gtk_timeout_add (guint32 interval,
> GtkFunction function,
> gpointer data);
> </verb></tscreen>
>
> The first arguement is the number of milliseconds
> between calls to your function. The second arguement is the function
> you wish to have called, and
> the third, the data passed to this callback function. The return value is
> an integer "tag" which may be used to stop the timeout by calling:
>
> <tscreen><verb>
> void gtk_timeout_remove (gint tag);
> </verb></tscreen>
>
> You may also stop the timeout function by returning zero or FALSE from
> your callback function. Obviously this means if you want your function to
> continue to be called, it should return a non-negative value, ie TRUE.
>
> The declaration of you callback should look something like this:
>
> <tscreen><verb>
> gint timeout_callback (gpointer data);
> </verb></tscreen>
>
> <sect1>Monitoring IO
> <p>
> Another nifty feature of gtk, is the ability to have it check for data on a
> file descriptor for you (as returned by open(2) or socket(2)). This is
> especially useful for networking applications. The function:
>
> <tscreen><verb>
> gint gdk_input_add (gint source,
> GdkInputCondition condition,
> GdkInputFunction function,
> gpointer data);
> </verb></tscreen>
>
> Where the first arguement is the file descriptor you wish to have watched,
> and the second specifies what you want gdk to look for. This may be one of:
> <p>
> GDK_INPUT_READ - Call your function when there is data ready for reading on
> your file descriptor.
> <p>
> GDK_INPUT_WRITE - Call your function when the file descriptor is ready for
> writing.
> <p>
> As I'm sure you've figured out already, the third arguement is the function
> you wish to have called when the above conditions are satisfied, and the
> fourth is the data to pass to this function.
> <p>
> The return value is a tag that may be used to stop gdk from monitoring this
> file descriptor using the following function.
>
> <tscreen><verb>
> void gdk_input_remove (gint tag);
> </verb></tscreen>
> <p>
> As with the gtk_timeout_add function above, a FALSE return from your
> callback function will also cause gtk to stop monitoring the file
> descriptor. (will have to verify this.)
>
>
> <sect1>Idle Functions
> <p>
> What about if you have a function you want called when nothing else is
> happening ?
>
> <tscreen><verb>
> gint gtk_idle_add (GtkFunction function,
> gpointer data);
>
> void gtk_idle_remove (gint tag);
> </verb></tscreen>
> <p>
> I won't explain the meaning of the arguements as they follow very much like
> the ones above. The function pointed to by the first arguement to
> gtk_idle_add will be called whenever the opportunity arises. As with the
> others, returning FALSE will stop the idle function from being called.
>
>
> <sect>glib Functions
> <p>
> There are several useful function that we recomend you use when creating gdk
> and gtk applications. I will list them all here with a brief explanation.
> They are all duplicates of standard libc functions so I won't go into
> detail. This is mostly to be used as a reference, so you know what is
> available for use.
>
>
> <tscreen><verb>
> gpointer g_malloc (gulong size);
> </verb></tscreen>
>
> This is a replacement for malloc(). You do not need to check the return
> vaule as it is done for you in this function.
>
> <tscreen><verb>
> gpointer g_malloc0 (gulong size);
> </verb></tscreen>
>
> Same as above, but zero's the memory before returning a pointer to it.
>
> <tscreen><verb>
> gpointer g_realloc (gpointer mem,
> gulong size);
> </verb></tscreen>
>
> Relocates "size" bytes of memory starting at "mem". Obviously, the memory should have been
> previously allocated.
>
> <tscreen><verb>
> void g_free (gpointer mem);
> </verb></tscreen>
>
> Free's memory. Easy one.
>
> <tscreen><verb>
> gchar* g_strdup (const gchar *str);
> </verb></tscreen>
>
> Replacement strdup function. Allocates memory for a new string and returns
> a pointer to it.
>
> <tscreen><verb>
> gchar* g_strerror (gint errnum);
> </verb></tscreen>
>
> I recomend using this for all error messages. It's much nicer, and more
> portable than perror() or others. The output is usually of the form:
>
> <tscreen><verb>
> program name:function that failed:file or further description:strerror
> </verb></tscreen>
>
> Here's an example of one such call used in our hello_world program:
>
> <tscreen><verb>
> g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
> </verb></tscreen>
>
> And our last function:
>
> <tscreen><verb>
> gchar* g_strsignal (gint signum);
> </verb></tscreen>
>
> Prints out the name of the signal given the signal number.
>
> There are many more such functions in glib/glib.h, but I will not go into
> depth on them. If anyone wants to add some short descriptions of other
> functions in here, like for the linked list stuff, please do.
>
>
>
> <sect>gtkrc Files
> <p>
> GTK has it's own way of dealing with application defaults, by using rc
> files. The following functions are used:
>
> <tscreen><verb>
>
> void gtk_rc_init (void);
>
> void gtk_rc_parse (char *filename);
>
> GtkStyle* gtk_rc_get_style (GtkWidget *widget);
>
> void gtk_rc_add_widget_name_style (GtkStyle *style,
> char *pattern);
>
> void gtk_rc_add_widget_class_style (GtkStyle *style,
> char *pattern);
>
> </verb></tscreen>
> <p>
> The most common one is gtk_rc_init() which will cause
> GTK to parse the file given as its arguementand and use the defaults found in it.
> This can be used to set colors, pixmaps for backgrounds etc.
> <p>
> If someone could expand further on this... I'd like to see examples of gtkrc
> files too. This is something that still mystifies me.
>
> <sect>Writing Your Own Widgets
> <p>
> It's in the works.
>
>
> <sect>Contributing
>
> <p>
> This document, like so much other great software out there, was created for
> free by volenteers. If you are at all knowledgable about any aspect of gtk
> that does not already have documentation, please consider contributing to
> this document.
> <p>
> If you do decide to contribute, please mail your text to me, Ian Main,
> <tt><htmlurl url="mailto:slow@intergate.bc.ca"
> name="slow@intergate.bc.ca"></tt>. Also, be aware that the entirity of this
> document is free, and any addition by yourself must also be free. That is,
> people may use any portion of your examples in their programs, and copies
> of this document may be distributed at will etc.
> <p>
> Thank you.
>
>
> <sect>Credits
> <p>
> I would like to thank the following for their contributions to this text.
>
> <itemize>
> <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
> name="chamele0n@geocities.com"></tt>
> for the menus tutorial.
>
> <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
> name="raph@acm.org"></tt>
> for hello world ala gtk, and the widget packing.
>
> <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
> name="petm@xcf.berkeley.edu"></tt>
> for the simplest gtk program.
>
> <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
> name="werner.koch@guug.de"></tt> for converting the original plain text to
> SGML, and the widget class hierarchy.
>
> </itemize>
> <p>
> And to all of you who commented and helped refine this document.
> <p>
> Thanks.
>
> </article>
>
> --
> To unsubscribe: mail -s unsubscribe gtk-list-request@redhat.com < /dev/null
>
>
------------------------------------------------------
/ Pavel Grinfeld, a.k.a.
/ Pavel Greenfield
/
/ http://www.geocities.com/SoHo/5277
/
/ pavel@ml.com
/
/ (212) 449 1318 (w)
/ (212) 449 5865 (w if you really need to find me)
/ (212) 797 1688
______________________________________________________
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]