EJEMPLOS DE MVC
Muy bien si has entendido que es eso de Modelo-Vista-Controlador tienes mucho avanzado, pero eso ¿Cómo se aplica a un programa en Cocoa?Para ello me preparado un pequeño programa que simplemente mostrará unas rectas por pantalla, una recta cada vez según las indicaciones del usuario. El esquema es el siguiente:
Vamos a crear tres clases, cada una de ellas nos representará a un elemento del trío MVC. Y esta vez el trabajo importante lo haremos con InterfaceBuilder.

1. Creación de las clases
Una vez creado el proyecto (¿hace falta explicar cómo?)se accede al programa Interface Builder. En este programa creamos tres clases (dentro de la pestaña classes de la ventana MainMenu.nib). MVCControl y MVCRecta que serán subclases de NSObject y MVCVista que será subclase de NSView. Recordad del artículo anterior que necesitábamos una subclase de NSView para poder dibujar.Una vez creada hacer falta añadir una instancia de las dos primeras a nuestro programa (recordar que se hace seleccionando la clase y luego con el menú Classes | Instantiate…).
Aquí estaba una de mis mayores preocupaciones: ¿Cuando se crea el objeto de la clase MVCRecta o MVCControl? No veía por ninguna parte un método alloc, ni init, ni nada por el estilo. Lo que pasa es que el sistema nos oculta todo el montón de trabajo que hace cuando se inicia un programa. Es en el momento de iniciar el programa cuando se crean las instancias del programa, y es por este sistema visual de Interface Builder que nosotros le hemos pedido que las cree.

2. La ventana de la aplicación
Siguiendo con Interface Builder creamos la ventana del programa:
Para añadir la clase que hemos creado MVCVista, hace falta añadir una clase personalizada (custom class) a la ventana y con el inspector (menú Tools | Show Inspector, escoger la pestaña Custom Class) indicar que será la clase que hemos creado nosotros.Vemos que he añadido dos botones. Estos serán los que permitirán el dibujo de las rectas. Desde luego es un método muy tosco y realmente no estarán dentro de la clase MVCVista, pero en realidad la autentica Vista de la aplicación es la ventana, y tanto MVCVista cómo los botones son elementos de dentro de la vista.

3. ¡Conexiones!
Lo realmente importante viene aquí: cómo relacionamos los objetos que trabajarán en nuestro programa.Siguiendo el esquema lo primero es hacer que el controlador pueda acceder al modelo y a la vista. Para ello seleccionamos la clase MVCControl en la pestaña de instancias. Nos aseguramos de tener el inspector abierto en la pestaña de conexiones (connections) y añadimos dos salidas (outlets) de nombre dibujo y laRecta. Una vez creadas, las seleccionamos y las conectamos (Control y arrastrar) a la instancia de la clase que nos interesa.
Luego nos aseguramos que el controlador (MVCControl) pueda recibir los mensajes del usuario a través de la vista. Para ellos tenemos que crear dos acciones (actions) llamadas dibujarRecta: y dibujarOtra: en la misma pestaña que las salidas, pero en el apartado actions. En este caso la conexión la realizamos desde los botones a la instancia de la clase MVCControl.
Cómo he dicho antes este método de utilizar dos acciones diferentes es un poco chapuza, pero para esta explicación nos valdrá.


4. Código
Todavía queda algo de trabajo en Interface Builder: crear los ficheros de las clases que hemos definido. Recordad que simplemente basta seleccionar la clase en la pestaña de clases y con el menú Classes | Create Files, crear los ficheros, asegurando que los incluimos en el proyecto.
4.1. Modelo
En el modelo el fichero de interficie es:
/* MVCRecta */ #import <Cocoa/Cocoa.h> @interface MVCRecta : NSObject { NSPoint inicio; NSPoint final; } -(void) init; -(void) setInicio: (NSPoint)puntoInicio; -(void) setFinal: (NSPoint)puntoFinal; -(NSPoint) puntoInicial; -(NSPoint) puntoFinal; @end
Cada objeto de esta clase guardará dos datos inicio y fin de recta (siempre es bueno ser originales ;) ). Además habrá que escribir cinco métodos. Un iniciador y los correspondientes a establecer y mostrar los datos del objeto.Y el de implementación:
// Implentación de una clase que representa una linea recta #import "MVCRecta.h" @implementation MVCRecta // Sobreescribimos la clase init para comenzar con // una "recta" de un solo punto. -(void) init { inicio = NSMakePoint(0,0); final = NSMakePoint(0,0); [super init]; } // Métodos para establecer los puntos inicial y final -(void) setInicio: (NSPoint)puntoInicio { inicio = puntoInicio; } -(void) setFinal: (NSPoint)puntoFinal { final = puntoFinal; } //Métodos para recuperar los datos de puntos inicial // y final -(NSPoint) puntoInicial{ return inicio; } -(NSPoint) puntoFinal{ return final; } @end
Nada especial, solamente ver cómo se sobrescribe el método init para asegurarnos que el objecto comienza con una “recta” no nula.
4.2. Controlador
En el controlador el fichero de interficie es:
/* MVCControl */ #import <Cocoa/Cocoa.h> @interface MVCControl : NSObject { IBOutlet id dibujo; IBOutlet id laRecta; } - (IBAction)dibujarOtra:(id)sender; - (IBAction)dibujarRecta:(id)sender;@end
Aquí ya hay más cosas. En primer lugar las dos variables que nos marcarán donde estarán las salidas (IBOutlet) y por otro lado los dos métodos que tendremos que escribir en el control para interactuar con el programa (IBAction). No es difícil imaginar que las iniciales IB significan Interface Builder.Y el de implementación:
// Control para dibujar dos rectas en una vista #import "MVCControl.h" #import "MVCRecta.h" #import "MVCVista.h" @implementation MVCControl // Método/Acción para dibujar una de las rectas - (IBAction)dibujarOtra:(id)sender { // Se indican los puntos inicial y final [laRecta setInicio:NSMakePoint(10,20)]; [laRecta setFinal:NSMakePoint(50,200)]; // Una vez definida la recta pide a la vista que // se actualice [dibujo setNeedsDisplay:YES]; } // Método/Acción para dibujar una de las rectas - (IBAction)dibujarRecta:(id)sender { // Se indican los puntos inicial y final [laRecta setInicio:NSMakePoint(30,90)]; [laRecta setFinal:NSMakePoint(150,300)]; // Una vez definida la recta pide a la vista que // se actualice [dibujo setNeedsDisplay:YES]; } @end
También es bastante sencillo, pero con unos detalles importantes.Cómo tiene que acceder a objetos de las clases MVCVista y MVCRecta hay que incluir la linea de #import correspondiente a cada clase.Hay que recordar las salidas que habíamos definido (laRecta y dibujo) a cada una de ellas se envían mensajes diferentes. A la primera los mensajes necesarios para definir la recta (en este caso totalmente fijada). Y a la segunda la necesidad de actualizar la vista. No tenemos que preocuparnos sobre cómo se dibujará la recta ni enviarla a la vista, la vista se encargará de todo (es que es muy lista).
4.3. Vista
En la modelo el fichero de interficie es:
/* MVCVista */ #import <Cocoa/Cocoa.h> @interface MVCVista : NSView { IBOutlet id laRecta2; } @end
Muy simple, sólo la salida al modelo.Y el código de implementación:
// Clase para representar una recta en una vista// personalizada #import "MVCVista.h" #import "MVCRecta.h" @implementation MVCVista- (id)initWithFrame:(NSRect)frameRect { if ((self = [super initWithFrame:frameRect]) != nil) { // Add initialization code here } return self; } - (void)drawRect:(NSRect)rect { //Dibujar el fondo de color blanco [[NSColor whiteColor] set]; [NSBezierPath fillRect:rect]; // Recoger los puntos de la recta y dibujar en color negro NSPoint inicioRecta = [laRecta2 puntoInicial]; NSPoint finRecta = [laRecta2 puntoFinal]; [[NSColor blackColor] set]; [NSBezierPath strokeLineFromPoint:inicioRecta toPoint:finRecta]; } @end
Támpoco nada de especial: los #import necesarios para tratar con la clase MVCRecta, la inicialización de la clase (que no se ha tocado para nada) y el método drawRect: para hacer el dibujo de la recta.Si vemos todo el código veremos muchas lineas para decir obviedades. Claro que es programa se podría haber solucionado con un sistema más sencillo y utilizar aquí el sistema Modelo Vista Controlador es un poco exagerado. Pero entonces la explicación no seria tan clara.
Comentarios
Publicar un comentario