27 marzo 2007

Deslizando imágenes en Flash

Para aprovechar el área de tu animación Flash al máximo (recuerda que la resolución mínima de un usuario vil y mortal es de 800x600 por lo que deberías hacer tus animaciones para esta resolución para que todo el mundo lo pueda ver), existen componentes diferentes que te pueden servir de ayuda.

En este ejemplo voy a usar el componente ScrollPane para mostrar una imágen bastante grande. Estos son los pasos que seguí para hacerlo (acompañado de algunas imágenes chiroliras):
  1. Hice un nuevo documento Flash. Lo "bauticé" scrollpane.fla.
  2. Importé a la biblioteca (library) 3 archivos JPG: foto1.jpg, foto2.jpg y foto3.jpg.
  3. En el primer fotorama de la capa Layer1 le inserté un símbolo Clip de película (movie clip) llamado fotos la cual contiene las tres imágenes todas alineadas en fila. Nótese que el punto de registro (registration mark) está en la esquina superior izquierda. Para alinearlas, usé las herramientas del ventana de alineación (Window-Align). Chécate la figura 1 que está hasta abajo de este post (en esta ocasión se me ocurrió poner todas las imágenes hasta abajo, espero que no te sea inconveniente).
  4. Agrupo las 3 imágenes (Modify-Group o CTRL+G).
  5. Abro la ventana de componentes y abro los componentes de interfaz (Window-Components). Esto lo puedes ver abajo en la figura 2.
  6. Arrastré una copia del componente ScrollPane al escenario de mi animación. Ve la figura 3. Le cambié el ancho a 448 y el alto a 296 (para adecuarse al tamaño del símbolo fotos) y lo centré en la escena pa' que se vea chuvidubis.
  7. Di click con el botón derecho del mouse sobre el icono del símbolo fotos en la ventana de la biblioteca (library) y selecciona la opción Linkage (no sé como se tradujo a la versión en español, será ¿vinculación?). Esto viene en la figura 4.
  8. Aparece la ventana que puedes ver en la figura 5. Aquí selecciono la opción Export for ActionScript (lo cual me permite accesarlo desde otras partes de mi animación como son los controles). Ahora le puedo poner un nombrecito con el que lo puedo vincular al ScrollPane. Yo le puse fotos0, pero, como te has de imaginar, puede ser el nombre que sea.
  9. Ahora selecciono mi ScrollPane y altero sus propiedades, en la parte de parámetros. Hago los siguientes cambios: al parámetro contentPath le escribo fotos0 (el nombre de la "liga" de mi clip de película fotos) para asignar el contenido de fotos al ScrollPane y al parámetro scrollDrag le pongo valor verdadero lo cual me permite arrastrar las imágenes dentro del fotos con mi mouse. Esto se ve en la figura 6.
  10. Ahora todo lo que resta hacer es presionar Ctrl+Enter y ser feliz. El resultado lo muestro en la figura 7.
Espero que esto te haya servido para iluminar tu vasto entendimiento. Seguimos en contacto...

Figura 1. El símbolo fotos

Figura 2. La ventana de componentes

Figura 3. Scene1 con el ScrollPane.

Figura 4. Menú contextual del símbolo fotos

Figura 5. Ventana "linkage" (¿será vinculación?)

Figura 6. Parámetros del ScrollPane

Figura 7. La animación terminada

26 marzo 2007

Animando desde una animación...

Como la idea es hacer que los archivos de Flash que ven los internautas sean lo más pequeños posible, es posible (valga la redundancia) crear una animación con el "esqueleto" de la página y desde esa animación cargar otras animaciones (por ejemplo, las diferentes partes del sitio). Esto lo usan casi todas las páginas hechas en flash. Ayuda a que el usuario no se desespere mientras baja una paginotototota que descarga partes de la página que a lo mejor ni le interesan.

El video explicativo lo puedes bajar aquí (baja los 3 archivos y descomprímelos con el WinRAR en tu computadora) o ver en YouTube aquí (también puse el video al final de este mensaje, por si te da flojera ir al sitio de YouTube). Los archivos con el proyecto están aquí.

Si quedan dudas, avísenme por i-meil o déjame un comentario al final. ¡Hasta la próxima!

25 marzo 2007

ADO 4 - El regreso de las consultas (2)

Ya me puse a chambear para hacer otra consulta leve. Con el mensaje anterior echamos relajo con una consulta que se llama para llenar un ComboBox con un campo de los registros de una tabla. Ahora, siguiendo con el programa para doña Amalia, voy a hacer una consulta y llenaré una ventana con los datos de un proveedor.

Bien, el proyecto, todavía en fase muy lejos de ser la final, que incluye lo que voy a explicar hasta ahorita lo puedes bajar aquí. Voy a ir explicando los pequeños cambios que hice poco a poco, con código y toda la cosa, para que entiendas mejor el código.

Bueno, como estamos continuando con el proyecto de doña Amalia, voy a explicar ahora los pequeños cambios que realicé. Como recordarás del mensaje anterior, ya teníamos una ventana que nos permite consultar por número de proveedor o por nombre del proveedor. Ahora voy a programar el botón Mostrar, que yo lo llamé btnMostrar, para que abra una ventana nueva, frmDatosProveed, con puras etiquetas para mostrar los datos del proveedor. Podría haber usado la misma ventana de los proveedores para la consulta pero, sería mucho relajo porque debería deshabilitar el botón de Altas (ni modo que le piquen, por error o maldad, el botón de Altas para insertar un registro que ya existe).

También decidí cambiar el botón Eliminar a la ventana con los datos del proveedor. Así, primero aseguro que el usuario vea los datos del proveedor antes de matarlo, perdón, quise decir eliminarlo.

Bueno, por lo pronto aquí va el código que llena la ventana frmDatosProveed con la información del proveedor elegido, ya sea por nombre o número. Sin más preámbulos (porque abajo describo y explico el código), ahi va...


Tal vez parezca mucho rollo complicado, pero no es así. En realidad es muy sencillo. Comienzo revisando las opciones: si seleccionó la primera opción, la de buscar por número de proveedor (optNoProveed) y el número que tecleó es correcto (para esto uso la función Val que me convierte una cadena a un número). En caso que esto sea cierto, llena la propiedad CommandText con la instrucción SQL que busca todos los registros que sean igual al número escrito por el usuario: SELECT * FROM Proveedor WHERE NoProveed=" & txtNo.

Si esto no se cumple, o sea, que seleccionó optNoProveed y no escribió un valor válido para el número de proveedor, le mando un mensaje de error, pongo el cursor en txtNo para que escriba un valor válido y me excito de la función (se oye feo, pero digo que me excito porque estoy usando el Exit).

Si ninguno de los anteriores se cumple, quiere decir que seleccionó optNombre y no tengo que revisar el valor porque es un Dropdown List (o sea que no deja que el usuario escriba algo que no venga en la lista) y lo inicialicé seleccionando el primer proveedor de la lista (si tienes dudas de cómo hacerlo, lee mi mensaje anterior). Entonces lo que hago es igualar a cmdCommand.CommandText a la instrucción SQL que regresa todos los campos del registro cuyo nombre es igual a lo que está en cboNombres (eso lo saco con el cboNombres.List(cboNombres.ListIndex)).

Una vez que ya asigné el comando SQL correcto, paso a abrir el RecordSet (tblTable) que tendrá el registro que ando buscando. Esto lo hago con el tblTable.Open que ya expliqué previamente.

Si la tabla no llegó al final del archivo, lo que debería suceder siempre, cargo a la memoria una nueva forma que hice para mostrar datos, llamado frmDatosProveed. Esto lo hago con la instrucción Load frmDatosProveed. Una vea hecho esto, frmDatosProveed ya existe en la memoria, pero el usuario todavía no lo ve. Entonces lleno las etiquetas (lblNo, lblNombre, lblWeb, lblFax, lblTel y lblIMeil) con los valores de los campos del registro encontrado (tblTable!NoProveed, tblTable!Nombre, etc.). Al terminar de llenar las etiquetas, dejo que el usuario vea la ventana (usando el método Show) y todo es felicidad.

Si de pura casualidad al abrir la tabla llega luego luego al final (tblTable.EOF), (por ejemplo, si el número de proveedor no existe) quiere decir que no pudo encontrar al registro y le mando un mensaje de error.

Para terminar, cierro la tabla para poder usarla de nuevo en cualquier otro lado del programa.

Pero, ¿cómo se ve esta ventanita chuvidubis llamada vulgarmente como frmDatosProveed? Así se ve en la vista diseño:


Y así se ve a la hora de ejecutar el programa:


Ese fue la función más trabajosa, bueno la que hace todo el trabajo. Solo nos resta cerrar la ventana. Esto lo hago en la función btnAceptar con este código que se ejecuta cuando hacen click sobre el botón:


Tal vez ese sea el código más complicado de esta etapa. Ahora, ¿qué sigue? Probablemente programaré el botón de Eliminar (btnEliminar), pero ya veremos luego. ¡Hasta la próxima!

ADO 3, consultando datos 1

Sé que el título parece marcador final de un partido de fútbol, pero no es así. Todo se trata del famoso ADO combinado con VB 6.0 y SQL.

Hace algunos mensajes, escribí acerca de la manera de trabajar con ADO. Hablé (bueno, escribí) acerca de la manera de añadir referencias a un proyecto VB 6.0, declarar los objetos como globales en un módulo (cosa que nos va a ahorrar muchas líneas de código más adelante), inicializar los objetos al arrancar el programa y hasta insertamos un registro con un comando SQL. Aquí voy a seguir con el mismo proyecto, ahora le agrego una consulta. Probablemente para poder entender este mensaje, tienes que leer el anterior. Ese lo puedes leer aquí y si no te quedó claro, el primer artículo de esta serie de ADO lo puedes leer aquí.

Pues bien, siguiendo con el proyecto del sistema para la taquería de doña Amalia, proyecto que puedes bajar, en la fase actual que no está terminada del todo, pero que tiene lo que voy a explicar aquí, lo puedes bajar en este sitio.

Lo que voy a hacer en esta parte del proyecto es agregar una ventana que me permita buscar a un proveedor (consulta) ya sea por número de proveedor (mi llave primaria de la tabla Proveedor) o bien que pueda escribir el nombre del cliente. Pero como eso de escribir el nombre del cliente puede ser confuso, voy a poner un ComboBox con los nombres de todos los proveedores, ordenados alfabéticamente, para que seleccione el que desea consultar. Todavía no busca proveedores, solo abre una ventanita que inicializa la lista de proveedores. Sin embargo, de la misma manera en que se inicializa el control con los proveedores se pueden también generar consultas para hacer casi lo que quieras (menos conquistar el mundo, pero tal vez algún día...).

Para empezar, se necesita el código para abrir la nueva ventana que acabo de crear. Sé que esto no tiene ningún chiste. Solo llamo al método Show de frmBuscaProveed (así nombré la ventana, o Form, que tiene la lista de proveedores). Si quieres más datos acerca del método Show, dale click aquí. Este el el código, puesto en el botón que llamé btnBuscar:


Este código hace que aparezca esta ventana (aquí está en el modo de diseño):


Ahora sí, voy a escribir el código que va a llenar el ComboBox (que nombré cboNombres). Aquí pongo el código y abajito explico todo a detalle (bueno, espero que con el detalle suficiente).


Como hicimos al insertar un registro, a la propiedad CommandText de mi objeto Command (en mi caso, se llama cmdCommand) le asigno la instrucción SQL que va a llevar a cabo, en este caso: SELECT Nombre FROM Proveedor ORDER BY Nombre. Esto me devuelve todos los valores del campo Nombre de la tabla Proveedor ordenados por el campo Nombre. ¿Fácil? Ya lo creo.

A diferencia de insertar registros, cuya instrucción, INSERT INTO, no devuelve valores, tengo que abrir los resultados en un objeto RecordSet (o sea, la tabla) que en este proyecto se llama tblTable. Si una instrucción SQL no devuelve registros, uso el método Execute del objeto Command, pero si el una instrucción SELECT, tiene que abrirse en una tabla. Para eso uso el método Open de un RecordSet. Así como lo escribí lo vamos a escribir de forma idéntica siempre (bueno, si le cambiaste le nombre a las variables, serí lo único que cambiaría). Pero por aquello del no te entumas, voy a explicar la sintaxis completa.

cmdCommand se refiere a mi objeto Command que tiene la instrucción SELECT que deseo ejecutar. Si no quisiera usar el objeto Command, podría escribir la cadena con la instrucción SQL directamente allí (encerrado entre comillas, obviamente). Luego dejo el siguiente parámetro en blanco (por eso ves repetidas dos comas) porque tendría que especificar la conexión deseada (ActiveConnection). Esto lo usaría en el caso que escribiera el comando SQL como el primer parámetro, pero como estoy usando el objeto Command, la cual ya tiene una ActiveConnection asignada.

adOpenStatic le dice al DBMS que solo voy a hacer una consulta, es decirt, quiero una copia estática de los datos requeridos. En lugar de este parámetro, hay otros que permiten modificar los datos de la tabla desde esta consulta, pero no es nuestro caso. El penúltimo parámetro (que es el último que estoy usando), adLockBatchOptimistic, especifica la manera en que se van a bloquear los registros. Con esta constante, le estoy diciendo al DBMS que lo resuelva de la mejor manera en que crea conveniente. Pero, ¿qué es esto de bloquear registros? Imagínate que tu sistema, cuya base de datos está en un servidor accesible por varios clientes, tiene un registro de una tabla que quieren modificar dos personas al mismo tiempo. Vas a tener un pequeño problema porque si uno quiere modificar el campo RFC, por ejemplo, y otro quiere modificar el campo Tel al mismo tiempo, el DBMS tiene que decidir quién puede cambiar, o si ambos pueden hacerlo, o que forma resolver la bronca. Algunas DBMSs viejitos bloquean toda la tabla, o sea que cuando yo altero un registro, nadie puede actualizar nada de la tabla aunque no estén trabajando en el mismo registro que yo. Otros bloquean el registro (nadie puede modificar el mismo registro que yo, aunque puede modificar otros de la misma tabla). Otros más bloquean solo el campo que está siendo alterado (varios pueden modificar datos del mismo registros con tal que no sean el mismo campo).

El último parámetro, el que omití, es para poner constantes que permiten opciones avanzadas, Nosotros, pese a lo avanzados que estamos, no lo vamos a usar.

Eso fue lo más difícil. Después de esto, comienzo a deambular por un ciclo While que me permite ir de registro en registro hasta el final de la tabla (cuando se cumpla la propiedad EOF o End Of File, fin de archivo). Dentro del ciclo, uso el método AddItem del ComboBox, en mi caso llamado cboNombres, para agregar el nombre al ComboBox. Después de esto, le indico que avance al siguiente registro de la tabla con el método MoveNext del RecordSet.

Al terminar de agregar todos los nombres (cuando se la propiedad EOF es verdadero), cierro el RecordSet (¡que nunca se te olvide cerrarlo!) y le digo a cboNombres que despliegue el elemento de la lista de nombres (o sea, el primero) usando la propiedad ListIndex del ComboBox.

Una nota adicional. Cuando estás trabajando con ComboBoxes con registros, no quiere que el usuario pueda teclear lo que se le pegue la gana, así que puedes cambiar la propiedad Style sea igual a 2 (o sea, Dropdown list), el cual no le permite al usuario teclear nada que no esté en la lista. Y luego, al cambiar la propiedad ListIndex como hice arribe, te evitas la flojera de tener que validar en otro lado si la lista tiene un elemento seleccionado o no.

Ok, ya pasó lo peor (o lo mejor, dependiendo de tu punto de vista). Ahora voy a jugar con mis OptionButton, los cuales me permiten elegir una u otra búsqueda (o sea, por número o nombre). Es buena idea usar OptionButtons para esto porque al asignar la propiedad Value a verdadero en uno de ellos ya garantizas que hay uno elegido, cosa que se te simplifica a la hora de validar. Pero para no confundir al usuario, o sea a doña Amalia, vamos a bloquear cboNombres desde el principio y dejar habilitado txtNo (caja de texto donde van a escribir el número de proveedor). Si seleccionan la opción de búsqueda por nombre, optNombre, habilita cboNombres y deshabilita txtNo. Este es el código:


Dejé al final el código que puede ser el más complicado, pero estoy seguro que tu, querido lector, no tendrás problemas en resolver. Se trata del código del botón Cancelar (btnCancelar), la cual cierra la ventana frmBuscaProveed sin hacer ninguna consulta. Para esto, lo descargo, lo elimino de la memoria. Para esto sirve la función Unload y lo escribiría así:


¿Por qué decidí quitarlo de la memoria y no simplemente esconderlo (con el método Hide)? Es que quiero que cada vez que se cargue esta forma a la memoria se actualice cboNombres (o sea que ejecute la función Form_Load donde inicializo cboNombres).

¡Listo! Creo que expliqué todo, pero si tienes dudas, no dudes (valga la redundancia) en mandarme un i-meil o dejarme un comentario aquí. Más adelante terminaremos esta ventana de búsqueda para que muestre los datos del proveedor, así que no te lo pierdas y mantente al tanto de mi blog.

¡Hasta la próxima!

18 marzo 2007

Si vas a tardar, por lo menos avisa...

No hay cosa más desesperante para un internauta que querer ver una página que tarda mil horas en bajar. Y peor tantito si ni siquiera sabe si es que no se ha interrumpido la descarga, cuanto tiempo va a terminar, etc.

Es por esto que Flash tiene la infraestructura necesaria para poder informarle al usuario que se está cargando la página con un montón de instrucciones ActionScript que le pueden brindar toda la información necesaria para que no se desespere (o por lo menos se aguante hasta que acabe). Así que ahora voy a discutir la manera en hacer esto.

Para explicar como se hace este procedimiento, llamado "preloader" por algunos doctos en el lenguaje del país de las hamburguesas y la Coca-Cola (o simples malinchistas que quieren apantallar), hice cuatro proyectos de Flash:
  1. El primero solo muestra un texto que dice "Cargando" con puntos suspensivos que van aumentando. Descárgalo aquí.
  2. El segundo quita esa animación chafa y hace un símbolo clip de película (o movie clip) que se encarga de parar la ejecución de la película y mostrar el porcentaje cargado y los bytes cargados vs. los totales. Descárgalo aquí.
  3. El tercero solo agrega a ese símbolo una barrita que va avanzando según el porcentaje descargado. Descárgalo aquí.
  4. El cuarto solo agrega el cálculo del tiempo que falta para descargar todo. Descárgalo aquí.

Lo que tienen en común todos es que sirven de preludio para una animación que carga varias instancias de un símbolo que tiene un cuate que camina (o corre, no entendí como está esa movida) y de fondo tiene parte de una canción (parte del soundtrack de la película Matrix). El caminador fue muy sencillo hacerlo: bajé de internet el "sprite" de un monito, separé los cuadros usando Photoshop, los importé a la biblioteca de mi proyecto Flash e hice un símbolo clip de película (movie clip) que tiene una animación donde cada cuadro tiene una de las imágenes cortados.

Voy a ignorar todo el rollo de la animación de los proyectos como tal para poder concentrarme en el preloader (ya me gustó la palabrita, pero conste que no es por malinchista, jeje). Mi animación consta de muchas capas (layers), pero las que nos interesan son dos: Acciones y Preloader. Acciones tiene 6 frames y Preloader tiene 5. Así se ve una parte de mi pantalla de la línea de tiempo:


Primero voy a mostrar lo que tienen los 4 fotoramas clave (keyframes) de la capa Preloader. Aquí están en su debido orden, bien ordenados como se ordena al ordenar (o sea, primero va el contenido del fotorama 1, luego el 2, etc.):


¡Listo! Fácil, ¿no? En el primer fotorama (frame) pongo el texto "Cargando" y en cada uno de los siguientes le iba aumentando un punto suspensivo. Ahora, como pudiste observar, mi capa (layer) Acciones tiene código en el primer fotorama. El código usa una variante del if llamado ifFrameLoaded que sirve para ver si ya se ha cargado un fotorama especificado (en nuestro caso, con el _root._totalframes estoy verificando si ya cargó el último fotorama). En el caso que ya haya terminado de cargar todo, le digo que comience a m,ostrar lo que hay desde el fotorama etiquetado como "inicio" (abajo escribo una notita sobre la ubicación de esta etiqueta). El código del primer fotorama de la capa Acciones se ve así:


El otro pedacito de código que usé en la capa Acciones fue la del fotorama 5 donde le digo que se regrese al primer fotorama a seguirle (o sea, cierro un ciclo que va a seguir tocando hasta que se cumpla la condición ifFrameLoaded . Para esto, basta escribir una sola línea de código:


Lo único que resta decir de la capa Acciones es que el fotorama 6 tiene una etiqueta, "inicio", para que el código explicado con anterioridad sepa a a partir de que fotorama continuar después de haber cargado todo a la memoria.

Con eso ya la armamos grave para el primer proyecto, el más sencillito. Para probar este y todos los proyectos que voy a explicar aquí, presiona CTRL+ENTER y de la ventana que aparece, ve al menú View->Simulate Download para que muestra la animación como si la estuvieran bajando de internet (la velocidad a la cual quieres simular lo puedes editar en View->Download Settings).

Ahora va el proyecto 2. Aquí hago algunos cambios importantes. En primer lugar, elimino la capa Acciones y renombro el Preloader a PreCargador (pa' que vean que se me quita lo malinche, jeje). En esta capa solo pongo una cosa: un símbolo de clip de película llamado preloader (y vuelve la malinche). La línea de tiempo se ve así:


Ignora las capas que están arriba de PreCargador, que son las mismas que el en proyecto 1. Ahora, voy a analizar lo que contiene el símbolo preloader que es quien hace toda la chamba. Al editar el símbolo, se ve así:


Pero, ¿qué es esto? Fíjate primero en la línea del tiempo. Tengo dos capas: Código, que contiene el código ActionScript que va a hacer todo el teje y maneje del buisness y la capa Resto que contiene, buen, el resto. La capa del resto está bien fácil. Solo tiene dos cajas de texto donde voy a desplegar los datos acerca del porcentaje de lo que se ha cargado (txtProgreso) y la cantidad de bytes cargados y totales (txtBytes). Lo único que tienen de "raro" es que en las propiedades especifiqué que son de tipo Dynamic Text (ver imagen abajo). Esto le dice a Flash que ese texto lo voy a modificar usando ActionScript.


Una pequeña nota para optimizar la película. Es posible, para mi texto (sobre todo si es dynamico) definir los caracteres que quiero que se incluyan en mi proyecto. Es decir, en lugar de agregar todo el alfabeto completo de un tipo de letra en el archivito Flash, puede solamente agregar unas cuantas letras. Esto lo puedes hacer presionando el botón Embed de la barra de propiedades del tipo de letra:


Al presionar este botón aparece una ventana como la que sigue.


En la lista superior puede especificar qué símbolos incluir y, en dado caso que necesitas algo de más, puedes escribirlos en la cada de texto inferior (en mi caso agregué un espacio y el signo %). Abajo le da el número de símbolos (glyph) que va a incluir en el proyecto. Así, en lugar de guardar todo el alfabeto completo de un tipo de letra determinado (256 símbolos), solo estoy guardando 12 (10 dígitos numéricos, el espacio y el signo "%"). Con esto se ahorra un poco de espacio en el producto final.

Sigamos, pues, con dar información al usuario acerca de la razón de la tardanza. Todo el código interesante está en la capa Código. Este es el código guardado en el primer fotorama de esta capa:


El stop() común y corriente seguramente lo conoces en demasía, pero lo interesante es que le agrego al principio _root. Al decirle _root.stop(), le estoy diciendo a Flash que haga la acción de parar toda la animación (stop()) en la primera escena. No olvides que estamos dentro de un símbolo que, para funcionar con la línea del tiempo de la escena 1, tiene que hacer referencia a él con el _root. Si quisiera, en lugar de _root, podría ponerle _parent que quiere decir que pare todo lo que está haciendo la escena "padre" (o sea, la escena que contiene a este objeto).

Ahora vámonos al fotorama 2, el cual contiene todo el código chuvidubis. Aquí pongo el código y abajito lo explico:


Las primeras 5 líneas estoy inicializando variables que voy a usar. Uso las funciones de Flash getBytesLoaded y getBytesTotal para saber el número de bytes que he cargado a la memoria y el número total de bytes que tiene el archivo, respectivamente. Los divido entre 1024 para reportar el número de kilobytes (algo que se me hace más interesante que los puros bytes a secas). Con una simple resta calculo el número de kilobytes que faltan bajar. Después de esto, calculo el porcentaje de lo que lleva y el que falta (si no te recuerdas de la manera de sacar porcentajes, puedes ir sacando tu libro de 5to año de primaria y repasarlo tantito). Las dos líneas que siguen le asignan valor a los textos dinámicos explicados anteriormente: txtProgreso y txtBytes.

Al final hace la comparación que regula hasta cuando se va a seguir usando esta animación. Si lleva menos del 99% del archivo bajado (valor que calculé en la variable porCientoCargado), vuelvo a tocar la escena 2 de este símbolo. En caso contrario, toca lo que hay en la escena 1 (_root) a partir del fotorama 2.

¡Listo! De esta manera tienes texto que le indica al usuario cómo va la movida. Al probar tu película (diciéndole que simule la descarga como se dijo antes), se debería ver algo así:


¡Listo! Con eso ya tenemos el texto. Ahora vamos a hacerlo más gráfico. A la capa Resto le voy a agregar un rectángulo abajo del texto (este es solo una prueba: tu lo puedes poner en vez de las letras, arriba, abajo, sobre ellas, etc.). Selecciono el relleno del rectángulo y lo hago un símbolo Clip de película. Ese símbolo, cuya instancia llamé barraCarga (ver imagen abajo), lo incluyo en el símbolo preloader, donde estoy trabajando, y voy a usar la propiedad _xscale que tienen los símbolos para ajustar su tamaño. Sé que existe también la propiedad _width, pero se me facilita más trabajar con la escala que es un porcentaje (y como yo ya calculé el porcentaje, todo sale de maravilla).


Al código del fotorama 2 solo le agrego una línea nueva: barraCarga._xscale = porCientoCargado; Recuerda que porCientoCargado es una variable que calcula el porcentaje de lo que se ha cargado ya en la memoria. Para no dejar las cosas a medias, el código en el fotorama 2 de mi símbolo preloader es así:


¡Listo! Ahora le estoy dando tanto los datos como texto y de manera gráfica con una barrita que se va llenando. Para pasar al último proyecto, voy solamente a agregar otro texto dinámico abajito de la barra llamado txtSeg el cual va a desplegar el número de segundos faltantes para que comience el show. Para esto, voy a usar la función getTimer la cual almacena el número de milisegundos transcurridos desde que arrnacó la animación. El el código que he ido cambiando tantas veces en el paso de estos proyectos, lo voy a editar una vez más para agregar un par de líneas. Comienzo creando otra variable donde voy a calcular el número de bytes por segundo de la transmisión actual. Esto se calcula en base al número de bytes que se han cargado desde que se arrancó la animación (si no recuerdas como, ahi revisa tus libros de matemáticas de la primaria). Esta línea es así:

kBytesSeg = kBytesCargados / (getTimer() / 1000);

Luego calculo el tiempo que falta por cargar todo con esta instrucción:

tiempoRestante = kBytesFaltantes / kBytesSeg;

Y al final, desplego los valores de los tiempos así:

txtSeg.text = Math.floor(tiempoRestante) + " segundos restantes"

Por todos lados estoy usando la función Math.floor para que me devuelva la parte entera de un número. Si no, se ve medio feo que diga que está bajando 89.907665 % del archivo o que faltan 2.34127 segundos para que termine de cargar la animación.

Creo que con estos ejemplos se entiende como hacer un preloader en Flash. Si tienes dudas, deja un comentario o mándame un emilio y trataré de contestarte a la brevedad. ¡Nos vemos!

14 marzo 2007

Sonándose a Flash

Flash no es un programa editor de sonido ni de secuencias musicales (si quieres alguno de estos, consigue el Adobe Audition y/o el Fruityloops), sin embargo, hay cosas interesantes que puedes hacer con él.

Para esto, hice un pequeño video de un documento en Flash que hace una banda sonora. Los archivos que forman el video (son 7) los puedes bajar aquí (baja todos los archivos en esta carpeta a tu computadora y descomprime uno de ellos con WinRAR para que tengas todo el video). Viene todo narrado, por lo que no creo que tengas broncas en entenderle. Si quieres el archivo del proyecto para verlo con calma, lo puedes bajar aquí.

Espero que les sea útil. ¡Nos vemos!

El ADO Contraataca: inicializando mis objetos y metiéndoselas a la tabla

Ahora que ya comenzamos a hacer un sistema que usa VB 6.0 y ADO para hacer un programita simple, vamos a dar el siguiente paso. En mi mensaje anterior, hablé (bueno, escribí) acerca de la manera de agregar la referencia a los objetos ADO (ActiveX Data Objects), declarar objetos globales de tipo ADODB.Connection, ADODB.Command y ADODB.Recordset, y uno que otro detallito más (si no lo leíste, lo puedes leer aquí).

Hasta allí empezaba la cosa bien, pero nos quedamos a medias (bueno, tampoco es mi intención abarcar todo lo faltante en este mensajito). Ahora voy a hacer dos cosas: voy a inicializar mis objetos ADO desde la subrutina Form_Load() de la primera ventana que abre mi aplicación y voy a programar un botón que da de alta un registro en una tabla. Si quieres el código completo de lo que va hasta ahorita (archivos de formas, de proyecto, íconos y una que otra chuchería más), lo puedes bajar aquí.

Primero, lo primero. El primer form (que yo bauticé como frmPrincipal en lugar de aburrido Form1 que le pone VB por default) tiene una serie de botones que abrirán otras ventanas que llevarán a cabo todo lo que quiere hacer doña Amalia en su taquería. Esta ventana, en mi ambiente de diseño de VB 6.0, se ve así:


Intenté hacerlo lo más sencillo pensando en que los que lo usarán son trabajadores de una taquería, con botones grandes que sean fáciles y rápidos de apretar que tienen iconos. Además tienen ToolTipText, una propiedad de casi todos los controles, para que aparezcan mensajitos explicativos de cada uno y son accesibles presionando la tecla ALT más el de la letra subrayada que tiene cada botón, la cual la asigné anteponiendo el ampersand (&) antes de la letra subrayada.

Dejando esto a un lado, vámonos al código. Como esta es la primera ventana que se carga a la memoria, en cuanto se cargue quiero que inicialice mis objetos ADO. Para esto, escribí este código en la subrutina Form_Load de esta ventana. El código es este:


Con el Set creo un nuevo objeto (lo estoy usando tanto para el Connection, el Command y el Recordset). El ConnectionString es una propiedad que tiene el objeto ADODB.Connection para definir la base de datos a la que se va a conectar y quién es el proveedor del servicio. En nuestro caso, estamos usando una base de datos hecha en Access que se llama Tacos.mdb. Al rato subo un mensaje donde explico mejor como se usa, pero si vas a usar una base de datos de Access, copia el código tal cual. Si te fijas, uso la propiedad App.Path para determinar desde qué carpeta está ejecutándose el programa. El archivo Tacos.mdb lo voy a guardar en el mismo lugar del ejecutable y de esta manera, no importa donde se instale mi programa, va a poder encontrar mi base de datos.

Una vez usado el ConnectionString para decirle con quién conectarse (Data Source) y quién los va a conectar (Provider), abro la conexión (Open). Con esto termino de inicializar mi conexión y puedo usarlo al crear mi objeto Recordset. Después de crearlo (con el New), le digo que la conexión que va a usar es la que acabo de inicializar, en nuestro caso, se llama conConnection (con el ActiveConnection).

Al final estoy creando un objeto Recordset (con el New) y le estoy diciendo que todo el trabajo "pesado" (filtrar datos, unir registros, ordenar, etc.) lo haga en el servidor de la base de datos (CursorLocation=adUseServer). La otra opción, que no recomiendo, es decirle que todo el trabajo lo hace la máquina donde está trabajando el usuario (CursorLocation=adUseClient). No lo recomiendo porque, en casi todas las ocasiones, el servidor de la base de datos es una maquinotototota choncha que tiene mayor capacidad de procesamiento que la PC de un mero mortal.

En fin, con eso termino la inicializadera. Ahora voy a proseguir a insertar un registro desde mi aplicación VB 6.0 por medio del objeto ADODB.Command. Esto lo voy a hacer en la ventana de Proveedores (frmProveedor) que se ve así en la vista de diseño:

Bueno, todavía no decido en un icono chuvidubis para el botón Agregar, pero luego que halle uno, se los paso. Pero eso es lo de menos, ahora nos interesa lo que se puede hacer con ese botón. Por esto, el código relacionado a este botón, que se ejecuta cada vez que un usuario de click sobre él, es este:


¿Se ve medio confuso? ¡No te apures que no lo es tanto! Sólo que vayámonos poco a poco. Para empezar, si no escribe nada en la caja de texto donde va el nombre (que yo nombré txtNombre), le marca error y sitúa el cursor en esa caja para que el usuario le teclee el nombre bien. Había puesto una condición que simplemente viera si no habían escrito nada (o sea, If txtNombre="" Then), pero un alumno, el buen Trank, me sugirió que validara también si da un espacio, cosa que sería válido si hubiera usado el If original. Luego entonces, de manera rauda y veloz, usé la función Trim para eliminar todos los espacios en blanco antes y después de una cadena. Si solo dió puros espacios, de todos modos marca error de nombre inválido.

Si este no es el caso, supongo quetodos los otros campos son opcionales. Ahora sí va lo único que aparenta ser difícil, pero que una vez que le agarres la onda, vas a ver que es sencillo. Todos los comandos SQL que le vamos a enviar a nuestra base de datos por medio de la conexión es usando la propiedad CommandText del objeto ADODB.Command. A esta propiedad se le asigna una cadena que contenga una instrucción SQL válida. Una vez aclarado esto, pasemos a ver que instrucción SQL necesito usar.

La instrucción para insertar un registro en una tabla en SQL es INSERT INTO, cuya sintáxis es así:

INSERT INTO tabla (lista de campos) VALUES (lista de valores)

Por ejemplo, en mi tabla, supongamos que quiero dar de alta a un proveedor. Entonces podría escribir la siguiente instrucción SQL:

INSERT INTO Proveedor (Nombre, Tel, Fax, Email, Web) VALUES ("Textiles Alfonso", "3635-3990", "8111-1112", "http://www.telasponcho.com")

Esto es tal cual lo que hago en mi código, con una pequeña diferencia. En mi programa, tanto como "Textiles Alfonso", "3635-3990", "8111-1112" y "http://www.telasponcho.com" están guardados en txtNombre, txtTel, txtFax, txtEmail y txtWeb, respectivamente. No puedo escribir esta instrucción:

INSERT INTO Proveedor (Nombre, Tel, Fax, Email, Web) VALUES ("txtNombre, "txtTel", "txtFax", "txtEmail", "txtWeb")

porque no tengo un cliente que se llame txtNombre ni su teléfono es txtTel. Lo que quiero es lo que está almacenado en txtNombre, txtTel, etc.

No hay que perder de vista que la propiedad CommandText es de tipo cadena, por lo que voy a armar una cadena de texto que tenga la instrucción tal y como quedar. Un operador básico para armar cadenas es el ampersand (&) el cual une (dicho elegantemente "concatena") dos cadenas para formar una sola. Y si después del ampersand dejo un espacio y escribo un guión bajo (_) quiere decir que puedo seguir concatenando la cadena que viene en el siguiente renglón. Por ejemplo, "Tony " & " Valderrama" sería igual a "Tony Valderrama". Usando esto, puedo armar mi cadena de la siguiente forma: cmdCommand.CommandText = "INSERT INTO Proveedor" & _ " (Nombre, Tel, Fax," & _ " Email, Web) VALUES ('" & _ txtNombre

almacenaría la cadena

INSERT INTO Proveedor, Tel, Fax, Email, Web) VALUES ('Textiles Alfonso

Fíjate que alrededor de valores que son texto le estoy poniendo apóstrofes (') para delimitar cadenas DE LA INSTRUCCIÓN SQL. Usa las comillas (") para delimitar cadenas de VISUAL BASIC.

Siguiendo con nuestro ejemplo anterior, todavía no está cerca de estar terminada. Siguiendo con el merequetengue de ir explicando paso a paso esa instrucción, le agregaría al final un & "','" de la siguiente manera:

cmdCommand.CommandText = "INSERT INTO Proveedor " & _ "(Nombre, Tel, Fax," & _ " Email, Web) VALUES ('" & _ txtNombre & "','"

Esto me almacenaría en la cadena esto:

INSERT INTO Proveedor, Tel, Fax, Email, Web) VALUES ('Textiles Alfonso','

¿Ves? Cierro el texto Textiles Alfonso con apóstrofes para indicar que es un tipo de dato cadena o texto y no se haga bolas. Recuerda que los números no llevan.

Siguiendo esta lógica, podrás imaginar que esta instrucción completa

cmdCommand.CommandText = "INSERT INTO Proveedor " & _ "(Nombre, Tel, Fax," & " Email, Web) VALUES ('" & _ txtNombre & "','" & txtTel & "','" & _ txtFax & "','" & txtEmail & "','" & txtWeb & "')"

Nos devolvería esta cadena:

INSERT INTO Proveedor (Nombre, Tel, Fax, Email, Web) VALUES ('Textiles Alfonso', '3635-3990', '8111-1112', 'http://www.telasponcho.com')

¡Listo! Allí está una instrucción SQL correcta almacenada en la propiedad de mi objeto Command. Ahora le tengo que decir que ejecute esa acción mediante el método Execute (cmdCommand.Execute) y todo está listo.

Todavía falta mucho por hacer y aprender, pero por lo menos están los primeros pasos. ¡Nos vemos en la próxima!

09 marzo 2007

Flash: ActionScript II

¡El ActionScript ataca de nuez! Ahora hice un proyecto diferente, desarrollado en dos etapas, que muestra como funciona el uso de variables y las condiciones if.

En este mensaje voy a hablar de la primera etapa. La idea es poner en la pantalla una ventana que tenga una carita en medio de dos botones, una que dice mejor y otra peor. Al presionar estos botones, la carita va a cambiar de sonrisa a tristeza. Sé que no es una obra de arte, ni una aplicación compleja y digna de su intelecto, pero espero que se entienda.

En el video se narran todos los pasos, pero a grandes razgos la animación tiene 3 símbolos: gráfico que es un rectángulo que no sirve de gran cosa (es la imagen que usa el botón), un botón que solamente cambia el brillo si pasa el cursor del mouse sobre él y un clip animado de la carita. La carita consta de 3 capas: una de la cara (un círculo amarillo con contorno negro), la de los ojos (dos líneas negras) y el de la boca. La boca consta de 15 fotoramas (frames) que tienen una interpolación de forma (shape tween) que lo cambia de contento a triste. En los fotoramas clave (donde está contento, neutral y triste) les puse nombre para poder luego "tocarlo" desde esos fotoramas (frames).

Creo una instancia del símbolo de la carita a mi escena y le pongo un nombre para poder después identificarlo y decirle que haga tal o cual cosa. Imagínate que quisieras hacer tal o cual cosa con alguien y no te supieras su nombre. No creo que te haga mucho caso si le gritas "Hey tu, ven". En fin, en esta animación le puse el nombre de CaraFeliz.

Acto seguido en el primer fotorama (frame) de la escena, le doy un stop() para que no intente seguir tocando más allá de lo que se tiene y le digo que ponga la carita en el fotorama etiquetada como neutral (con el this.CaraFeliz.gotoAndStop()).

Bien, no escribo más porque en el video va explicado. Los archivos comprimidos que contienen los dos videos los puedes descargar aquí y aquí.

Falta todavía mucho por hacer con ActionScript, pero creo que con esto ya puedes hacer algo emocionante y creativo. ¡Hasta la próxima!

06 marzo 2007

Flash: ActionScript I

La vida sería demasiado aburrida si no hubiera acción. Entre más inteligente sea la acción, tendrás mejores resultados. Esto se aplica en todos lados, por ejemplo, si decides llevarle flores a tu chica ideal, es más probable que te pele a que si le lanzas un piropo callejero, vulgar y soez.

En la computadora es básico y fundamental, nuestro deber y salvación (salvación de caer en errores gachos) saber realizar acciones inteligentes. En este caso, que estamos hablando en este "post" de mi blog de Flash y ondas por el estilo, vamos a usar el lenguaje de programación que viene incluido con él. Este es el ActionScript. No voy a redundar mucho en una explicación larga, tediosa, aburrida y por demás (si quieres saber más acerca de esto, dale click aquí).

Aquí les dejo un proyecto, que puedes bajar aquí, muestra el funcionamiento de los botones y fotoramas clave (keyframes) con ActionScript. Solamente en estos dos lugares se puede insertar código. El ejemplo tiene dos botones (hechas con imágenes que hice en Photoshop), dos escenas y, según el botón presionado, salta a una u otra parte dentro de la segunda escena.

El video está narrado con una voz varonil y seductor que explica todo lo que va sucediendo. Espero que sea explicación suficiente. Si tienes dudas, déjame un comentario y me pongo en contacto contigo. Los archivos que forman este primer video (son 4) lo puedes bajar aquí (baja todos los archivos en esta carpeta a tu computadora y descomprime uno de ellos con WinRAR para que tengas todo el video).

Después de lo que muestra este video, le hice un par de mejoras. Le agregué a la segunda escena unas imágenes de un niño y una niña y los acomodé de tal forma con un botón atrás que hacía que abriera el navegador de internet y fuera a una página güev para niñas o para niños, según las preferencias sexuales de usuario (que se entienda: al decir preferencia sexual me estoy refiriendo a las páginas que los gusta ver a las personas de corta edad de uno u otro sexo). Los archivos de ese video (la segunda parte, que son otros 4 archivos) lo puedes bajar aquí o ver en YouTube abajo o en este URL: http://www.youtube.com/watch?v=WzwiQG2IOPY.

¡Hasta la próxima!

04 marzo 2007

Poniéndonos las máscaras, parte III y final

Para ahorrarme la tecleadera (y de paso a ti la leidera), hice este video que usa una máscara conformada por texto y hace que se vea una imagen que se mueva atrás de él. Además le añadí una capa con el contorno de las letras para que se vea más chuvidubis. Los archivos de flash los puedes bajar aquí y los 3 archivos que conforman el video lo puedes bajar aquí (baja todos los archivos en esta carpeta a tu computadora y descomprime uno de ellos con WinRAR para que tengas todo el video).

También hice otro similar que usa un rectángulo con un degradado en lugar de la imagen del ejemplo anterior. Si lo quieres ver, puedes bajar los archivos aquí.

Ahora en Flash, tendremos que adentrarnos más a los rincones recónditos del ActionScript para poder hacer cosas más interactivas y emocionantes. ¡Hasta la próxima!

02 marzo 2007

Máscaras, parte II

Antes hablé del uso de máscaras en Flash. Ahora voy a dar otro ejemplo.

En este, vamos a simular una luz que va alumbrando un letrero en una pared. Los pasos a seguir son estos:
  1. Crear una nueva película.
  2. Cambiar el color de fondo a la película (de hecho, en el video vas a ver que primero le puse morado, pero luego recordé que la noche es oscura, negra, así que más adelante lo cambié).
  3. Usando la herramienta de texto, escribí una frase en una capa llamado Texto.
  4. Agrega otra capa, llamado Luz. En ella dibuja un círculo que sea un poquito más grande que el texto y conviértelo en símbolo.
  5. Haz que la animación sea de 50 cuadros (frames).
  6. Haz un nuevo fotorama clave (Keyframe) al final de la capa Luz y en ese fotorama mueve el círculo (el símbolo que hiciste antes) al final del texto.
  7. Cambia la propiedad de la capa Luz a máscara (Mask) y haz que la capa Texto sea la capa enmascarada (Masked) como se explicó en el mensaje anterior de máscaras (si no lo leíste, lo puedes ver aquí).
  8. Al bloquear las dos capas y visualizarlo, se ve bien, pero generalmente cuando alumbras una pared, se ve como gris claro alrededor de lo que estás alumbrando. Por lo tanto, agrega otra capa, llamada Gris y pónlo arriba de la capa Text. En esta capa dibuja un rectángulo gris que sea del tamaño del texto.
  9. Bloquea todas las capas de nuevo y ¡ya está!

Notas finales: El video lo puedes ver aquí abajo (o verlo en YouTube en http://www.youtube.com/watch?v=o3dtQPFlhQU). También puedes bajar todos los archivitos de este proyecto (el FLA y SWF) aquí.

Todavía hace falta un par de ejemplos del uso de máscaras, así que no te los pierdas. ¡Nos vemos la próxima!


El Tony y sus ondas...

Related Posts Plugin for WordPress, Blogger...