Construyendo una aplicación Cocoa sin Interface Builder

Inmediatamente después de leer el título de la entrada os preguntareis, y ¿por qué no usar el Interface Builder para hacer una aplicación Cocoa?. Realmente el uso de esta herramienta nos ayuda en gran medida a la hora de realizar las interfaces gráficas de nuestro programa. ¿Entonces?.

La razón de esta entrada es que no todo el mundo puede usar esta herramienta, en muchas ocasiones nos olvidamos de que no todos los usuarios de ordenador interactuamos con él de la misma manera, no todos podemos usar los métodos  habituales de entrada, esto es, el habitual teclado y ratón, y para este tipo de usuarios, usar ciertas herramientras puede constituir una barrera de uso muy alta. Como supongo que ya habreis adivinado me estoy refiriendo a personas que como Tyflos, tienen la desgracia de no poder usar su vista.

Desarrollar una aplicación sin Interface Builder es una tarea compleja, pero perfectamente posible, todos los controles y el comportamiento puede ser realizado en código.

Así que pongamonos manos a la obra😉, lanzamos el XCode y debemos crear un proyecto de tipo Cocoa. Este proyecto nos creará el esqueleto de una aplicación Cocoa incluyendo el fichero que habitualmente usamos para editarlo con el Interface Builder, cuyo nombre es MainMenu.xib. Aunque no vayamos a usarlo, es la forma mas comoda de crear la estructura de un proyecto Cocoa, ya que automaticamente se nos incluirán las dependencias con los frameworks necesarios y el código de inicialización de la aplicación. Es posible hacerlo desde un proyecto creado como “vacio” pero tendriamos que añadir los frameworks y este código inicial.

Una vez que tenemos el proyecto creado, nos vamos directamente al fichero “NombreDeLaAplicacion”AppDelegate.m que se nos ha creado. En este fichero tendremos el delegate de la aplicación, este delegate recibirá la llamada del mensaje “applicationDidFinishLaunching:(NSNotification*)”, cuando la aplicación este lista para funcionar.

En esta entrada, vamos a hacer algo muy sencillo pero que sienta las bases para seguir incorporando controles. El objetivo es poner un cuadro de texto, un botón, y una etiqueta para que nos muestre un mensaje. Además, de cara al objetivo de la entrada, la aplicación nos narrará cuando el botón esta seleccionado o el ratón esta encima de él, y también nos dirá cuando cambie el contenido de la etiqueta.

Lo primero que tenemos que hacer es declarar los componentes necesarios  para nuestra aplicación, para ello vamos al fichero .h y declaramos una vista, un botón, y dos campos de texto. Recordemos que las etiquetas son campos de texto. Además tambien declararemos el motor de sintetizador de voz y una función que nos ayudará a calcular la posición de donde pintar el control. Por lo tanto nuestro .h quedará así:

@interface PruebaNOIB2AppDelegate : NSObject <NSApplicationDelegate> {
    NSWindow *window;
	NSView *view;
	NSButton *mybutton;
	NSTextField *mytf, *mylabel;
	NSSpeechSynthesizer *spch;
}

- (NSRect) calculatePosition: (NSView *) referingView
					 xoffset: (int) xoff
					 yoffset: (int) yoff
					   width: (int) wdth
					  heigth: (int) hght;

@property (assign) IBOutlet NSWindow *window;

@end

Como no vamos a usar Interface Builder, debemos inicializar y posicionar dinámicamente todos los controles, para ello empezamos creando la vista:

view = [[NSView alloc] initWithFrame:NSMakeRect(0,
						0,
						[window contentMaxSize].width,
						[window contentMaxSize].height)];

El siguiente paso será crear el botón, y posicionarlo. Además le indicaremos que nosotros somos el Target de su Action, para que cuando se pinche sobre el botón, nos llegue a nosotros el mensaje.

mybutton = [[NSButton alloc] initWithFrame: NSMakeRect(50, 50, 100, 20)];
[mybutton setButtonType:NSToggleButton];
[mybutton setTarget:self];
[mybutton setAction:@selector(onButtonPressed)];

Para acabar con la creación de la interfaz, inicializaremos los botones y los posicionaremos:

mytf = [[NSTextField alloc] initWithFrame:
			[self calculatePosition:mybutton xoffset:10 yoffset:0 width:100 heigth:20]];

mylabel = [[NSTextField alloc] initWithFrame:
		   [self calculatePosition:mytf xoffset:10 yoffset:0 width:100 heigth:20]];
[mylabel setEditable:NO];
[mylabel setSelectable:NO];
[mylabel setDrawsBackground:NO];

Como vemos, utilizamos el método “calculatePosition” para calcular la posición del control dependiendo de la vista que le pasamos como paremtros. Todas las vistas tienen un mensaje llamado “frame” que devuelve un NSRect del que podemos sacar tanto el punto de inicio como el tamaño de la vista. Todos los controles de Cocoa son realmente vistas, de hecho una interfaz es un “arbol” de vistas. Por lo tanto lo que tenemos que hacer es añadir a la vista padre todas las subvistas de nuestros controles.

[view addSubview:mybutton];
[view addSubview:mytf];
[view addSubview:mylabel];

Finalmente le indicamos a la ventana, que la vista principal es la nuestra:

[window setContentView:view];

Antes de terminar con este método, tenemos que inicializar el motor de habla, e indicar que queremos capturar los eventos de ratón sobre nuestro botón. Esta forma de capturar los eventos bien puede ser una nueva entrada del blog🙂

spch = [[NSSpeechSynthesizer alloc] initWithVoice:nil];
[window setAcceptsMouseMovedEvents:YES];
[mybutton addTrackingRect:[mybutton bounds] owner:self userData:nil assumeInside:NO];

Como vemos, el código es bastante sencillo. Hacer una interfaz grande es muy laborioso, pero no complejo. Para que al pinchar sobre el botón, el texto de la etiqueta cambie, debemos implementar el action del botón. En nuestro caso:

- (void) onButtonPressed
{
	[mylabel setStringValue:[mytf stringValue]];
	[spch startSpeakingString:[NSString stringWithFormat:@"Label Value: %@",[mytf stringValue]]];
}

En este método también vemos el uso sencillo del motor de habla, solo debemos mandarle un mensaje “startSpeakingString:” a nuestro objeto NSSpeechSynthesizer. Finalmente debemos implementar los mensajes que atienden a los eventos de ratón sobre nuestro botón:

- (void) mouseEntered:(NSEvent *) theEvent
{
	[spch startSpeakingString:@"Mouse Entered"];
}

- (void) mouseExited: (NSEvent *) theEvent
{
	[spch startSpeakingString:@"Mouse Exited"];
}

Con todo esto, ejecutamos y la aplicación deberia funcionar sin problemas.

Como decía al inicio de esta entrada, el ejemplo es muy sencillo, pero pone las bases para seguir investigando en como realizar las aplicaciones de esta forma.

4 respuestas a Construyendo una aplicación Cocoa sin Interface Builder

  1. Tyflos dice:

    Hola, un artículo muy interesante y bien explicado. Muchas gracias, desde aquí ya puedo comenzar a desarrollar mis interfaces sin el InterfaceBuilder y controlarlo todo mejor. Además, el ejemplo de la síntesis de voz me viene genial, ya no tengo que buscar por la documentación!🙂

    Muchas gracias, postearé algo en mi blog redireccionando aquí.

    • robjperez dice:

      Gracias por el comentario🙂

      El tema del motor de habla es algo muy interesante, voy a investigar algo mas sobre él e intentaré escribir alguna entrada mas sobre este aspecto.

  2. Artus88 dice:

    Hola, el codigo de la inicializaion de *view donde lo pongo???

    • robjperez dice:

      Hola, lo primero de todo, gracias por el comentario🙂

      Sobre la inicialización de la vista, si te he entendido bien. Puede ocurrir dos cosas, una de ellas es que la vista sea propia tuya. Si es así y has hecho una subclase de NSView, coloca ese código en la sobrecarga el constructor ( no te olvides de llamar al constructor del padre )

      Si por otro lado no has hecho tu propia vista, el código de inicialización lo puedes colocar justo debajo de la propia instanciación.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: