Blog sobre programación en VFP, Actualizado por Jorge Mota en Guatemala ;)



Archivo de CategoríasIdeas



Desarrollo & Ideas & Trucos 13 Feb 2008 02:02 pm

Como imprimir imágenes almacenadas en tablas sin usar campo general en los reportes (VFP 9)

, , , , , , , , ,

Bueno, hasta hace poco lo que hacía al necesitar imprimir una imagen en un reporte era usar campo general para almacenarlas o sacarlas a un directorio temporal para así poder mandarlas a impresión.

Pero ahora con el campo BLOB en VFP9 podemos almacenar el contenido de una imagen y al mismo tiempo imprimirla en un reporte sin necesitar hacer conversión a un campo general.

Veamos un ejemplo

Create cursor qImagen (imagen blob)
append blank in qImagen
lcDir =FullPath(Curdir())
replace qImagen.imagen with filetostr(getfile([jpg;bmp;gif]))
cd (lcDir)
private oImg
oImg = newobject([image])
oImg.pictureVal = qImagen.imagen

Necesitamos también un reporte con un objeto Picture/OLE Bound establecido así:

Ahora corremos el reporte
report form "NuestroReporte" preview

Pero y que pasa si queremos imprimir imágenes que están almacenados en una tabla (en registros diferentes)?

Grabamos lo siguiente como GetImg.prg

*Function getImg
lParameters nId, cImgCont
oImg = newobj([image])
oImg.pictureval =cImgCont
return oImg

Creamos un reporte y le agregamos un objeto Picture/OLE Bound y le establecemos la propiedad así:
reporte_picture_val2.jpg

Ahora podemos probar la función en el reporte:

use in select([qImagen])
Create cursor qImagen (numero i,imagen blob)

append Blank in qImagen
append Blank in qImagen
append Blank in qImagen
append Blank in qImagen

lcDir =FullPath(Curdir())
lcFile = getfile([jpg;bmp;gif])
update qImagen set numero =recno(),imagen =filetostr(lcFile)
report form "MiReporte" preview

, , , , , , , , ,

Desarrollo & Ideas 27 Ago 2007 02:30 am

Configurando El entorno para el control de versiones con VFP y SubVersion (parte 2)

, , , , , , , , , , , , , , , ,

Bueno, en esta parte del tutorial vamos a configurar algunas cosas de nuestro proyecto para poder importarlo en nuestro Depósito (repository) de SubVersion.

Cabe mencionar que la primera parte es configurar TortoiseSVN para evitar que incluya archivos que no querramos llevar control de versiones (archivos propios de cada desarrollador que no van al ejecutable, archivos de configuración de cada estación, archivos .fxp, archivos de texto, archivos dbf, cdx, fpt, dbc, etc)

Así que vamos a una carpeta en el explorador de Windows, clic derecho / TortoiseSVN / Settings


Opción Menú para ingresar a opciones de TortoiseSVN

En la ventana que aparecerá debemos configurar las 2 opciones que están señaladas a continuación:

Ventana de opciones de TortoiseSVN

  • Global Ignore pattern:
  • Acá debemos indicar las extensiones de los archivos queremos exclúir, tenga en cuenta que es Case Sensitive por lo que quizá quiera agregar las extensiones en la forma:
    *.Fxp, *.fxp, *.FXP
    o bien indicar una exclusión así:
    *.[Ff][Xx][Pp]
    También puede indicar que quiere exclúir un directorio completo usando una cadena como ésta:
    */Data, Datos/*, Puede referise a la ayuda para más opciones de exclusión :).

  • Use “_svn” instead “.svn” directories
  • Es especialmente util cuando pensemos usar SubVersion con Visual Studio también, debido a que el editor de .Net tiene problemas con los folders que empiezan por un punto (.svn), se debe tener en cuenta que sí un directorio ya fué versionado con TortoiseSVN sin marcar esta opción y luego la selecciona deberá versionar nuevamente, para que lo reconozca.

Si nos conectamos a traves de un proxy al servidor de SubVersion, necesitaremos ir al apartado Network a configurarlo. Igualmente si ya disponemos de algún software para comparar archivos como WinMerge o DiffDoc deberá ir a configurarlo al apartado External Programs /Diff Viewer , sí deséa ver algunos otros programas para ver las diferencias entre las versiones puede darle un vistazo a este listado.

Esta segunda parte ha sido poco, pero conforme tengo tiempo he ido escribiendola, esperen pronto la segunda parte :)

, , , , , , , , , , , , , , , ,

Desarrollo & Ideas 18 Ago 2007 01:22 am

Instalando SubVersion para control de versiones con VFP (parte 1)

, , , , , , , , , ,

Bueno, hasta hace poco yo estuve usando SourceGear para el control de versiones de mis proyectos, pero debido al problema por todos conocido que los formularios y clases se almacenan realmente en archivos DBF (el control de versiones los considera binarios) es prácticamente imposible que 2 personas trabajen en la misma forma/clase y luego unir los cambios en un solo archivo y que este sea un archivo válido para vfp.

Ahora debido al presupuesto, estoy utilizando el control de versiones SubVersion, pero lastimosamente no he encontrado casi ninguna buena documentación de uso en español, por no decir que no existe prácticamente nada en español que enseñe a implementarlo con VFP.

En este primer artículo, voy a mostrar como instalar SubVersion y también TortoiseSVN para empezar.

La mejor manera de instalar SVN, configurarlo como servicio, Crear un “Depósito” inicial (Repository) e instalar TortoiseSVN, es usando el instalador de http://svn1clicksetup.tigris.org/ ya que nos hará todo el trabajo.

Para los que quieran instalar por aparte todo, acá les dejo los links de descarga:

Debido a que el instalador svn1clickSetup no necesita mucha información intentare acá explicar los pasos necesarios para instalarlos por separado:

Una vez que tengamos el paquete denominado svn-X.X.X-setup.exe (en mi caso 1.4.4) procedemos a ejecutarlo y a seguir las instrucciones en pantalla. Debemos recordar donde lo instalamos en mi caso C:\Archivos de programa\SubVersion.

Instalamos TortoiseSVN, y reiniciamos la máquina en caso nos lo solicite.

Una vez que reiniciamos si es que lo pidió, abrimos una ventana del explorador de windows, y nos dirigimos a la unidad en que querramos mantener la Base de datos de SubVersion, por fácilidad yo prefiero ponerlo en el C: en la raíz, bajo el nombre de SVNCode (procuren no usar espacios en el nombre ni caracteres raros :P ), así que todo lo que hace falta hacer es crear dicho directorio para que quede así:

C:\SvnCode

Damos clic derecho sobre el folder y en la nueva opción que dice “TortoiseSvn” nos posicionamos para seleccionar en el submenú la opción “Create Repository Here…”

Creando el Depósito

Luego nos preguntará, el tipo de base de datos que deséamos utilizar para el depósito, la recomendación general es que utilizemos el tipo Native Filesystem (FSFS):

Tipo de datos para el depósito

Una vez que selecciones el tipo de datos a usar, damos clic a ok y nos avisará que el depósito fue creado exitósamente :) a menos claro que no dispongamos de permisos sobre esa carpeta o espacio ;) (o que la carpeta no se encuentre vacía antes de crear el depósito allí).

Al exáminar la carpeta veremos que ha creado varias subcarpetas

  • Dav
  • Locks
  • Conf
  • Db
  • Hooks

También un Readme.txt que conviene dejar allí, en caso que alguien más use esa computadora y quiera averiguar que es esa carpeta para evitar que la borre, también en la carpeta hooks, encontrará varios archivos .tmpl que quizá le guste revisar y leer al respecto cómo usarlos y configurarlos (estos pueden estar escritos en python o en perl)

El siguiente paso, será configurar nuestro depósito, abrimos la carpeta Conf y veremos 3 archivos:

  • svnserve.conf
  • passwd
  • authz

Los 2 primeros archivos serán los únicos que necesitaremos configurar por el momento (a menos que quieran configurar apache y el módulo webdav, que escapa al objetivo de este artículo ya que no uso apache)

SvnServe.conf:
Debemos agregar 2 líneas, una para los usuarios que no inicien sesión anon-access) y otra para los usuarios que se auntentícaron (auth-access), el valor Default es darle lectura a los no autentícados y escritura para los otros, yo recomiendo no dar acceso a nada (none) para los no autentícados sí el acceso se hará atravéz de internet. por lo pronto vamos a agregar a nuestro archivo Svnserve.conf las 2 siguientes líneas:

anon-access = none
auth-access = write

Passwd
Acá vamos a agregar tantas líneas como usuarios querramos que tengan acceso al depósito, en mi caso agregare 2:

dev1=pwd1630
dev2=1675Prq

Grabamos los cambios y nos toca decidir sí queremos que SubVersion este configurado como servicio, o por el contrario si lo que queremos es arrancar el programa cada vez que lo vayamos a necesitar (la máquina no solo sirve para desarrollo/servidor/o bien queremos tener control de cuando este disponible/etc).

En el caso que querramos controlar cuando arranca SubVersion lo mejor será usar un archivo.Bat con algo como esto:
cd "c:\archivos de programa\programacion\subversion\bin"
svnserve.exe --service -rC:\svncode

Recuerde que debe editar las rutas para que coincidan con su instalación y el depósito que creó con tortoisesvn. Cada vez que necesite iniciar SubVersion puede ejecutar ese archivo.bat.

Por el contrario, si lo que queremos es que este disponible al iniciar la máquina (aún cuando no hayamos iniciado sesión aún), debemos configurarlo como un servicio, así que arrancamos la consola de comandos (Inicio /Ejecutar / cmd.exe) y escribimos lo siguiente (todo en una línea)

sc create svn binpath= "\"c:\archivos de programa\Subversion\bin\svnserve.exe\" --service -rC:\svncode" displayname= "Servidor de SubVersion" depend= Tcpip start= auto

Deben tener en cuenta el espacio que se encuentra después de cada signo de igual (= ) ya que es obligatorio escribirlo así, también tengan en cuenta la ruta, quizá necesite ajustarla para que concuerde con su instalación o su depósito.

Sí todo ha ído bien nos deberá mostrar un texto como este

[SC] CreateService SUCCESS

Delo contrario nos dará un error informandonos de la sintáxis, tendremos que digitar de nuevo y poner atención a que quede igual al texto de arriba :).

Una vez que tengamos creado el servicio, debemos iniciarlo, desde la consola de comandos:

sc start svn

Que a su vez devolverá algo como esto:

SERVICE_NAME: svn
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 3800
        FLAGS              :

Y bueno ya tenemos Svn configurado instalado, configurado como servicio, y un Depósito creado, listo para ser usado. Pronto la segunda parte del control de versiones en el que veremos como integrar nuestros proyectos.

Para los que desean tener SubVersion en un servidor pero no se animan a instalarlo sin probarlo antes, podrían probar esta máquina virtual con vmware que corre en un ubuntu. http://www.young-technologies.com/Software/Subversion-Virtual-Machine/ (en inglés), la ventaja de correrlo así es que podríamos migrar a un servidor posteriormente, y también el hecho de cargar el servicio solo cuando lo necesitemos en caso que solo sea 1 programador en el proyecto :).

Hasta la próxima.

Links: SubVersion (sitio oficial)
TortoiseSVN (sitio oficial)
Referencias: Setting up and running Subversion and Tortoise SVN
with Visual Studio and .NET

CVS, SubVersion and Visual FoxPro

, , , , , , , , , ,

Desarrollo & API & Ideas & Trucos 08 Ago 2007 01:43 pm

Obteniendo el nombre corto de una ruta o archivo

, , , , , , , ,

Hace poco me tope con la necesidad de saber la ruta corta de un archivo (o ruta DOS), al decir ruta corta me refiero a la ruta que manejaba el DOS antiguo, que a diferencia de windows cada archivo solo puede tener 8 caracteres en el nombre del archivo y 3 en la extensión. es decir

C:\Mis Archivos\Juan Pérez y Pérez.xls una aplicación DOS lo encontraría así: C:\Misarc~1\JUANPR~1.XLS.

Esta Función permite obtener ese nombre corto:

Function GetDosFileName(lcfile As String) As String
**http://fox.desdeguate.com/?p=77
**Autor: Jorge Mota
**Devuelve la ruta corta (DOS) de una ruta o un archivo.
Declare Long GetShortPathName In "kernel32" String lpszLongPath,;
String lpszShortPath, Long lBuffer
lcFileName=Replicate(Chr(0),254)
lnTotal=GetShortPathName(lcfile, @lcFileName, Len(lcFileName))
Return Substr(lcFileName,1,lnTotal)
Endfunc

Ejemplos de uso:
Archivo:
?lcfile = GetDosFileName([C:\Juan Pérez y Pérez.xls])
Directorio:
lcDir = GetDosFileName([C:\Archivos de Programa\])

Retornará una cadena vacía si el directorio o archivo no existe.

Hasta la próxima.

, , , , , , , ,

Desarrollo & Ideas & Trucos 29 Jul 2007 01:01 pm

Obteniendo la hora desde un servidor de Tiempo en internet con vfp (iTime)

, , , , , , ,

Hace algún tiempo en www.Portalfox.com se publicaron algunos artículos para poder obtener la hora de nuestro servidor, pero en algunos casos, no nos es posible tener acceso al servidor, ya que no usamos carpetas compartidas (shared) así que no podemos hacer el trabajo por medio de esos métodos.

Y como hace algún tiempo instale linux, para pruebas de servidor de mySql, en una máquina y me dí cuenta que se puede configurar como un servidor de hora, (tengo entendido que en Windows, podemos lograrlo según Microsoft para windows 2003 y para XP también pero no he tenido tiempo de probarlo), bueno el caso es que teniendo un servidor de hora me dí cuenta que podía sincronizar las estaciones XP desde el apartado que pone Hora de internet /Internet zone, al entrar a Panel de control (Control Panel) y seleccionar Hora y Fecha (date and time).

Así que me puse a investigar, de que manera podíamos obtener la hora desde un servidor de este tipo desde vfp, según el RFC 868 el servidor debe devolver un número de 32 bits, el cual debemos sumarle en segundos a la fecha 01-01-1900. a la Fecha y Hora que obtengamos de allí, debemos restarle/sumarle la diferencia horaria según en la zona que nos encontremos.

Seguir leyendo »

, , , , , , ,

Sin Categoría & Desarrollo & Ideas 12 Jun 2007 03:08 pm

Formateando datos para usar con SQL PassTrough (SPT)

, , , , , ,

Pues como se puede ver en estos artículos podemos usar el ? para que el Fox formatée correctamente los valores, el debuggear esos scripts sql son muchas veces bastante difíciles, sobre todo cuando nos conectamos aVFP por medio de ODBC y nos dice “Tipo de dato incorrecto” / “Data type Mismatch” y no sabemos por donde buscar.

Lo ideal también puede ser almacenar el script en un .sql o .txt para su posterior ejecución, allí tenemos que lidiar con el formato a enviar a cada cadena.

Esta función FormatoDato, sirve para datos VFP o Sql Server (podría servir para otros motores, excepto con tipos Date o Datetime, ya que usa el formato de fechas de Sql Server)

Para otros motores de datos, tendrá que modificar el tratamiento de Fechas.

La función:

Function FormatoValor(luValor, lSql) As String
	Local luReturn
	luTipo = Vartype(luValor)
	Do Case
		Case luTipo = [C]
			luReturn = [']+Alltrim(luValor)+[']
		Case Inlist(luTipo,[I], [N], [Y])
			lcNum = Alltrim(Transform(luValor))
			If [.] $ lcNum
				luReturn = Transform(luValor)
			Else
				luReturn = Alltrim(Transform(luValor))
			Endif
		Case luTipo = [D]
			If !lSql
				If Empty(luValor)
					luReturn =[{}]
				Else
					luReturn = [Date(] + Alltrim(Transform(Year(luValor)))+[,]+Alltrim(Transform(Month(luValor)))+[,]+Alltrim(Transform(Day(luValor)))+[)]
				EndIf
			Else
				If Empty(luValor)
					luReturn =[Null]
				Else
					luReturn = [{d '] + Alltrim(Transform(Year(luValor)))+[-]+Alltrim(Transform(Month(luValor)))+[-]+Alltrim(Transform(Day(luValor)))+['}]
				EndIf
			Endif
		Case luTipo = [T]
			If Empty(luValor)
				luReturn = [Null]
			Else
				luReturn = [{ ts ']+Alltrim(Transform(Year(luValor)))+[-]+Alltrim(Transform(Month(luValor)))+[-]+Alltrim(Transform(Day(luValor)))+[ ]+Alltrim(Transform(Hour(luValor)))+[:]+Alltrim(Transform(Minute(luValor)))+[:]+Alltrim(Transform(Sec(luValor)))+['}]
			Endif
		Case luTipo = [X]
			luReturn = [Null]
		Case luTipo = [L]
			luReturn = luValor
		Otherwise
			luReturn=[']+Alltrim(Transform(luValor))+[']
	Endcase
	Return Transform(luReturn)
Endfunc

También puede descargarla desde acá: http://fox.desdeguate.com/descargas/vfp/formatodato.prg

Un ejemplo sería

Set textmerge on to Memvar cSql noshow
\ insert into tabla (CampoC, CampoT, CampoN) values (< >,< >,< >)
set textmerge to

Lo que daría como resultado para vfp
insert into tabla (CampoC, CampoT, CampoN) values (’ValorCampo’,date(2006,05,06),10.50)

sí usaramos el segundo parámetro:
insert into tabla (CampoC, CampoT, CampoN) values (’ValorCampo’,{d ‘2006-05-06′ },10.50)

También puede agregar su lógica de selección de motor a la función para que todo el trabajo sea transparente!.

Saludos

, , , , , ,

Desarrollo & API & Ideas 22 Feb 2007 05:04 pm

Creando aplicaciones de modo consola desde VFP

, , , , , , ,

Bueno, esto es un código viejo que tengo desde hace rato por publicar, pero no por eso no util :)

Recuerdo que en unos de mis primeros contactos con el mundo linux, ví una aplicación para grabar cd’s, que al entrar a modo debug, mostraba una ventana al estilo D.O.S en el que íba indicando que método llamaba y que parámetros estaba usando, también el valor que retornaba, y me gusto mucho la idea, pero nunca realmente lo implemente, hasta hace poco que necesitaba en un proceso que se invoca desde otra estación para ejecutarse en el servidor, saber en que método se quedaba exactamente, ya que el proceso era asíncronico, pues bien, allí fue donde se me ocurrio tener desde vfp la manera de poder crear una de estas ventanitas:

Aplicación de modo consola

Pero en este ejemplo aún no les mostrare como usar la emulación de la consola de comandos, nada más les brindo una aplicación que les permitira agregar comandos en un dbf y ejecutarlos desde la ventana en cuestión:

Ejemplo de emulación de consola de comandos desde vfp

al ejecutar “vfp_console.prg” veran la pantalla negra en cuestión (también es configurable el color de fondo y color de la letra, como aprenderemos en la próxima publicación), puede escribir “ayuda” y presionar enter, lo que le mostrará una lista de comandos disponibles, también podrá escribir Ayuda Comando (donde Comando es el comando del que quiere obtener ayuda) para mostrar información acerca del mismo, por ejemplo Ayuda hora

El proyecto incluye un dbf llamado “Comandos” donde puede establecer que x Comando VFP no sea permitido ejecutar (Wait window, quit, cancel, debug, etc) solo debe establecer el valor del campo “Permitido” a .f. en el registro.

Para descargar el proyecto: http://fox.desdeguate.com/descargas/vfp/vfp_console.zip clic acá

Saludos y hasta la próxima cuando revisaremos y veremos más a detalle estas funciones API.

, , , , , , ,

Desarrollo & Internet & Ideas 24 Ene 2007 01:27 pm

Procesando RSS desde VFP

, , , , , , , ,

Recientemente para un proyecto en el que estoy trabajando, (un lector de orígenes RSS, para blogs), me tope con el problema de como cargar un RSS en XML a un cursor en vfp, pues por más que le movía al XMLToCursor y al XMLAdapter no lograba ver todas las entradas, así que probando probando y leyendo un poco sobre XML dí con la forma de hacerlo :)

Básicamente consiste en seleccionar la referencia a IXMLDOMElement que nos brinda el XMLAdapter, y hacer uso del metodo SelectNodes que este nos brinda.

Un breve ejemplo de lo que hablo:

Local loXml As Xmladapter, loItems As Collection
loXml = Createobject("XMLAdapter")
luNonXML = .F.
lcFileName = Getfile("xml")
Try
	loXml.LoadXML(lcFileName,.T.)
Catch To loError
	Messagebox("Error al procesar el XML, por favor revise que la URL del FEED del sitio sea correcta",48,"Error")
	luNonXML = .T.
	Set Step On
Endtry
If luNonXML
	Return .F.
Endif
loDom = loXml.IXMLDOMElement
loItems= loDom.SelectNodes("//item")
For lnCiclo = 0 To loItems.Length - 1
	Append Blank In qElementos
	lcOtros = []
	lcTitulo = []
	For lnItem = 0 To loItems.Item(lnCiclo).ChildNodes.Length -1
		loElem= loItems.Item(lnCiclo).ChildNodes.Item(lnItem)
		lcNodo =Upper(Alltrim(loElem.NodeName))
		Do Case
			Case lcNodo = [TITLE]
				lcTitulo = loElem.Text
				*			Case lcNodo =[CONTENT]
				*				Wait Window "Content:" + loElem.Text
				*			Case lcNodo = [DESCRIPTION] And Empty(Alltrim(qElementos.texto))
				*				Wait Window "Description:" + loElem.Text
				*			Case lcNodo = [LINK]
				*				Wait Window "URL:" + loElem.Text
				*			Case lcNodo = [CATEGORY]
				*				Wait Window "Category:" + loElem.Text
		Endcase
		lcOtros = lcOtros + loElem.NodeName + [:] + loElem.Text + Chr(13)+Chr(10)
	Endfor
	Messagebox(lcOtros,0,lcTitulo)
Endfor

Antes deben de guardar en su pc, un orígen de algún blog, como puede ser el de este blog:
http://fox.desdeguate.com/feed

(clic derecho, guardar como… y le ponen extensión xml ;) )

Luego lo cargan con este simple programa y podran ir recorriendo cada uno de los atributos que el Feed nos de.

Para más información sobre el standard RSS: http://www.rss-specifications.com

Ojalá y mi bendito lector de RSS-VFP este a punto para ser lanzado ;)

Creo que me acabo de dar cuenta que en realidad esto sirve para ATOM no para RSS 1.0 :)
Saludos y hasta la próxima.

, , , , , , , ,

Desarrollo & Ideas 10 Ene 2007 04:32 am

Estableciendo una Forma a solo lectura: iReadOnly

, , , , , , ,

En algunas ocasiones, necesitamos que una forma bajo ciertas circunstancias muestre su contenido, pero de solo lectura para la mayoría de los controles, normalmente bajo los accesos de usuario, estado del registro, etc.

Recientemente me he visto en esa necesidad, así que nada más práctico que crear una clase que me permita hacer ese trabajo, aunque con una pequeña observación, yo no acostumbro usar la propiedad ReadOnly de un control para deshabilitar el acceso, prefiero utilizar Enabled = .f., y la clase hace su trabajo así, deshabilitando controles, y por que se preguntarán, pues debido a que algunas veces necesito que carguen la forma, y para ciertos registros puedan editar la información, pero para otros, no puedan ni siquiera acceder al contenido de los pageframes, o navegar por los grids.

La clase cuenta con 2 propiedades importantes:

  • icExcluir
  • que indica que clases base no queremos procesar (labels, timers, shapes, etc), debe ser una lista al estilo: “shape”,”timer” incluyendo las comillas.

  • ilContenedores
  • nos permite indicar si la clase deshabilitará los controles contenedores también, tal es el caso de los pageframe, pages,grids, container. para que el usuario no los pueda usar.

También cuenta con una propiedad ilReadOnly que nos indica si la forma se encuentra en solo lectura (.T.) o acceso normal (.F.), que puede utilizar en cualquier momento para saber el estado del acceso.

El método que se debe invocar para alternar entre acceso normal y solo lectura es SetReadonly() podiendole indicar el estado al que queremos establecer, mandandolo a llamar con el parametro .T., establece a solo lectura la forma, con parametro .f. o vacío, se establece en acceso normal (subsecuentes llamadas del mismo método sin parametros alternará entre solo lectura y acceso normal).

La clase incluye un formulario de ejemplo que permite ver en acción la clase, si el checkbox con el texto “DesHabilitar Objetos contenedores” se establece en .T., al dar clic en el botón “Solo Lectura” no podrá hacer uso del grid, ni del pageframe, por el contrario, si esta en .F., entonces sí podra tener acceso.

La clase cuenta con un método que debe ser reescrito según cada forma “Proceso_Before” en el que puede tomar las consideraciones del caso, para decidir si determinado control se establecen a solo lectura, el método recibe como parametro el control que se esta evaluando, por lo que puede hacer una comparación del tipo:

If oControl = Thisform.MiGrid
	Return .F. &&impide que se deshabilite el control.
Endif

O también del tipo

If Inlist(oControl, Thisform.cmdSave, Thisform.cmdCancel)
	Return .F. &&impide que se deshabilite el control.
Endif

Si el método retorna .F., el control no se deshabilita.

Además si necesita que x Control siempre se mantenga deshabilitado, puede programar el refresh del control para que siempre lo haga, o establecer la propiedad ReadOnly a .T., también, puede establecer siempre la propiedad Enabled = .f. desde Procesa_Before cuando oControl = thisform.controlsiempredeshabilitado.

Para ver el ejemplo y descargar la clase clic acá
http://fox.desdeguate.com/descargas/vfp/iReadOnly.zip

Saludos y hasta la próxima.

, , , , , , ,

Desarrollo & Ideas 28 Dic 2006 01:42 pm

Guardando logs… iLog

, , , , , , ,

Bueno, esta vez de regreso con un programita un tanto sencillo, que nos permite generar un log sencillo de un proceso dado.

un ejemplo de uso:

Local oLog As oLog Of iLog.prg
oLog = Newobject("oLog")
lnTime = Datetime()
oLog.icLog = "C:log_prueba.txt"
oLog.agregar("Inicio del log","*Inicio*")
lnCont = 0
For lnCiclo  = 1 To 10000
	If lnCont >= 7
		If Mod(lnCiclo,3)!=0
			oLog.agregar("Ocurrió un error interno #" +;
	 Transform(lnCiclo),"Error")
			lnCont = 0
		Else
			oLog.agregar("Evento Procesado" + [# ] +;
 	Alltrim(Transform(lnCiclo)),"Proceso")
		Endif
	Else
		oLog.agregar("Nuevo evento" + [# ]+;
	Alltrim(Transform(lnCiclo)),"Evento")

	Endif
	lnCont = lnCont + 1
	Wait Window trans((lnCiclo/10000) * 100,[###]) + [%] Nowait
Endfor

oLog.agregar("Final  del log","*Fin*",.T.)

Messagebox([Tiempo utilizado para registrar 10,000 eventos: ] +;
	 Transform(Datetime()-lnTime) + [ segs.])

La clase cuenta con una propiedad icLog que es el archivo de Texto en el que deseamos generar el log, también el método Agregar, que requiere de 3 parametros, los primeros 2 son necesarios y son Cadena que queremos almacenar (información del evento) y Tipo del evento: proceso, error, alerta, etc., el tercer parametro, al pasarse como .T. hace que la clase escriba el contenido del log al disco (hasta que se pasa como .T. se genera el log en el disco), también puede invocarse el método GenerarLog() para el mismo resultado.

Una parte del log generado con el ejemplo:

*Eventos registrados *
Error: 1333
Evento: 8001
Proceso: 666

12:51:32.87| *Inicio*: Inicio del log
12:51:32.87| Evento: Nuevo evento# 1
12:51:32.87| Evento: Nuevo evento# 2
12:51:32.87| Evento: Nuevo evento# 3
12:51:32.87| Evento: Nuevo evento# 4
12:51:32.87| Evento: Nuevo evento# 5
12:51:32.87| Evento: Nuevo evento# 6
12:51:32.87| Evento: Nuevo evento# 7
12:51:32.87| Error: Ocurrió un error interno #8
12:51:32.87| Evento: Nuevo evento# 9
12:51:32.87| Evento: Nuevo evento# 10
12:51:32.89| Evento: Nuevo evento# 11
12:51:32.89| Evento: Nuevo evento# 12
12:51:32.89| Evento: Nuevo evento# 13

Para descargar el código (incluye el código del ejemplo):
http://fox.desdeguate.com/descargas/vfp/ilog.prg

Saludos y hasta la próxima.

, , , , , , ,

Desarrollo & Ideas 18 Dic 2006 01:59 pm

Presentando iBrowser (Navegando por las imágenes de un directorio)

, , , , , , ,

En esta ocasión les presento un post pre programado, ya que esta por nacer mi hij@ así que no sé muy bien, cuando va a salir este post, ya que lo estoy preprogramando, para estas alturas ya mi hij@ debe estar a mi lado :).

Esta es una clase que permite navegar por un directorio, mostrar las imágenes en miniatura que contiene, y permitir al usuario seleccionar una imágen:

iBrowser

La clase iBrowser se debe invocar de la siguiente manera:

oImg =Newobject("ibrowser", "iBrowser", "", "C:windows", "bmp,gif,jpg,png", "Seleccione una imágen", "Mensaje de Texto al usuario...",@oValor)
oImg.Show()
  • Donde “iBrowser”,”iBrowser” indica el nombre de la clase y vcx en el que se almacena la clase.
  • “C:\windows” directorio del que quieren permitir al usuario seleccionar una imágen.
  • “bmp,gif,jpg,png” es el filtro de las imágenes que desean permitir al usuario seleccionar, si por ejemplo, necesita que el usuario seleccione únicamente archivos JPG y GIF, escriba “jpg,gif”.
  • “Seleccione una imágen”, es el título que tendrá la ventana de iBrowser.
  • “Mensaje de Texto al usuario..” es un mensaje corto que desee mostrar al usuario, tal como “Seleccione una imágen para papel fondo de pantalla.”.
  • @oValor es una variable que de existir previamente, en la que se almacenará un objeto empty que contiene la ruta al archivo seleccionado en la propiedad icFileName.

iBrowser necesíta de la clase iPanel XP, previamente públicada en este sitio.

También incluye un botón arriba a la izquierda como […] para permitir al usuario moverse de directorio.


Seguir leyendo »

, , , , , , ,

Desarrollo & Ideas 09 Nov 2006 03:09 pm

Permitiendo navegar en las tablas al usuario…

Hace poco ví una pregunta en el news de Microsoft, sobre como poder dar la opción a un usuario para navegar “browse” para los amigos, a una tabla, pero en un grid, y que la forma sepa que campos debe usar, digamos para x Tabla, es decir, se le pide que muestre la forma Contactos, y que solo muestre los campos Nombre, Apellidos y Teléfono.

Seguir leyendo »

Ideas 06 Oct 2005 10:45 pm

Optimizando el Escritorio de Trabajo de VFP con iDesktop

Bueno, en esta ocasión (si ya se que me he tardado en publicar algo, pero ha sido por motivos de fuerza mayor) vengo con una utilidad para usar mientras desarrollamos en VFP (únicamente probado con VFP 9, pero debería funcionar con Visual Fox Pro 8 también, como mínimo).

La idea principal, se basa en el escritorio de Windows, y es el tener iconos en nuestra área de trabajo del _Screen, así como una ventana “iOutput” para que allí se muestren los resultados de los comandos tales como ?[1], Calculate Sum(1) o el comando Dir.

Seguir leyendo »