22 de julio de 2005

Personalizar Intellisense

Artículo original: Customizing Intellisense - I
http://weblogs.foxite.com/andykramek/archive/2005/04/03/334.aspx
Autor: Andy Kramek
Traducido por: Ana María Bisbé York

Una de las cuestiones que comienza a inquietar cada vez más es cómo controlar algunas de las facetas más irritantes del motor de Intellisense en VFP. Intellisense se introdujo por primera vez en el mundo del desarrollo de software en el Microsoft Visual Basic 5.0 y se implementó ampliamente como herramienta esencial de productividad en muchos lenguajes de programación. La implementación en VFP, que lo introdujo en su versión 7.0, es la única entre todos que de hecho, tiene código abierto que permite a los desarrolladores personalizar y extender su funcionalidad agregando, a su vez, otras características. Para desarrollar el tema de todas las posibilidades de Intellisense hace falta mucho más que una entrada de blog. Espero que los siguientes artículos sobre la configuración de Intellisense sean de su utilidad.

_VFP.EditorOptions

La funcionalidad básica de Intellisense está controlada por la propiedad EditorOptions del objeto aplicación VFP (al que se accede directamente utilizando la variable de sistema _VFP). El valor predeterminado para esta propiedad es "LQKT" aunque en realidad son implementados cinco aspectos básicos en todas las versiones de Intellisense, y una sexta ha sido agregada en Visual FoxPro 9.0. Ellas son:
  • Hiperenlaces ("K o k"). Determina cómo son activados los enlaces. Al igualarlo a "k" se activarán con un único Clic del ratón; pero si es "k" necesita CTRL+Click para activarlos, esta es la opción predeterminada. Si no se especifica nada, los hiperenlaces se tratan como texto normal en la edición o en la ventana de comandos.
  • Arrastrar y soltar palabras (Word Drag ‘n’ Drop) ("W"). Cuando está habilitado, el texto puede ser arrastrado solamente a la posición inmediatamente siguiente a un espacio. Esto evita que el texto sea insertado (de forma inadvertida) en el texto existente al utilizar arrastrar y soltar en una ventana de edición o de la ventana de comandos. Este comportamiento está inhabilitado de forma predeterminada.
  • Valores de diseño sugeridos (Designer Value Tips) ("T"). Este controla si  los elementos que se muestran en la lista van acompañados de los tips. Se muestran de forma predeterminada y se puede recorrer la lista de miembros.
  • Lista de miembros (List Members) ("L o l"). Este controla si y cuándo, se muestra la lista de miembros del objeto . De forma predeterminada, las listas se muestran automáticamente ("L"). Cuando se establece la minúscula "l" la lista aparece sólo cuando se presiona Ctrl+J ( o al seleccionar "Mostrar miembros" (List Members) del menú Edición (Edit) del menú principal de Visual FoxPro.
  • Información rápida (Quick Info) ("Q o q"). Este controla si y cuando, se muestran los diferentes tipos de Información rápida. De forma predeterminada, se muestran automáticamente ("Q"). Cuando se iguala a minúscula "q" la Información rápida sólo aparece al presionar CTRL+I (o seleccionar "Información rápida" (Quick Info) del menú Edición (Edit) del menú principal de Visual FoxPro.
  • Copiar texto enriquecido Rich Text Copy( "X"). Este parámetro fue introducido en la versión 9.0 de VFP y elimina la funcionalidad, que copia el texto al bloc de notas utilizando texto enriquecido. De forma predeterminada se omite, por tanto todos los textos se copian con formato de texto enriquecido. Esto significa que cuando se pega texto en otra aplicación (por ejemplo, un mensaje de correo o un documento) mantiene la sintaxis coloreada y la configuración que haya tenido en el editor de VFP. Al incluir "X" en la cadena EditorOptions, asegura que el texto se copie como texto plano - esto es útil al producir documentación u otros materiales, que se debe imprimir en blanco y negro.
Lo importante a observar aquí es que existen letras minúsculas para los parámetros Lista de miembros e Información rápida. Si sustituye los valores predeterminados por las minúsculas, no se inhabilita el Intelisense; pero tampoco se muestra automáticamente.

Si le molesta la aparición de la caja amarilla que no deja ver su trabajo al escribir comandos SQL sencillos o Browse, pruebe cambiando "Q" por "q". Esto hace que la información rápida no se muestre automáticamente; pero si la necesita en algún caso, presione Ctrl+I, en cualquier lugar del comando y se mostrará el tooltip inmediatamente. (Vea que si hace esto también inhabilita la lista de comandos/opciones disponibles cuando, por ejemplo escribe SET o USE).

De forma similar, si encuentra molesto ver la lista de propiedades, eventos y métodos de objetos, puede cambiar "L" por "l". Puede continuar ahora mostrando las referencias de objeto por si mismo; pero, si necesita una lista la tendrá disponible si oprime Ctrl+J.

Registros CustomPEMs en FoxCode.dbf

Además de la propiedad EditorOptions existe un registro especial en la tabla FoxCode que guarda la configuración para algunas propiedades adicionales de configuración. Se puede acceder a través de la ficha Advanced del Administrador de Intellisense (IntelliSense Manager) o abriendo directamente FoxCode.DBF y utilizando el comando:

LOCATE FOR TYPE = "Z" AND ABBREV = "CustomPEMs"

La cantidad de propiedades depende de la versión de Visual FoxPro que se está utilizando. En VFP 7.0 existían 6 (una de las cuales nunca estuvo documentada), y se agregaron otras dos en VFP 8. La siguiente tabla muestra la lista de propiedades y describe lo que hacen:

Propiedad Objetivo
lEnableFullSetDisplay
Predeterminado = .T.
Muchos de los comandos SET toman como parte de su sintaxis un modificador "TO". Esta propiedad determina si este "TO" se va a incluir como parte de una extensión del comando en Intellisense. El valor predeterminado es T; pero podemos preferir desactivarlo. La razón es que incluso si escribe el comando completo por si mismo, Intellisense va a agregar "TO", teniendo como consecuencia error en el comando, porque estará escribiendo comandos del tipo SET INDEX TO TO nombre.
lHideScriptErrors
Predeterminado = .F.
De acuerdo al archivo de ayuda esta propiedad "Elimina la salida de los errores de script de Intellisense". El valor predeterminado es Falso. De hecho, esto es otro parámetro que sólo se aplica a los script que utilizan una instancia local de la clase FoxCodeScript. Esta clase define el diseño de un error de usuario y si está habilitado mostrar o no el error. Si ocurre un error de cualquier otro tipo de script va a tener, o el mensaje de error estándar apropiado (cuando es aplicable), o un diálogo de error con el texto "Fallo en el FoxCode Script"  ("FoxCode Script Failure"), independientemente de la configuración de esta propiedad.
lKeyWordCapitalization
Predeterminado = .T.
Controla la auto expansión y capitalización de las partes subordinadas de los comandos. La configuración predeterminada es .T. Se utiliza en el método ReplaceKeyWord() de foxcode.prg. Observe que esto sólo afecta a la capitalización cuando se escribe el comando íntegramente (por ejemplo CLEAR ALL). Los comandos auto insertados se capitalizan de acuerdo a sus reglas individuales.
lPropertyValueEditors
Predeterminado = .T.
De acuerdo al archivo de ayuda esta propiedad "Activa scripts que desencadenen editores de valores para determinadas propiedades". El valor predeterminado es .T. De hecho, esta propiedad determina si el script definido en foxcode.dbf se ejecute para registros con Type = "P". No afecta ninguno de la lista de valores estándar que se definieron para propiedades que se continúan mostrando independientemente de este parámetro.
lExpandCOperators
Predeterminado = .T.
Activa la autoexpansión "al estilo de C", de los operadores más y menos: "lcVar ++" y "lcVar - -" se expande como "lcVar = lcVar + 1" y "lcVar = lcVar –1". Pero, a diferencia de C, Intellisense en VFP permite utilizar el operador "=" con cualquier operador aritmético para la auto expansión de cadenas. Entonces  "lcVar +=" se convierte en "lcVar = lcVar + " y "lcVar *=" se convierte en "lcVar = lcVar *"
lAllowCustomDefScripts
Predeterminado = .T.
Esta es una propiedad no documentada en VFP 7.0. El método FoxCodeScript.DefaultScript() (que es llamado siempre que Intellisense encuentra un espacio en blanco) utiliza el valor de esta propiedad para determinar si se ha llamado o no al método HandleCustomScripts(). Si no pretende utilizar script de usuarios para modificar el comportamiento predeterminado, debe establecer este valor a Falso debido a que el script predeterminado es llamado cada vez que escribimos un espacio en la ventana de edición.
lEnableMultiWordCmdExpansion
Predeterminado = .T.
VFP 8.0 y posterior
Controla si los comandos con múltiples partes se expanden automáticamente. El valor predeterminado es .T. y cuando se iguala a .F. los comandos como INDEX ON deben ser escritos en su totalidad. Establecer estos valores a .F. deshabilita también la capitalización de la segunda palabra clave, independientemente del valor de lKeyWordCapitalization
lDebugScripts
Predeterminado = .F.
VFP 8.0 y posterior
Controla si el script que utiliza la versión de usuario del objeto foxcode puede ser recorrido línea a línea por el depurador. El valor predeterminado es .F. Vea que solo afecta a los script que utilizan su propia instancia local de la clase FoxCodeScript.

14 de julio de 2005

Juego de memoria

Un juego de memoria hecho con VFP.


*Blocks.prg
tic = createobject('frm')
tic.addobject('LOGIC','LOGIC')
for I = 1 to 64 step 1
 cmd = "cmdbk" + allt(str(i))
 tic.addobject(cmd,"cmdback")
endfor
=fillrand()
for I = 1 to 64 step 1
 cmd = "cmdtp" + allt(str(i))
 tic.addobject(cmd,"cmdtop")
endfor
tic.addobject("txt1","text1")
tic.addobject("txt2","text1")
tic.addobject("capt","capt")
tic.addobject("play1","capt1")
tic.addobject("play2","capt2")
=alignobj()
tic.autocenter = .T.
tic.show
on shutdown quit
Read Events

Define Class Frm As Form
 procedure init
  thisform.maxbutton = .F.
  thisform.minbutton = .F.
  thisform.width = 550
  thisform.height = 480
  thisform.caption = "Blocks"
 Endproc
 PROCEDURE UNLOAD
  Clear Events
 ENDPROC
Enddefine

PROCEDURE ALIGNOBJ
Private lnleft,lntop, lnrow, lncol
lnROW  = 1 
lnCOL  = 1
lnLEFT = 1
lntop = 1
For I = 1 to 64 Step 1
 AC = "tic.cmdtp"+ALLT(STR(I))
 lnLEFT = lnLEFT + 55
 &ac..left = lnLEFT
 &ac..top = lnTOP
 AC1 = "tic.cmdbk"+ALLT(STR(I))
 &ac1..left = lnLEFT
 &ac1..top = lnTOP
 lnCOL = lnCOL + 1
 IF Inlist(I,8,16,24,32,40,48,56)
  lnROW = lnROW + 1
  lnCOL = 1
  lnLEFT = 1
  lntop = lntop+ 55
 ENDIF
Endfor
lnleft = 20
lntop = lntop + 50
tic.play1.top = lntop
tic.play1.left = lnleft
tic.play2.top = lntop
tic.play2.left = lnleft + 120
lntop = lntop + 20
tic.txt1.left = lnleft
tic.txt1.top = lntop
tic.txt2.left = lnleft + 120
tic.txt2.top = lntop
tic.capt.left = lnleft + 300
tic.capt.top = lntop
Rele lnleft,lntop
Return

Define class LOGIC As Custom 
noofclick = 0
objval = ""
player1 = 0
player2 = 0
pla1 = .t.
pla2 = .f.
chkobj = ""
Enddefine
Define Class CMDtop As CommandButton
 Caption = ""
 visible = .t.
 backcolor = RGB(0,0,0)
 Forecolor = RGB(255,255,255)
 Fontsize = 25
 fontname = "Comic Sans MS"
 Visible = .t.
 width = 50
 Height = 50
 Borderstyle = 1
 PROCEDURE Click
  this.visible = .f.
  nm = substr(this.name,6)
  newnm = "tic.cmdbk" + nm + ".visible"
  newnval = "tic.cmdbk" + nm + ".value"
  newnobj = "cmdtp" + nm
  &newnm = .t.
  If tic.logic.noofclick = 0
   tic.logic.noofclick = 1
   tic.logic.objval = &newnval
   tic.logic.chkobj = newnobj
  Else
   tic.logic.noofclick = 2
   if tic.logic.objval # &newnval
    =inkey(.6,"h")
    obj_btn1 = tic.logic.chkobj
    obj_no1  = substr(obj_btn1,6)
    cmd = "tic.cmdtp" + obj_no1 + ".visible"
    &cmd = .t.
    obj_btn2 = newnobj
    obj_no2  = substr(obj_btn2,6)
    cmd = "tic.cmdtp" + obj_no2 + ".visible"
    &cmd = .t.
   Else
    if tic.logic.pla1 = .t.
     tic.logic.player1 = tic.logic.player1 + 1
     tic.txt1.value = tic.logic.player1
    Else
     tic.logic.player2 = tic.logic.player2 + 1
     tic.txt2.value = tic.logic.player2
    Endif
   Endif
   if tic.logic.pla1 = .t.
    tic.logic.pla1 = .f.
    tic.logic.pla2 = .t.
    tic.capt.caption = "Jugador 2 Turno"
   Else
    tic.logic.pla1 = .t.
    tic.logic.pla2 = .f.
    tic.capt.caption = "Jugador 1 Turno"
   Endif
   tic.logic.objval = ""
   tic.logic.noofclick = 0
  Endif
 Endproc
Enddefine

Define Class CMDback As TextBox
 Enabled = .f.
 visible = .f.
 backcolor = RGB(0,0,0)
 Forecolor = RGB(255,255,255)
 Fontsize = 25
 fontname = "Wingdings"
 Visible = .t.
 width = 50
 Height = 50
 Borderstyle = 1
Enddefine

Define Class text1 As TextBox
 Enabled = .f.
 Visible = .t.
 fontname = "Comic Sans MS"
 fontbold = .t.
Enddefine

Define Class capt As Label
 Enabled = .f.
 Visible = .t.
 fontname = "Comic Sans MS"
 caption = "Jugador 1 Turno"
Enddefine

Define Class capt1 As Label
 Enabled = .f.
 Visible = .t.
 fontname = "Comic Sans MS"
 caption = "Jugador 1"
Enddefine

Define Class capt2 As Label
 Enabled = .f.
 Visible = .t.
 fontname = "Comic Sans MS"
 caption = "Jugador 2"
Enddefine

Procedure fillrand
private m.var
For I = 90 to 121
 for j = 1 to 2
  do while .t.
   m.var = ceil(rand()*64)
   nm = "tic.cmdbk" + allt(str(m.var)) + ".value"
   if empty(&nm)
    &nm = chr(i)
    exit
   Endif
  Enddo
 endfor
Endfor
EndProc
Tomado de un mensaje de Alan Rodríguez Gonzaga del grupo vFoxPro (http://ar.groups.yahoo.com/group/vfoxpro)

 Carlos

1 de julio de 2005

Evitar la ejecución de nuestra aplicación (MUTEX API)

Determina cuando una instancia de la aplicación esta ya ejecutándose. Esta función se debe llamar al principio de la aplicación, si esta ya se esta ejecutando, la función intentará activar la aplicación.

Ejemplo:
*-- Primera vez
? FirsTime("Mi Aplicacion")  && retorna .T.
*-- Segunda vez
? FirsTime("Mi Aplicacion")  && retorna .F.
PROCEDURE FirsTime
********************************************************************
*** Name.....: FIRSTTIME.PRG
*** Author...: Marcia Akins & Andy Kramek
*** Date.....: 01/11/2004
*** Notice...: Copyright (c) 2004 Tightline Computers, Inc
*** Compiler.: Visual FoxPro 09.00.0000.2124 for Windows 
*** Function.: Determine whether an instance of the application is already running
*** .........: This function uses the creation of a named MUTEX to determine whether
*** .........: or not the application is already running. This function should be called
*** .........: near the top of the application's main program to create a named object 
*** .........: that can be checked every time the application is started.  If the named 
*** .........: object exists, the function will try to activate the FoxPro running application.
*** Returns..: Logical
********************************************************************
LPARAMETERS tcAppName
LOCAL lcMsg, lcAppName, lnMutexHandle, lnhWnd, llRetVal
lcMsg = ''
SET ASSERTS ON
IF EMPTY( NVL( tcAppName, '' ) )
  TEXT TO lcMsg NOSHOW 
    This is another Brain Dead Programmer Error.
    You must pass the name of an application to FirstTime().
    Have a nice day now...
  ENDTEXT
  ASSERT .F. MESSAGE lcMsg
  RETURN 
ENDIF
*** Format the passed in program name
lcAppName = UPPER( ALLTRIM( tcAppName ) ) + CHR( 0 )
*** Declare API functions
DECLARE INTEGER CreateMutex IN WIN32API INTEGER lnAttributes, INTEGER lnOwner, STRING @lcAppName
DECLARE INTEGER GetProp IN WIN32API INTEGER lnhWnd, STRING @lcAppName
DECLARE INTEGER SetProp IN WIN32API INTEGER lnhWnd, STRING @lcAppName, INTEGER lnValue
DECLARE INTEGER CloseHandle IN WIN32API INTEGER lnMutexHandle
DECLARE INTEGER GetLastError IN WIN32API 
DECLARE INTEGER GetWindow IN USER32 INTEGER lnhWnd, INTEGER lnRelationship
DECLARE INTEGER GetDesktopWindow IN WIN32API 
DECLARE BringWindowToTop IN Win32APi INTEGER lnhWnd
DECLARE ShowWindow IN WIN32API INTEGER lnhWnd, INTEGER lnStyle
*** Try and create a new MUTEX with the name of the passed application
lnMutexHandle = CreateMutex( 0, 1, @lcAppName )
*** If the named MUTEX creation fails because it exists already, try to display
*** the existing application 
IF GetLastError() = 183
  *** Get the hWnd of the first top level window on the Windows Desktop.
  lnhWnd = GetWindow( GetDesktopWindow(), 5 )
  *** Loop through the windows. 
  DO WHILE lnhWnd > 0
     *** Is this the one that we are looking for?
     *** Look for the property we added the first time
     *** we launched the application
     IF GetProp( lnhWnd, @lcAppName ) = 1
       *** Activate the app and exit stage left
       BringWindowToTop( lnhWnd )
       ShowWindow( lnhWnd, 3 )
       EXIT
     ENDIF
     lnhWnd = GetWindow( lnhWnd, 2  )
  ENDDO
  *** Close the 'failed to open' MUTEX handle
  CloseHandle( lnMutexHandle )
ELSE
  *** Add a property to the FoxPro App so we can identify it again
  SetProp( _vfp.Hwnd, @lcAppName, 1)
  llRetVal = .T.
ENDIF
RETURN llRetVal

Regards,

Marcia G. Akins
Tightline Computers, Inc.