La versión 9.0 de VFP aporta nuevas posibilidades en temas de IntelliSense.
Durante la Conferencia DevEssentials 2004, Toni Feltman comentó y ejemplificó varios casos de la vida real, en los que es posible aplicar IntelliSense en tiempo de ejecución.
IntelliSense para Aplicaciones Autor: Toni M. Feltman (www.f1tech.com) Traducido por Ana María Bisbé York (amby@telefonica.net) Para PortalFox (www.portalfox.com)
SinopsisEn la Conferencia Frankfurt Visual FoxPro DevCon en otoño 2003, ví a Y. Alan Griver demostrando IntelliSense en campos memo por primera vez. Después de esta demostración, comenté con mi esposo que era una característica realmente buena a demostrar; pero que no podía encontrar una buena razón en una aplicación para utilizarla. Mi esposo me comentó la aplicación sobre Fisioterapia en la que nos encontrábamos trabajando, en la que teníamos escrito un módulo para que el Fisioterapeuta guardara anotaciones sobre sus pacientes. En este módulo tuvimos que diseñar IntelliSense, como un motor que les permitirá utilizar notación abreviada para llenar campos memo. Se hizo la luz. Tan pronto como pude tener en mis manos una versión de Visual FoxPro 9.0, tuve que jugar con esta característica y ver cuál era el impacto que tendría en esta aplicación. No encontré solamente que el actual motor de IntelliSense es muy útil en tiempo de ejecución, sino que mientras lo iba utilizando, mis ojos se abrían al ver otras vías en que yo podría enriquecer la interfaz de usuario utilizando IntelliSense como característica en áreas de la aplicación donde IntelliSense no es soportado de forma predeterminada. Esta característica es muy enriquecedora para el producto y espero que el siguiente ejemplo les demuestre porqué. Resumen de IntelliSense Comenzaré por ver algunas de las bases de IntelliSense para que podamos utilizar luego su terminología. Autocorregir (AutoCorrect) y Texto de Información rápida (Quick Info Text)Lo siguiente es un ejemplo de AutoCorrect. La mayor parte de los desarrolladores le llaman Autocompletar (AutoComplete). Yo prefiero llamarle AutoCorrect por dos razones: - Es el término que reconocen los usuarios finales porque la función que realiza es similar a AutoCorrect en Microsoft Office (en inglés)
- Existe un nuevo cuadro de texto AutoComplete en Visual FoxPro 9.0 y no quiero que los usuarios confundan este AutoCorrect con el cuadro de texto AutoComplete.
 Figura 1 – Escribir las letras MC en el editor de programas.
 Figura 2 – Luego de presionar la barra espaciadora, MC se expande a MODIFY COMMAND.
Ocurre algo más al presionar la barra espaciadora. Una pequeña ventana "ToolTip" muestra la sintaxis para MODIFY COMMAND. Esta ventana se llama Texto de información rápida (Quick Info Text). Información rápida – Lista (y Texto)A veces, al escribir un comando en la ventana Comandos o el editor de programas se presenta una lista de opciones como en el ejemplo siguiente.  Figura 3 – Lista y Texto de Información rápida
Estas listas se denominan Listas de información rápida. La lista ayuda a crear los comandos adecuadamente. En la medida en que me mueva por la lista, un Texto de información rápida puede acompañar el elemento seleccionado, para brindar detalles adicionales. Scripts (se les puede llamar Plantillas - Templates)El ejemplo siguiente lo que yo llamo plantilla (que también he oído llamar script). Básicamente, se escribe una palabra y cuando se presiona la barra espaciadora, la palabra es reemplazada por una o más líneas de código.  Figura 4 – Escribir DOCASE en el editor de programas.
 Figura 5 – Cuando se presiona la barra espaciadora, la palabra es remplazada por una o más líneas de código.
IntelliSense en tiempo de ejecución Los elementos de Intellisense no son diferentes que en las versiones anteriores de Visual FoxPro. Sin embargo, si observa la figura 6 debajo, verá que las mismas posibilidades existen ahora para campos memo, incluso en el editor de programa en tiempo de ejecución.  Figura 6 – IntelliSense en un campo memo.
Configuración Antes de poder utilizar IntelliSense en campos memo en tiempo de ejecución, se debe marcar la opción Colorear Sintaxis (Syntax Coloring) en el campo memo. Para marcar la opción Colorear Sintaxis, debe estar desmarcada la opción Ajuste automático de líneas (Word Wrap). La figura 7 muestra el cuadro de diálogo Modificar propiedades (Edit Properties Dialog) para campos memo.  Figura 7 – Propiedades campo Memo
Las propiedades del editor se guardan en el archivo FoxUser. Es buena idea lanzar la aplicación con un archivo FoxUser que ya tenga marcada la opción Syntax coloring como predeterminada para los campos memo. Para hacer esto, cree un nuevo Archivo de recursos. Esto se puede hacer a través del Panel Administrador de Entorno (Environment Manager pane) del Administrador del panel de Tareas (Task Pane Manager). Después de crear un nuevo Archivo de recursos, ejecute el siguiente código:
create cursor junk (mNotes m)
modi memo mnotes
Con la ventana de edición del campo memo abierta, haga Clic derecho y seleccione Propiedades (properties). En la ventana Modificar propiedades (Edit Properties) haga lo siguiente: - Desmarque Ajuste automático de líneas (Word Wrap).
- Seleccione Colorear Sintaxis (Syntax Coloring).
- Seleccione Guardar preferencias (Save Preference).
- Seleccione Aplicar a los archivos de tipo memo (Turn Apply to Memos). (Esto garantizará que esta configuración se mostrará como predeterminada para los campos memo que se abran a partir de ese momento.)
Otra herramienta de configuración es la propiedad EditorOption del objeto _VFP. Esta propiedad contiene una combinación de letras que seleccionan o no seleccionan varias opciones de Intellisense. El valor predeterminado para esta propiedad es "LQKT". La tabla 1 muestra la lista con los valores posibles. | Carácter | Significado | | k | Un solo clic del ratón estará seguido por un hiperenlace (hyperlink). | | K | Ctrl+Clic debe ser utilizado para seguir un hiperenlace en el editor. | | L | La lista de miembros se muestra automáticamente cuando es apropiado. | | l | La lista de miembros debe ser invocada manualmente utilizando CTRL+J (List Members en el menú Edit.) | | Q | Es mostrada automáticamente información rápida (Quick Info) cuando es apropiado. | | q | La información rápida debe ser invocada manualmente utilizando CTRL+I (Quick Info en el menú Edit.) | | T | Cuando aparece, se muestran, los consejos (tips), para los elementos de las listas y listas de información rápida. | | W | Cuando aparece, al utilizar arrastrar y soltar puede ser soltada una palabra en un lugar donde haya un espacio (entre dos palabras). |
Tabla 1 - Valores de _VFP.EditorOptions. Nota: Algunas de estas opciones no estarán disponibles en tiempo de ejecución y otras dependerán de la configuración del editor, tales como Ajuste automático de líneas y Colorear sintaxis. Finalmente, el nivel de Intellisense de la aplicación será muy diferente del nivel de IntelliSense del desarrollador. Además, la aplicación debe utilizar una tabla de datos IntelliSense personalizada. La tabla Intellisense predeterminada puede ser encontrada en la variable de memoria del sistema _FOXCODE. Una vez que se conoce, la estructura de esta tabla puede ser copiada en una carpeta de datos de la aplicación utilizando el comando COPY STRUCTURE TO. En tiempo de ejecución, establecer la variable de memoria del sistema _FOXCODE al nombre y localización de la tabla específica de la aplicación. Otro aspecto a definir es, si cada usuario tendrá o no, una tabla específica para IntelliSense. Esto dependerá de la funcionalidad de la aplicación. Un usuario específico podría copiar / actualizar esta tabla desde una localización de red en dependencia de sus necesidades. EjemplosEl objetivo principal de esta sesión es mostrar ejemplos de la vida real de cómo IntelliSense puede ser útil en tiempo de ejecución. El resto de los textos de ejemplos pueden incluirse en aplicaciones Visual FoxPro para ayudar en la entrada de datos en campos memo. Sabemos que la mayor ayuda que se puede dar al usuario de la aplicación, es la menor cantidad de errores en la entrada de datos. Estos ejemplos no cubren en detalle todas las características de IntelliSense, son utilizados solamente en los ejemplos. Puede leer artículos anteriores y los papeles blancos (white papers) para ganar en conocimiento sobre el motor interno de IntelliSense. Ejemplo #1 – AutoCorrección (AutoCorrect)Como mencioné anteriormente, le llamo AutoCorrect debido a que es cómo el usuario final puede entender, ya que hace lo mismo que el Microsoft Office AutoCorrect. Los desarrolladores lo llaman AutoComplete debido a que es una notación abreviada (shortcut notation) para comandos comunes de programación. Vimos un ejemplo de AutoCorrect cuando las letras MC se expandieron a MODIFY COMMAND. Los usuarios finales pueden encontrarlo muy útil para muchas notaciones abreviadas. Las iniciales (para personas y compañías) son comúnmente utilizadas para este tipo de AutoCorrect. Los datos necesarios para este tipo de IntelliSense son muy simples. Sólo se necesitan tres campos en la tabla IntelliSense para que funcione adecuadamente. | Campo | Propósito | Valor/Ejemplo | | Type | Indica el tipo de dato para el motor IntelliSense. | U | | Abbrev | Valor escrito. | TMF | | Expanded | Valor expandido después que se presiona la tecla espaciadora. | Toni M. Feltman |
Tabla 2 – Campos necesarios en la tabla IntelliSense Utilizar IntelliSense en tiempo de ejecución es bueno; pero, por supuesto el usuario querrá tener una vía para personalizarlo. El formulario siguiente es similar al formulario AutoCorrect de Microsoft Office en el que se permite al usuario agregar, eliminar y modificar las entradas.  Figura 8 – Formulario de entrada de AutoCorrect para una aplicación (AutoCorrect.scx).
Este formulario (incluido en los ejemplos) proporciona una interfaz sencilla a los tres campos que la tabla IntelliSense necesita para cumplir esta funcionalidad. Cuando se agrega una nueva entrada a la tabla IntelliSense, se ejecuta el siguiente código:
LOCAL ;
lcAbbrev AS Character, ;
lcExpanded AS Character
WITH This
lcAbbrev = .txtReplace.Value
lcExpanded = .txtWith.Value
ENDWITH
INSERT INTO AppFoxCode ;
(Type, Abbrev, Expanded, Case, Save) ;
VALUES ;
("U", lcAbbrev, lcExpanded, "M", .T.)
Ejemplo #2 – Listas personalizadas (Estáticas)Vimos un ejemplo utilizando los comandos SET. Después de escribir SET + barra espaciadora, se muestra una lista para que el usuario pueda escoger entre todos los comandos SET predefinidos. Este mismo tipo de lista puede ser útil en la evaluación donde las personas tienen una lista finita de valores que pueden seleccionar. Las figuras 9 y 10 a continuación, muestran esto en acción.  Figura 9 – Escribir la abreviatura Perf
 Figura 10 – Texto expandido y Lista de información rápida (Quick InfoList)
Esto es fácil de establecer si sabemos cómo leer la tabla FoxCode existente. El registro del comando SET en la tabla FoxCode tiene Type = "C" indicando que es un comando. Para nuestros propósitos, podemos utilizar TYPE = C incluso cuando nuestros elementos no sean comandos. Los campos Abbrev y Expanded tienen el mismo propósito que antes. En el campo Abbrev está lo que escribe el usuario y en el campo Expanded con lo que reemplaza el contenido del campo Abbrev. Además de los campos Type, Abbrev y Expanded, en este ejemplo se utilizan otros dos campos. El campo Data (memo) contiene la lista (hard coded list) de los posibles valores. El campo Cmd guarda el script a ejecutar, toma la información del campo Data y crea una lista a partir de este. Para el comando SET en la tabla IntelliSense predeterminada, el campo Cmd apunta a un registro script (Type = "S") nombrado cmdhandler (en el campo Abbrev). Después de una pequeña comprobación, determiné que el mismo registro script podría ser utilizado para manipular esta lista en tiempo de ejecución. Por tanto, utilicé SCATTER MEMVAR MEMO y GATHER MEMVAR MEMO para copiar los datos desde el registro cmdhandler script de la tabla original de IntelliSense a la tabla específica de la aplicación. Igual que en el primer ejemplo, supongo que el usuario final puede desear configurar la lista estática. Por ello, tomo el formulario AutoCorrect Form y lo expando, incluyendo un botón para crear / modificar los elementos de la lista.  Figura 11 – Formulario de entrada para la lista estática (CustomList.scx).
 Figura 12 – Ventana existente para la lista estática
Al agregar una nueva entrada, se ejecuta el siguiente código:
LOCAL ;
lcAbbrev AS Character, ;
lcExpanded AS Character
WITH This
lcAbbrev = .txtReplace.Value
lcExpanded = .txtWith.Value
ENDWITH
INSERT INTO AppFoxCode ;
(Type, Abbrev, Expanded, cmd, Case, Save) ;
VALUES ;
("C", lcAbbrev, lcExpanded, [{cmdhandler}],"M", .T.)
El botón Edit List simplemente abre el campo memo Data para la modificación directa. Ejemplo #3 – Listas personalizadas (Dinámicas desde una tabla)La lista con código estático, está bien. ¿Qué pasa si desea crear una lista basada en una tabla? Podemos expandir el ejemplo 2 y crear una entrada en IntelliSense que pueda crear una lista dinámica. Las figuras 13 y 14 muestran una lista dinámica basada en datos en una tabla que guarda las partes del cuerpo.  Figura 13 – Escriba BAE y presione la barra espaciadora.
 Figura 14 – El texto es expandido y la lista se llena basada en los datos de la tabla que contiene las partes del cuerpo.
Para crear la lista dinámica, existen piezas adicionales necesarias. - Al agregar código de programa para entradas de IntelliSense, un objeto (oFoxCode) debe ser pasado y aceptado por el código de programa. Sin embargo, la primera línea de código, debe ser LPARAMETERS oFoxCode o algo similar.
- El objeto oFoxCode object tiene una propiedad llamada ValueType que determina que debe hacer el motor con el dato devuelvo. La tabla 3 lista los valores posibles según se aplican en esta sesión.
| Valor de la propiedad | Propósito | | V | Valor – El retorno reemplaza o agrega a los tipos del texto original. | | L | Muestra una lista de información rápida. | | T | Muestra un consejo (tip). |
Tabla 3 – Valores de la propiedad ValueType. <ol start="3">Cuando se necesita una lista de información rápida, hay una matriz de propiedades para guardar la lista de elementos. La primera columna de esta matriz es la lista de elementos. La segunda columna es opcional y guarda el tip para el elemento. Entonces, el resultado final, es que necesitamos dos nuevos registros en la tabla IntelliSense. El primer registro define la notación abreviada. En este registro, el campo cmd referenciará un registro script llamado ListBuilder. El código de programa en el campo Data del registro ListBuilder es muy sencillo. Igual que el cmdhander script, decide utilizar el campo Data en el registro original para guardar algún metadata. En mi ejemplo, he guardado cuatro piezas de información en el campo data: - Campo List
- Campo Tip
- Tabla
- Campo Sort Order
El siguiente código está en el registro script (type = "S" y abbrev = "listbuilder") y lee la información del registro IntelliSense original y lo utilice para generar una instrucción select adecuada. La propiedad ValueType para el objeto FoxCode se establece a "L" de tal forma que la lista sea mostrada.
LPARAMETERS ;
toFoxCode
WITH toFoxCode
LOCAL ;
lnLines AS Integer, ;
laLines[1], ;
laList[1, 2], ;
lcCommand AS Character
IF EMPTY(.Data)
.ValueType = "V"
RETURN .UserTyped
ENDIF
lnLines = ALINES(laLines, .Data)
IF lnLines <> 4
.ValueType = "V"
RETURN .UserTyped
ENDIF
.ValueType = "L" && List
lcCommand = [SELECT ] + ;
laLines[1] + [, ] + laLines[2] + ;
[ FROM ] + laLines[3] + ;
[ ORDER BY ] + laLines[4] + ;
[ INTO ARRAY laList]
&lcCommand
DIMENSION .Items[ALEN(laList,1), ALEN(laList, 2)]
ACOPY(laList, .Items)
RETURN ALLTRIM(.Expanded)
ENDWITH
Nota: En este ejemplo, la tabla utilizada para la lista debe estar en la ruta de la aplicación. Nuevamente se necesita un formulario en tiempo de ejecución. El original AutoCorrect se utiliza nuevamente como clase padre. Se agregó un botón para configurar la lista (configure list) para llenar el campo memo con la información apropiada.  Figura 15 – Formulario para la entrada de datos en la lista en tiempo de ejecución (DynamicList.scx)
 Figura16 – Formulario para configurar la lista (List Configuration) (ConfigureList.scx)
Cuando se agrega una nueva entrada, se ejecuta el siguiente código:
LOCAL ;
lcAbbrev AS Character, ;
lcExpanded AS Character
WITH This
lcAbbrev = .txtReplace.Value
lcExpanded = .txtWith.Value
ENDWITH
INSERT INTO AppFoxCode ;
(Type, Abbrev, Expanded, cmd, Case, Save) ;
VALUES ;
("U", lcAbbrev, lcExpanded, [{listbuilder}],"M", .T.)
El botón Configure List simplemente abre el formulario ConfigureList para seleccionar el dato necesario para generar dinámicamente la lista. Esta información es escrita luego en el campo memo en el nuevo registro agregado. Ejemplo #4 – PlantillasFinalmente, el último ejemplo es para las plantillas. En este escenario, una plantilla está estructurada de una abreviatura que se desdobla en varias líneas de texto. En el texto, pueden existir campos text merge. Estos campos son evaluados cuando la abreviatura es utilizada y el campo text merge es reemplazado por el dato actual. Este tipo de IntelliSense es mucho más sencillo de configurar de lo que se pueda imaginar. Para comenzar, veamos los registros que necesita la tabla IntelliSense que contienen la abreviatura y el texto expandido. A continuación, un ejemplo de mi aplicación de Fisioterapia. 
 Figura 17 – IntelliSense Script de Evaluación inicial.
Observe los delimitadores estándar del Text Merge en el texto memo. Estos serán evaluados en tiempo de ejecución y el dato actual será escrito en el campo memo tan largo como sea posible. El código en el registro script de la plantilla es también sorprendentemente bastante sencillo.
LPARAMETERS ;
toFoxCode
WITH toFoxCode
.ValueType = "V"
IF EMPTY(.Data)
RETURN .UserTyped
ELSE
RETURN TEXTMERGE(.Data)
ENDIF
ENDWITH
No tengo un formulario en tiempo de ejecución para este ejemplo y probablemente sea bastante complicado hacerlo durante una sesión. Sin embargo, la figura 18 muestra lo que puede hacer IEVal en tiempo de ejecución.  Figura 18– IEval utilizado en tiempo de ejecución.
ConclusiónMe gustaría ver IntelliSense disponible en controles cuadro de texto y de edición (textbox y editbox). Estos controles tienen más eventos que pueden ser utilizados para personalizar este comportamiento. En cualquier caso, esta es una magnífica cualidad que ya puedo utilizar. Además, tengo ahora nuevas ideas para la personalización de mis clases textbox y editbox para agregar IntelliSense como cualidad que ayude en la entrada de datos. Archivos de ejemplos para descargar.
|