NSTableView y NSOutlineView

NSTableView

En Gorm los objetos NSTableView se agregan desde la paleta Containers:

Tabla

Dando un clic sobre dicha tabla, el Inspector nos permite configurar la información relativa al objeto NSScrollView que contiene al objeto NSTableView. Las principales características a configurar son el color de fondo, el tipo de borde y las barras de desplazamiento (vertical y/o horizontal) presentes en la tabla:

Inspector para una tabla

Una vez seleccionada la tabla y dando un doble clic sobre ella, el Inspector nos permite configurar aspectos del objeto NSTableVIew. La sección Selection nos permite configurar si se permiten múltiples selecciones (de reglones), si se permite una selección vacía (ningún reglón seleccionado) y si se permite la selección de columnas (dando un clic sobre la cabecera). Las siguientes secciones Scrollers y Border, configuran el aspecto del NSScrollView que contiene la tabla (la misma configuración que se realiza con el Inspector anterior). La sección Background configura el color del fondo de la tabla (el color de fondo de las columnas, no del objeto NSScrollView que contiene a la tabla y que se configura en el Inspector anterior). En la sección Dimensions se configura el alto del reglón (en pixeles) y el número de columnas. La sección Options nos permite configurar si la tabla dibujara una rejilla, si permitirá redimensionar las columnas y si permite reordenar estas (cambiar el orden de las columnas arrastrándolas con el mouse). Y por último podemos establecer un tag para la tabla:

Inspector para la tabla

Una vez seleccionada la tabla, dando doble clic sobre la cabecera de una columna podemos configurar las características de dicha columna. Las secciones Title y Contents configuran la alineación del titulo y del contenido de las columnas, respectivamente. La sección Options configura si la columna se puede redimensionar (para ello la tabla debe marcarse como redimensionable en el Inspector anterior) y si la columna es editable. La sección Column Title es el título de la columna y la sección Identifier es el identificador de la misma. Por último la tabla Data Cell nos permite elegir el tipo de objeto de contendrá la columna, el cual se establece con el botón Set. El valor por defecto es NSTextFieldCell.

Inspector de columna

En general los objetos NSTableVIew son utilizados en aplicaciones de bases de datos y la conexión en ese caso es sencilla. Sin embargo, en otras aplicaciones pueden utilizarse para manejar información no relacionada con bases de datos, y en esos casos hay que manejar la tabla mediante código. Aquí veremos un ejemplo sencillo que muestra como hacer esto.

Lo primero que debe hacerse es establecer el objeto que servirá de fuente de datos. Es decir, el objeto donde la tabla buscara los datos que debe desplegar. Podemos establecer este objeto de la siguiente forma:

[tabla setDataSource: objeto];

o en la interfaz gráfica de nuestra aplicación con Gorm (creando una conexión entre la tabla y nuestro objeto, y luego conectando el Outlet dataSource). Y cada vez que queramos actualizar la tabla:

[tabla reloadData];

Ahora debemos implementar (básicamente) tres métodos en el objeto establecido como fuente de datos. Estos métodos deben estar declarados en la interfaz de nuestro objeto. El primero de ellos es:

- (int) numberOfRowsInTableView: (NSTableView*)aTableView

retorna el número de reglones en la tabla. Ya que este número puede cambiar dependiendo de las acciones del usuario, aquí es donde debe controlarse esto. El siguiente método es:

- (id) tableView: (NSTableView*)aTableView objectValueForTableColumn: (NSTableColumn*)aTableColumn row: (int)rowIndex

Este método es el que provee los datos para la tabla. Este método es llamado para cada una de las columnas presentes en la tabla y para cada reglón en cada una de estas columnas:. Los parámetros aTableColumn y rowIndex nos permiten devolver el valor correspondiente a cada casilla en la tabla. El parámetro aTableView nos permite identificar la tabla en cuestión (para el caso de que gestionemos varias tablas desde un mismo objeto). Un ejemplo sencillo del código en este método es el siguiente (para cuando únicamente se gestiona una tabla):

Ejemplo de Tabla

El último método es

- (void) tableView: (NSTableView*)aTableView setObjectValue: (id)anObject forTableColumn: (NSTableColumn*)aTableColumn row: (int)rowIndex

este método nos permite almacenar el dato (el parámetro anObject) que el usuario ingresa en determinada celda (parámetros aTableColumn y rowIndex) de la tabla (parámetro aTableView). Un ejemplo sencillo es (para cuando únicamente se gestiona una tabla) almacenar la información en un objeto NSMutableDictionary que almacena objetos NSMutableArray (uno para cada columna):

Ejemplo de tabla

Para más información consultese la documentación de la clase NSTableView.


NSOutlineView

La siguiente imagen muestra un objeto NSOutlineView usado en Gorm para mostrar la jerarquía de las clases:

OutlineView

En Gorm los objetos NSOutlineView se agregan desde la paleta Containers:

NSOutlineView

Estos objetos nos permiten organizar items en distintas categorías. Las distintas categorías pueden ocultarse o hacerse visibles dando un clic en la flecha correspondiente. Cuando un item esta contraído la flecha apunta hacia la derecha, mientras que al estar expandido apunta hacia abajo (estas flechas pueden ser remplazadas por otras imágenes como en el ejemplo de Gorm mostrado mas arriba). Dando un clic sobre este, el Inspector nos permite configurar el objeto NSScrollView que contiene al NSOutlineVIew. Las principales características a configurar son el color de fondo, el tipo de borde y las barras de desplazamiento (vertical y/o horizontal) presentes:

NSOutlineVIew Inspector

Una vez seleccionado el objeto OutlineView, dando doble clic sobre este podemos configurar el objeto NSOutliveView propiamente dicho. La sección Selection nos permite configurar si se permiten múltiples selecciones (de reglones), si se permite una selección vacía (ningún reglón seleccionado) y si se permite la selección de columnas (dando un clic sobre la cabecera). Las siguientes secciones Scrollers y Border, configuran el aspecto del NSScrollView que contiene la tabla (la misma configuración que se realiza con el Inspector anterior). La sección Background configura el color del fondo de la tabla (el color de fondo de las columnas, no del objeto NSScrollView que contiene a la tabla y que se configura en el Inspector anterior). En la sección Dimensions se configura el alto del reglón (en pixeles) y el número de columnas. La sección Options nos permite configurar si la tabla dibujara una rejilla, si permitirá redimensionar las columnas y si permite reordenar estas (cambiar el orden de las columnas arrastrándolas con el mouse). Y por último podemos establecer un tag para el OutlineView:

NSOutliveView Inspector

Una vez seleccionado el OutlineView, dando doble clic sobre la cabecera de una columna podemos configurar las características de dicha columna. Las secciones Title y Contents configuran la alineación del titulo y del contenido de las columnas, respectivamente. La sección Options configura si la columna se puede redimensionar (para ello el OutlineView debe marcarse como redimensionable en el Inspector anterior) y si la columna es editable. La sección Column Title es el título de la columna y la sección Identifier es el identificador de la misma. Por último la tabla Data Cell nos permite elegir el tipo de objeto de contendrá la columna, el cual se establece con el botón Set. El valor por defecto es NSTextFieldCell.

NSOutlineView Inspector

Veremos aquí un sencillo ejemplo de como se maneja uno de estos objetos.  Concretamente manejaremos un OutlineView con una sola columna como se muestra a continuación. En la imagen izquierda se muestra el OutlineView con sus items no desplegados y a la derecha con los items desplegados.

OutlineView de ejemplo

Primero debemos establecer un objeto dataSource para nuestro NSOutlineView. Mediante código:

[outlineView setDataSource: objeto];

o en la interfaz gráfica de nuestra aplicación con Gorm (creando una conexión entre el OutlineView y nuestro objeto, y luego conectando el Outlet dataSource). Este objeto debe implementar, por lo menos, cinco métodos. Estos métodos deben estar declarados en la interfaz de nuestro objeto. El primero de ellos es:

- (int) outlineView: (NSOutlineView*)outlineView numberOfChildrenOfItem: (id)item;

Este método le indica al NSOutlineView cuantos hijos (subitems) tiene cada uno de los items, el parámetro item, para determinado OutlineView, el parámetro outlineView (este parámetro es útil cuando se gestiona más de un OutlineView en el mismo objeto). En nuestro ejemplo, el item Sup tiene dos subitems (Uno y Dos), y cada uno de estos tiene a su vez 3 y 5 subitems respectivamente. El item Alfa tiene 3 subitems. Por lo tanto el código es el siguiente (solamente se maneja un OutlineView, por lo que no se utiliza el parámetro outlineView):

NSOutlineView ejemplo

Examinemos este código. Si item es igual a nil , es porque el OutlineView esta preguntando por la cantidad de items superiores (es decir los items padre, que no son hijos de ningún otro item). En nuestro caso hay dos de estos items, Sup y Alfa. por lo tanto se retorna 2. Cuando item es igual a Sup, se retorna 2, ya que Sup tiene dos hijos, Uno y Dos. Cuando item es igual a Uno, se retorna 3, ya que Uno tiene 3 hijos, 1.1, 1.2 y 1.3. Y de forma similar para los demás items que tienen hijos. Por último, para cualquier otro item que no tiene hijos se retorna 0.

El siguiente método a implementar es:

- (id) outlineView: (NSOutlineView*)outlineView child: (int)index ofItem: (id)item;

Este método devuelve el item (para ser más preciso el identificador del item) que se mostrara en un determinado reglón de la columna (el parámetro index) para cierto item (el parámetro item). Nuevamente, el parámetro outlineView es útil cuando se gestiona más de un OutlineView en el mismo objeto. Este método es el encargado de manejar la jerarquía de nuestra información. Para nuestro ejemplo, el código en este método es:

Código

Una breve explicación muestra como funciona esto. El OutlineView primero consulta cuantos items superiores hay (los que no tienen padre, información proporcionada por el método visto anteriormente). En nuestro ejemplo hay dos items, entonces procede a consultar este método, preguntando cual item superior (item == nil) va en el indice 0. En nuestro ejemplo (el código en la imagen superior) se devuelve Sup. Seguidamente el OutletView pregunta cuantos hijos tiene el item Sup, en nuestro ejemplo son 2. Así procede a preguntar que item, hijo del item Sup, corresponde al indice 0. En nuestro ejemplo se trata del item 1.1. Como este item no tiene hijos, se procede a preguntar que item, hijo del item Sup, corresponde al indice 1. En nuestro ejemplo se trata del item 1.2.  Como este item no tiene hijos, se procede a preguntar que item va en el indice 3, en nuestro ejemplo 1.3. Como este item no tiene hijos, se precede a preguntar cuantos hijos tiene el item Uno… y así sucesivamente.

El tercer método a implementar es:

- (BOOL) outlineView: (NSOutlineView*)outlineView isItemExpandable: (id)item;

Este método le indica al OutlineView que items, parámetro item,  son desplegables (tienen hijos). Nuevamente, el parámetro outlineView es útil cuando se gestiona más de un OutlineView en el mismo objeto. En nuestro ejemplo el código sería el siguiente:

OutlineView ejemplo

El cuarto método a implementar es:

- (id) outlineView: (NSOutlineView*)outlineView objectValueForTableColumn: (NSTableColumn*)tableColumn byItem: (id)item;

Este método devuelve el objeto que se desplegara en el item indicado, el parámetro item. Como mencione anteriormente, los textos Sup, Alfa, Uno, … son sólo identificadores de nuestros items. Sin embargo, es posible usar estos mismo identificadores como los objetos que se desplegaran en nuestros items. Este es el caso en nuestro ejemplo, por lo que este método queda de la forma:

OutlineView código

Aunque este método es más complicado para el caso cuando el OutlineView tiene más de una columna. Ya que debe devolver el objeto que contendrá cada una de las columnas dependiendo del item indicado. Por ejemplo algo como:

OutlineView código

Por razones de claridad, y dado que era un OutlineView con pocos datos, he usado sentencias if .. else … para manejar la información. Sin embargo, en un OutlineView que maneje más información, sería más apropiado usar otros métodos. Por ejemplo a través de diccionarios y arrays.

Para el caso en que queramos saber que reglón esta seleccionado (para llevar a cabo alguna acción), debemos establecer un objeto delegate. Este puede  establecerse mediante código (puede ser el mismo objeto que hace de dataSource):

[outlineView setDelegate: objeto];

o en la interfaz gráfica de nuestra aplicación con Gorm (creando una conexión entre el OutlineView y nuestro objeto, y luego conectando el Outlet delegate). El método a implementar es:

- (void) outlineViewSelectionDidChange: (NSNotification*)aNotification;

Aquí podemos saber que reglón esta seleccionado mediante el código:

id item = [[aNotification object] itemAtRow: [[aNotification object] selectedRow]];

Para más información consultese la documentación de la clase NSOutlineView.