Programando para Haiku - BApplication, BWindow y BButton - Parte I
18/05/2016
Hoy voy a comenzar una serie de tutoriales donde explicaré la programación de una apliación en Haiku. Para ello vamos a usar C++ y la BeAPI. Siempre que tengais cualquier duda podéis visitar la documentación oficial: tanto la antigua de BeOS en el BeBook y la nueva de Haiku en Haiku API. Aun así hay APIs nuevas que todavía no aparecen documentadas. En ese caso hay que recurrir al código fuente.
Haiku (y BeOS) comparte con UNIX muchas características de bajo nivel. El tema de las librerías es uno de ellos. También han de empezar por lib y terminar por .so si son compartidas y .a si son estáticas. Para compilar también se usa GCC. Sin embargo hay una pequeña diferencia con el resto de sistemas UNIX. En UNIX normalmente disponemos de una librería del C, libc y una librería de funciones matemáticas, libm. En Haiku no existe libm, en cambio existen muchas más, libroot y libbe, para interactuar con el sistema de manera básica, libtracker, con funciones relacionadas con el explorador de archivos, libnetwork y libnetapi, con funciones de red, y muchas otras.
Además la API se divide en Kits, cada Kit se encarga de una tareas diferentes dentro del sistema operativo. AppKit, Game Kit, Interface Kit, Media Kit, Storage Kit, etc... Si queremos usar la funcionalidad de un kit tendremos que revisar que hemos añadido la librería correcta al compilador y que hemos añadido #include dentro del código que lo usemos.
Vamos a empezar por lo simple, una aplicación que muestre una ventana y ya.
Creamos un archivo de C++, será el punto de inicio de nuestra aplicación. Como sabéis, el punto de inicio de un programa de C o C++ es la función main.
Hemos creado un objeto llamado app del tipo AplicacionPrueba y después hemos ejecutado la aplicación. AplicacionPrueba tiene que ser del tipo BApplication. Es la clase básica de todas las aplicaciones Haiku/BeOS. BApplication provee de mensajería entre los distintos procesos del programa (hay que tener en cuenta que BeOS se diseñó pensando en el multiproceso). Vamos a ver como definimos AplicacionPrueba
Las Application necesitan un MIME type, al igual que se usa para indicar los tipos de archivo. No es necesario que sea real. Además hemos creado un objeto VentanaPrueba y la mostramos. VentanaPrueba es del tipo BWindow y es la ventana básica de Haiku, lo que vemos. Veamos la definición:
BWindow necesita un tamaño, que es indicado con BRect, un título, un estilo (por defecto es BTITLEDWINDOW, pero podemos tener ventanas sin bordes o modal) y opciones varias. En las opciones varias podemos especificar que al cerrar la ventana se cierre la aplicación (BQUITONWINDOWCLOSE), que el usuario no pueda cambiar su tamaño (BNOTRESIZABLE), que no se pueda minimizar (BNOTMINIMIZABLE) y otras opciones por el estilo.
Además dentro de la clase hemos definido dos funciones virtuales, es decir, que tienen implementación por defecto de la clase padre, BWindow, pero nosotros podemos modificar su comportamiento.
QuitRequested es llamada cuando algo pide el cierre de la ventana. El objeto global beappmessenger es del tipo BApplication, pero está definido en todos los puntos de nuestra aplicación sin que nosotros hagamos nada. Gracias a este objeto podemos enviar mensajes entre procesos. En este caso enviamos el mensaje a la aplicación de BQUITREQUESTED. Y luego llamamos a la función sin modificar.
MessageReceived es muy importante. Se encarga de procesar todos los mensajes que recibe la ventana. Para distinguir los mensajes (que son del tipo BMessage) tenemos que inspeccionar la propiedad what. Se trata de un valor de tipo uint32. Hay algunos ya definidos por el sistema como BQUITREQUESTED pero nosotros podemos definir más. Veremos más tarde como. De momento simplemente devolvemos el procesado de mensajes a BWindow padre.
Con esto ya podemos compilar.
Ahora vamos a añadir cosas a nuestra ventana sosa. Ponemos una vista dentro de la ventana. Las vistas en Haiku son muy potentes pero eso lo trataré en otro momento. A esa vista le añadiremos un botón.
Aquí hemos hecho varias cosas. Por una parte he creado un layout horizontal. Es decir, dispongo el espacio de la ventana de manera horizontal, según se vayan añadiendo elementos lo harán a la derecha. Esto no estaba en BeOS y es particular de Haiku, pero recomiendo usar este sistema pues permite realizar un responsive design. Creamos una vista o panel. Bounds() indica que cubra todo el espacio disponible. El resto son propiedades de la vista más o menos estándar. Con SetViewColor le podemos poner un color de fondo, y con SetLayout le aplicamos el layout previamente creado.
Creamos un botón, que es del tipo BButton. BButton tiene muchos constructores si revisais la documentación pero este es muy cómodo si usamos el sistema de layouts. Simplemente indicamos el texto que va a mostrar y el mensaje que envía. En este caso NULL pues no vamos a poner ninguno.
sizer->AddView() lo usamos para añadir el botón al layaout y AddChild para añadir la vista a la ventana. Puedes compilar.
Vamos ahora a crear un evento para el botón. Cuando pulsemos el botón mostrará un mensaje al usuario.
Los eventos se realizan por el sistema de mensajería basado en BMessage y BHandler. Para crear un BMessage necesitamos un ID, que es del tipo uint32. Eso es lo mínimo y con eso ya serviría para este caso.
Pero los mensajes pueden llevar información adicional de cualquier tipo. Por ejemplo si queremos añadir además una cadena de texto al mensaje usaremos AddString.
Podremos recuperar el valor en cualquier momento con FindString.
Ahora si vamos a MessageReceived podemos añadir código que gestione este tipo de mensaje.
Con un simple case gestionamos el mensaje. Para mostrar un diálogo simple se puede usar BAlert. Es muy simple, indicamos el título, el contenido del mensaje y el texto del botón que aparecerá. Y con Go lo mostramos.
Esta ha sido la primera parte del tutorial. Os ha gustado. Hay algo que no haya quedado claro. Comentádmelo.
Librerías en Haiku
Haiku (y BeOS) comparte con UNIX muchas características de bajo nivel. El tema de las librerías es uno de ellos. También han de empezar por lib y terminar por .so si son compartidas y .a si son estáticas. Para compilar también se usa GCC. Sin embargo hay una pequeña diferencia con el resto de sistemas UNIX. En UNIX normalmente disponemos de una librería del C, libc y una librería de funciones matemáticas, libm. En Haiku no existe libm, en cambio existen muchas más, libroot y libbe, para interactuar con el sistema de manera básica, libtracker, con funciones relacionadas con el explorador de archivos, libnetwork y libnetapi, con funciones de red, y muchas otras.
Además la API se divide en Kits, cada Kit se encarga de una tareas diferentes dentro del sistema operativo. AppKit, Game Kit, Interface Kit, Media Kit, Storage Kit, etc... Si queremos usar la funcionalidad de un kit tendremos que revisar que hemos añadido la librería correcta al compilador y que hemos añadido #include dentro del código que lo usemos.
Un hola mundo
Vamos a empezar por lo simple, una aplicación que muestre una ventana y ya.
Creamos un archivo de C++, será el punto de inicio de nuestra aplicación. Como sabéis, el punto de inicio de un programa de C o C++ es la función main.
int main(int argc, char** argv)
{
AplicacionPrueba app;
return app.Run();
}
Hemos creado un objeto llamado app del tipo AplicacionPrueba y después hemos ejecutado la aplicación. AplicacionPrueba tiene que ser del tipo BApplication. Es la clase básica de todas las aplicaciones Haiku/BeOS. BApplication provee de mensajería entre los distintos procesos del programa (hay que tener en cuenta que BeOS se diseñó pensando en el multiproceso). Vamos a ver como definimos AplicacionPrueba
#include <AppKit.h>
class AplicacionPrueba : public BApplication {
public:
VentanaPrueba* ventana;
AplicacionPrueba() : BApplication("application/x-applicion-prueba"){
ventana = new VentanaPrueba();
ventana->Show();
}
};
Las Application necesitan un MIME type, al igual que se usa para indicar los tipos de archivo. No es necesario que sea real. Además hemos creado un objeto VentanaPrueba y la mostramos. VentanaPrueba es del tipo BWindow y es la ventana básica de Haiku, lo que vemos. Veamos la definición:
class VentanaPrueba : public BWindow{
public:
VentanaPrueba() : BWindow(BRect(100,100,900,700),"Mi ventana", B_TITLED_WINDOW,0){
// iniciar ventana
}
bool QuitRequested(){
be_app_messenger.SendMessage(B_QUIT_REQUESTED);
return BWindow::QuitRequested();
}
void MessageReceived(BMessage* msg){
switch(msg->what){
default:
BWindow::MessageReceived(msg);
}
}
};
BWindow necesita un tamaño, que es indicado con BRect, un título, un estilo (por defecto es BTITLEDWINDOW, pero podemos tener ventanas sin bordes o modal) y opciones varias. En las opciones varias podemos especificar que al cerrar la ventana se cierre la aplicación (BQUITONWINDOWCLOSE), que el usuario no pueda cambiar su tamaño (BNOTRESIZABLE), que no se pueda minimizar (BNOTMINIMIZABLE) y otras opciones por el estilo.
Además dentro de la clase hemos definido dos funciones virtuales, es decir, que tienen implementación por defecto de la clase padre, BWindow, pero nosotros podemos modificar su comportamiento.
QuitRequested es llamada cuando algo pide el cierre de la ventana. El objeto global beappmessenger es del tipo BApplication, pero está definido en todos los puntos de nuestra aplicación sin que nosotros hagamos nada. Gracias a este objeto podemos enviar mensajes entre procesos. En este caso enviamos el mensaje a la aplicación de BQUITREQUESTED. Y luego llamamos a la función sin modificar.
MessageReceived es muy importante. Se encarga de procesar todos los mensajes que recibe la ventana. Para distinguir los mensajes (que son del tipo BMessage) tenemos que inspeccionar la propiedad what. Se trata de un valor de tipo uint32. Hay algunos ya definidos por el sistema como BQUITREQUESTED pero nosotros podemos definir más. Veremos más tarde como. De momento simplemente devolvemos el procesado de mensajes a BWindow padre.
Con esto ya podemos compilar.
gcc -o AplicacionPrueba app.cpp -lbe -lroot
Añadiendo BView, BButton y BGroupLayout
Ahora vamos a añadir cosas a nuestra ventana sosa. Ponemos una vista dentro de la ventana. Las vistas en Haiku son muy potentes pero eso lo trataré en otro momento. A esa vista le añadiremos un botón.
VentanaPrueba() : BWindow(BRect(100,100,900,700),"Mi ventana", B_TITLED_WINDOW,0){
// iniciar ventana
BGroupLayout* sizer = new BGroupLayout(B_HORIZONTAL);
BView* panel = new BView(Bounds(), NULL, B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE |
B_FRAME_EVENTS | B_DRAW_ON_CHILDREN);
panel->SetViewColor(220, 220, 220);
panel->SetLayout(sizer);
BButton* boton = new BButton("Hola Mundo",NULL);
sizer->AddView(boton);
AddChild(panel);
}
Aquí hemos hecho varias cosas. Por una parte he creado un layout horizontal. Es decir, dispongo el espacio de la ventana de manera horizontal, según se vayan añadiendo elementos lo harán a la derecha. Esto no estaba en BeOS y es particular de Haiku, pero recomiendo usar este sistema pues permite realizar un responsive design. Creamos una vista o panel. Bounds() indica que cubra todo el espacio disponible. El resto son propiedades de la vista más o menos estándar. Con SetViewColor le podemos poner un color de fondo, y con SetLayout le aplicamos el layout previamente creado.
Creamos un botón, que es del tipo BButton. BButton tiene muchos constructores si revisais la documentación pero este es muy cómodo si usamos el sistema de layouts. Simplemente indicamos el texto que va a mostrar y el mensaje que envía. En este caso NULL pues no vamos a poner ninguno.
sizer->AddView() lo usamos para añadir el botón al layaout y AddChild para añadir la vista a la ventana. Puedes compilar.
Añadiendo eventos. Mensajería con BMessage. Diálogo con BAlert.
Vamos ahora a crear un evento para el botón. Cuando pulsemos el botón mostrará un mensaje al usuario.
Los eventos se realizan por el sistema de mensajería basado en BMessage y BHandler. Para crear un BMessage necesitamos un ID, que es del tipo uint32. Eso es lo mínimo y con eso ya serviría para este caso.
const uint32 MOSTRAR_DIALOGO = 1;
...
BMessage* msg = new BMessage(MOSTRAR_DIALOGO);
BButton* boton = new BButton("Hola mundo",msg);
...
Pero los mensajes pueden llevar información adicional de cualquier tipo. Por ejemplo si queremos añadir además una cadena de texto al mensaje usaremos AddString.
msg->AddString("NombrePropiedad","ValorPropiedad");
Podremos recuperar el valor en cualquier momento con FindString.
Ahora si vamos a MessageReceived podemos añadir código que gestione este tipo de mensaje.
void MessageReceived(BMessage* msg){
switch(msg->what){
case MOSTRAR_DIALOGO:
BAlert* alert = new BAlert("Hola", "Sabes pulsar el boton, eh?", "Sip");
alert->Go();
break;
default:
BWindow::MessageReceived(msg);
}
}
Con un simple case gestionamos el mensaje. Para mostrar un diálogo simple se puede usar BAlert. Es muy simple, indicamos el título, el contenido del mensaje y el texto del botón que aparecerá. Y con Go lo mostramos.
Esta ha sido la primera parte del tutorial. Os ha gustado. Hay algo que no haya quedado claro. Comentádmelo.
#include <AppKit.h>
#include <InterfaceKit.h>
#include <Layout.h>
#include <GroupLayout.h>
const uint32 MOSTRAR_DIALOGO = 1;
class AplicacionPrueba : public BApplication {
public:
VentanaPrueba* ventana;
AplicacionPrueba() : BApplication("application/x-applicion-prueba"){
ventana = new VentanaPrueba();
ventana->Show();
}
};
class VentanaPrueba : public BWindow{
public:
VentanaPrueba() : BWindow(BRect(100,100,900,700),"Mi ventana", B_TITLED_WINDOW,0){
// iniciar ventana
BGroupLayout* sizer = new BGroupLayout(B_HORIZONTAL);
BView* panel = new BView(Bounds(), NULL, B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE |
B_FRAME_EVENTS | B_DRAW_ON_CHILDREN);
panel->SetViewColor(220, 220, 220);
panel->SetLayout(sizer);
BMessage* msg = new BMessage(MOSTRAR_DIALOGO);
BButton* boton = new BButton("Hola Mundo",msg);
sizer->AddView(boton);
AddChild(panel);
}
bool QuitRequested(){
be_app_messenger.SendMessage(B_QUIT_REQUESTED);
return BWindow::QuitRequested();
}
void MessageReceived(BMessage* msg){
switch(msg->what){
case MOSTRAR_DIALOGO:
BAlert* alert = new BAlert("Hola", "Sabes pulsar el boton, eh?", "Sip");
alert->Go();
break;
default:
BWindow::MessageReceived(msg);
}
}
};
int main(int argc, char** argv)
{
AplicacionPrueba app;
return app.Run();
}