RE: g_signal_connect
- From: "Freddie Unpenstein" <fredderic excite com>
- To: gtk-app-devel-list gnome org
- Subject: RE: g_signal_connect
- Date: Tue, 3 May 2005 23:25:54 -0400 (EDT)
the g_signal_connect works like what?
g_signal_connect(GTK_WIDGET(widget),
signal("clicked"),<br>G_CALLBACK(Function),
(gpointer) "Data");
but the callbacks functions have the GtkWidget *Widget as a 1st
parameter, and... well, i simply don't get it. =)
Lots of answers, means lots of chances to understand. But I haven't seen one that really explains WHY those
arguments are there, and what they're useful for. So I'll throw in my 2000c worth... ;)
An "object" is a cluster of information and traits, related to a specific purpose. A button, for example,
has a rectanglular area on the screen, an appearance that it knows how to draw, a child widget that it
contains, and a purpose, which it fulfills via callback functions. All these things it knows about and can
do, are encapsulated within the concept of an object. Some traits and capabilities (represented by the API
functions), such as its rectangular area are inherited from a "parent" object. A check button, for instance,
has all the traits of a toggle button, which is similar to a standard button but with slightly different
symantics. (The "clicked" callback is a feature of the GtkButton.)
Now, if you've got three buttons on the screen, and they all were using the same callback function, how would
you know which one the user clicked on? To answer that question, two extra arguments are passed besides the
ones that the "clicked" signal defines. One, is a pointer to the actual button that was clicked on
(GtkWidget *widget), and the other is an argument of your choosing. A user data pointer. The widget pointer
allows you to easily reach back into the widget that caused the clicked signal, for instance, to fetch some
data that was attached to it, or even to change the colour of the text label, or make it insensitive, or
whatever. The user pointer would usually carry information that makes that button's purpose different from
the other two. Maybe it's the Play button on a music player, rather than the Stop button. They're both
buttons. And with i18n, you can't even be certain what the buttons text will be. So the only way to tell
them apart, is with the user
data.
Since you've got a play and a stop button, you might want only one to be sensitive (available) at a time. So
you might pass the pointer to the other one as the user data. Whichever one was clicked on, you can
insensitise using the "widget" pointer. And the other one you can make sensitive through the user data.
There are other things you can do too. Say you want to make the button simply cease to exist as soon as it
gets clicked. You could use gtk_widget_destroy() as the callback function. I once did something like that
with log messages, each built as a button that destroyed itself when clicked (or when a timer expired). The
timer ID was attached as data to the button widget, and destroyed in the widgets own destroy signal handler.
So no matter which way it happened, everything was cleaned up automatically, and once the button was made I
didn't have to keep any pointers to it, or any extra data anywhere. The entire log message, and the option
for the user to get ri
d or it or just wait until it went away itself, was all wrapped up in a set-and-forget parcel.
On the other hand, you might want to make it destroy the entire window when it gets clicked. A cancel button
on a dialog box or preferences page, for instance. You can use the same trick, passing gtk_widget_destroy()
as the callback. But instead of allowing it to destroy the widget itself, you pass the pointer to the window
as the user data, and use the g_signal_connect_swapped() method instead. This puts the user data first, and
the widget pointer last. gtk_widget_destoy() only looks at the first argument, so it destroys the entire
window instead of a single widget. I frequently attach a windows close signal directly to
gtk_widget_destroy() using g_signal_connect(), and use the very technique I just mentioned on a Close/Cancel
button to just make the whole thing go away, in exactly the same way. There are "other" ways of doing it,
such as if you need to ask the user if they're sure before you close it. But for a simple task like getting
rid of a small message box, us
e a simple solution.
A signal is the means by which an object (such as a button) tells you something has happened. And the widget
and user data pointers are the means by which it tells you which specific widget it was (among however many
of them might be there), and what its purpose for being there was. You don't have to use either, for
instance, if there's only one widget that will ever call that callback function for one particular reason.
But in the case of gtk_widget_destroy(), it has no idea which widget was calling it unless you tell it. And
in the case of the log messages, each message was put up as a button, as it happened at run-time. There was
no way to predict how many buttons there might me, or even whether there would be any at all. And since the
GtkVBox they were being packed into was already a list of them all, there wasn't much point duplicating the
effort by creating and maintaining my own list, when the widgets callbacks contained all the information
needed to perform the
buttons purpose (which was simply to get rid of itself and the associated timer).
Fredderic
_______________________________________________
Join Excite! - http://www.excite.com
The most personalized portal on the Web!
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]