'' Artillería Multimedia

Por Alberto Rodriguez




En cierta ocasión un cliente me pidió que hiciera una aplicación multimedia con VFP 3.0. Las razones de usar Fox estaban más o menos jutificadas pues tendría un gran acceso a datos, etc.. y el uso de VFP 3.0 era debido a que tendría que correr sobre win 3.11

Pero la aplicación tendría que ser muy visual con un cuidado diseño y todos los efectos habituales de las aplicaciones multimedia como visualización de graficos AVI, sonido, efectos visuales de los botones, etc...

En principio tuve mis reparos pues al tener que correr también sobre win 3.11 ya no podías utilizar .OCX y todas las posibilidades graficas quedaban muy mermadas. De todos modos, después de las últimas experiencias que había tenido con los .OCX tampoco me hacía mucha ilusión, embadurnar toda la aplicación con estos controles que luego dan mucho problemas en los mantenimientos de las aplicaciones y en las instalaciones.

Antes de empezar estuve haciendo algunas pruebas con el código pues tenía que ver de qué forma se podían visualizar ficheros .AVI en win 3.11 o escuchar sonido en esa plataforma y también la forma de hacer sin el uso de OCX los contenidos visuales de la aplicación. Fruto de esos ensallos es este código que te da la artillería necesaria para enfrentarte a una aplicación de esas características.

Ejecutar ficheros .AVI

El primer problema que había que acotar era poder visualizar ficheros AVI en VFP 3.0 y corriendo en entornos Win9x y Win 3.11

No puedo decir que sea fácil pero el resultado fue satisfactorio, basta con que ejecutes el siguiente código:

PUBLIC MCIEXE
SET LIBRARY TO FOXTOOLS.FLL
* La siguiente función registra la libería * MCIEXECUTE usando la
* Foxtools
MCIEXE = REGFN("MCIExecute" ,"C","I",;
	 "MMSYSTEM.DLL

cAVIFile = "c:\bmps\foxrain.avi" 
nRESULT = CALLFN(MCIEXE, "open " + ;
cAVIFile + " TYPE AVIVIDEO alias;
 	wind style popup") 
nRESULT = CALLFN(MCIEXE, "put wind ;
	window at 300 200 200 160")
nRESULT = CALLFN(MCIEXE, "play wind wait") 
nRESULT = CALLFN(MCIEXE,"close wind")

Este código no sólo te permite visualizar ficheros .AVI sino cualquier componente MCI. La función MCIEXECUTE se encuentra dentro de la librería de 16 bits MMSYSTEM.DLL y por tanto se debe de usar las funciones REGFN y CALLFN para registrarla antes de poder ejecutarla. Seguramente si trabajas con VFP 6.0 te sentirás ahora que estás viajando hacia atrás unos cuantos años pero, ya sabes, ¡el cliente manda!

Una vez que se ha registrado la función MCIEXECUTE entonces de pueden enviar una gran variedad de órdenes para abrir, ejecutar y cerra los ficheros .AVI. La sintaxis de las órdenes MCI te permiten controlar muchos de los atributos de las opciones MCI como tamaño, posición, velocidad, etc...

De las órdenes que hemo usado antes, la sentencia:

 
nRESULT = CALLFN(MCIEXE, "open " + cAVIFile +;
	 " TYPE AVIVIDEO alias wind style popup") 

nos abre una instancia del device MCI y le da el nombre de 'wind'

La órden:

nRESULT = CALLFN(MCIEXE, "play wind wait") 

ejecuta el fichero AVI paralizando las órdenes MCI hasta que se ha completado la ejecución.

La órden:

nRESULT = CALLFN(MCIEXE,"close wind") 

cierra la instancia del device MCI especificado por el alias 'wind'

Existen más cosas interesante, si pones:

nRESULT = CALLFN(MCIEXE, "put wind window at 300 200 164 147")

antes de :

nRESULT = CALLFN(MCIEXE, "play wind wait")

podrás controlar donde quieres que se te muestre la ventana con el fichero .AVI

La velocidad de ejecución también la puedes controlar con:

nRESULT = CALLFN(MCIEXE, "SET WIND SPEED 500")

Añadiendo este línea inmediatamente antes de la línea:

nRESULT = CALLFN(MCIEXE, "play wind wait")

También se puede controlar la dirección del path con:

cAVIFile = SYS(2004) + "TEST.AVI" 

Y abrir una instancia del device poniéndole como alias el nombre de 'wind':

nRESULT = CALLFN(MCIEXE, "open " + ;
	cAVIFile + " TYPE AVIVIDEO alias ;
	wind style popup")

Establecer el playback en milisegundos:

nRESULT = CALLFN(MCIEXE,;
 	"SET wind TIME FORMAT MILLISECONDS

nRESULT = CALLFN(MCIEXE, ;
	"PLAY wind WINDOW FROM 5000 TO 0 WAIT") 

Botones Multimedia

Otros de los problemas que se suelen presentar en estas aplicaciones es la implementación de botones con alto contenido gráfico con opciones de rollover, hundido, levantado, desactivado, etc... Todas estas opciones superar las posibilidades del commadbutton y hay que escoger otro sistemas.

Podemos acudir a los controles de Imagen que te permiten poner gráficos y dotarlos de las funcionalidades anteriormente mencionadas.

En un principio estuve trabajando con una clase contenedora y dentro un botón gráfico. La clase contenedora detectaba si el ratón pasaba por ella y le daba tiempo a cambiar el gráfico del botón pero el resultado no era satisfactoria pues si el ratón pasaba demasiado rápido el evento mousemove no se ejecutaba y entonces el botón no cambiaba de forma

Estos controles en combinación con el Timer nos resuelven estos problemas. En un principio era reacion a utizar el Timer pues sobrecarga el procesador y es bastante duro depurar una aplicación con unos cuantos timer activados, pero descubrí que el timer puede estar desactivado (.F.) y sólo activarlo cuando el usuario pasa con el ratón por encima del gráfico con formato de botón que nos interesa activar.

Estos botones a su vez los tenemos de varios tipos:

Tipo1: Las tres posiciones clásicas (normal,rollover,hundido)pero recupera su posición cuando el ratón sale de él.

Tipo2: Las tres posiciones clásicas (normal,rollover,hundido)pero el botón se queda marcado cuando el ratón sale de él.

Tipo3: Las tres posiciones clásicas más la opción de desactivado con lo que tendríamos cuatro opciones.

Pero veamos el código. Unicamente mostraré los Tipo1 y Tipo2 pues el Tipo3 es una variante que se puede controlar, sin problemas, por código:

Pasamos a continuación a la construcción del código que tienes entre los ficheros del mes.

Para poder conseguir todas las funcionalidades deseadas vamos a contruir dos clases. Una clase Timer que se activará cuando el ratón esté por encima y una clase para el gráfico que en principio no hará nada.

Si el uso de las clases siempre es interesante, mucho más en este caso pues los botones que habrá en la aplicación serán numerosos y es especialmente interesante la reutilización de código.

Clase Migráfico

1.- Creamos una clase que vamos a llamar migrafico basada en la clase de Fox Gráficos.

2.- Creamos un método en esa clase llamado onmouseout

Clase MiTimer

1.- Creamos una clase que vamos a llamar Mitimer y que la basamos en la clase Timer de Fox

2.- En el método Timer escribimos el siguiente código:

oToCheck=SYS(1270)
IF TYPE('oToCheck')='O'
	IF !ISNULL(This.ToCheck) AND This.ToCheck.Name <> oToCheck.Name 
		This.ToCheck.OnMouseOut()
		This.ToCheck=.NULL.
		This.Enabled = .F.
	ENDIF	
ELSE
	IF !ISNULL(This.ToCheck)
		This.ToCheck.OnMouseOut()
		This.ToCheck=.NULL.	
	ENDIF
	This.Enabled = .F.
ENDIF	

3.- Creamos un método que vamos a llamar checkforme y escribimos:

LParameters oToCheck

IF TYPE('oToCheck')='O'
	IF !ISNULL(This.ToCheck) 
		IF This.ToCheck.Name <> oToCheck.Name
			This.ToCheck.OnMouseOut()
		ENDIF	
	ENDIF	
	This.ToCheck=oToCheck
	This.Enabled = .T.
ENDIF	

4.- En sus propiedades es especialmente importante poner la propiedad de Enabled a .F. para que no esté disparando continuamente.

5.- La propiedad Interval la reducimos a 50 milisegundos.

6.- Creamos una propiedad que la vamos a llamar Tochek y la rellenamos de momento con un .NULL.

Y ya tenemos casi todo:

Formulario

1.- Creamos un formulario y le ponemos un gráfico basado en nuestra clase Migrafico.

2.- En el método Mousemove escribimos:

This.picture = SET('DEFAULT') + ;
	SYS(2003)+ '\espanoli.bmp'
ThisForm.mitimer1.CheckForMe(This)

3.- En el Método MouseOut escribimos:

this.picture = SET('DEFAULT') +;
 	SYS(2003)+ '\espanold.bmp'

4.- En el Método MouseDown se escribe:

this.picture= SET('DEFAULT') +;
 SYS(2003)+ '\espanol.bmp'

Y ya está.

Para el botón de tipo 2 será necesario usar las mismas clases pero varía ligeramente el código de los métodos:

1.- El método mouseout sería:

IF ! this.picture = SET('DEFAULT') + ;
SYS(2003)+ '\espanol.bmp'
	this.picture = SET('DEFAULT') + ;
SYS(2003)+ '\espanold.bmp'
	thisform.refresh()
ENDIF

2.- El método MouseMove:

IF !This.picture = SET('DEFAULT') + ;
SYS(2003)+ '\espanol.bmp'
	This.picture = SET('DEFAULT') +;
 SYS(2003)+ '\espanoli.bmp'
	ThisForm.mitimer1.CheckForMe(This)
ENDIF
thisform.refresh()

3.- El método MouseDown:

IF this.picture = SET('DEFAULT') + ;
SYS(2003)+ '\espanol.bmp'
	this.picture= SET('DEFAULT') + ;
SYS(2003)+ '\espanold.bmp'
ELSE
	this.picture= SET('DEFAULT') + ;
SYS(2003)+ '\espanol.bmp'
ENDIF