On Fri, 2007-05-04 at 10:28 -0400, Alejandro Valdes Jimenez wrote:
> Adjunto un ejemplo que hice de gobject para que alguien si tiene un
> tiempecito le de una miradita... quiero saber si está bien
> implementado
> y si es un buen ejemplo.
Le eché una mirada rápida, no soy experto en GObject, pero tengo algunos
comentarios, ojalá te sean útiles:
- Para definir el tipo te conviene usar la macro G_DEFINE_TYPE(), ya que
evita que escribas a mano la declaración de varias funciones y
cabeceras que son siempre iguales. Ve la documentación sobre esa macro
y las otras relacionadas.
- Los atributos públicos que definiste (nombre, edad) típicamente
serían declarados de otra manera: como datos privados, y con
funciones _get_name/age (), _set_name/age (). Además, si quieres
utilizar 100% GObject, deberías instalar esas propiedades en la
clase. Para eso necesitarías:
- Agregar una enumeración con todas las propiedades, para poder
asignarle a cada una un entero distinto:
enum {
PROP_NAME = 1,
PROP_AGE
};
- En _class_init ():
/* substituir las funciones set/get_property por defecto de la
clase padre por unas definidas en nuestra clase */
g_object_class->set_property = my_object_set_property;
g_object_class->get_property = my_object_get_property;
/* ... */
/* instalar una propiedad para guardar el nombre de la persona */
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string ("name",
"Name",
"The name of the
person",
"anónimo",
G_PARAM_READABLE |
G_PARAM_WRITEABLE));
/* ... */
Esta llamada lo que hace es instalar en tu clase una propiedad de
lectura/escritura "name" de tipo string, con valor por defecto
"anónimo". Haces algo similar para la edad, pero usas
g_param_spec_int (). Haces lo mismo para cada una de las otras
propiedades públicas que quieras instalar.
Todavía faltaría declarar las funciones set/get_property (). Estas se
deben ver así aproximadamente:
my_object_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MyObjectPrivate *priv = MY_OBJECT (object)->priv;
switch (prop_id) {
case PROP_NAME:
/* guardar la propiedad en mi string privado */
if (priv->name) {
g_free (priv->name);
}
priv->name = g_strdup (g_value_get_string (value));
break;
case PROP_AGE:
priv->age = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
my_object_get_property() es bastante similar,
my_object_get_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MyObjectPrivate *priv = MY_OBJECT (object)->priv;
switch (prop_id) {
case PROP_NAME:
g_value_set_string (value, priv->name);
break;
case PROP_AGE:
g_value_set_int (value, priv->age);
break;
default:
/* warn again... */
}
}
- La declaración de métodos usando punteros a función que hiciste tiene
sentido exclusivamente si deseas que una clase heredada cambie la
manera de realizar la acción que dicho método haría por defecto, y
aún así poder ejecutarla tu mismo. Si lo que deseas es escribir un
simple método sin nada especial, que no sea reimplementable por las
clases heredadas, no necesitas agregar el puntero a función.
De todas maneras, nunca querrías que tus usuarios llamen a métodos
usando directamente punteros a funciones. Tener algo como
my_object_print (MyObject *object)
{
object->print_function (object);
}
Sería ideal. Así para los usuarios es transparente que la función haya
sido reemplazada o no.
- La declaración de la estructura privada en un archivo separado
(-private.h) sólo es útil si vas a dividir el código de tu clase
en más de un archivo. En caso contrario (como en tu ejemplo), bastaría
con declararla en el mismo archivo .c
Algunas cuestiones de estilo con respecto a tus métodos:
- En vez de hacer las llamadas
obj = persona_main_app_new ();
obj->agregar_persona (obj,"matias",1);
Yo asignaría los valores de la persona directamente en el constructor:
obj = persona_new ("matías", 1);
O también:
obj = persona_new ();
persona_set_age (obj, 1);
persona_set_name (obj, "matias");
O, si instalaste las propiedades a la GObject, podrías incluso hacerlo
así:
obj = persona_new ();
g_object_set_property (obj, "age", 1);
g_object_set_property (obj, "name", "matias");
- El nombre (PersonaMainApp) me suena familiar :-)
Eso sería. Espero te sean útiles estos comentarios. Si quieres ver un
ejemplo completo de una clase escrita con GObject, que instala
propiedades, señales, y tiene dos constructores, te recomiendo mirar los
archivos eog/src/eog-print-preview.[ch], que pueden servirte.
¡Saludos y que te diviertas con GObject!
Claudio
--
Claudio Saavedra <[EMAIL PROTECTED]>