Tema 9 El Gran Concurso de Presidentes Introducción
El Gran Concurso de Presidentes es un juego de preguntas pregunta s sobre antiguos presidentes de los EEUU. Pero, lo cierto es que la base de la app se puede utilizar como plantilla para crear otras app’s sobre cualquier tema. A lo largo de los temas anteriores hemos ido introduciendo algunos conceptos básicos sobre programación y, ahora, ya estás preparado para hacer algunas cosas más difíciles que requieren de un salto conceptual en términos de programación, habilidades y pensamiento abstracto. En concreto, usaremos dos variables de tipo lista para almacenar los datos, en este caso, las preguntas y las respuestas del concurso. Y usaremos una variable índice para hacer un seguimiento de en qué pregunta del cuestionario se encuentra el usuario. Al finalizar el tema, estarás preparado para crear app’s de preguntas y respuestas donde se utilicen variables de tipo lista, que podrás utilizar para crear tus propios cuestionarios sobre tu especialidad.
Qué vamos a aprender
En este tema se presentan los siguientes conceptos y componentes: •
•
•
•
Necesitaremos declarar y manejar variables de tipo lista para almacenar las preguntas y sus correspondientes respuestas. Usaremos una variable que sirva de índice para recorrer las distintas preguntas del cuestionario una a una, y la variable nos permitirá conocer cuál es la respuesta adecuada (buscando en la lista de respuestas) para la pregunta planteada. Usaremos programación condicional (bloque if-then) para realizar determinadas acciones bajo ciertas condiciones, es decir, qué sucede cuando el usuario acierta una pregunta, cuando falla o cuando llegamos al final del cuestionario. Usaremos un componente imagen para mostrar distintas imágenes que irán cambiando de forma dinámica en base a la pregunta planteada.
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
1
Diseño de componentes
Conéctate a la web de App Inventor con tu navegador en http://ai2.appinventor.mit.edu. Abre un proyecto nuevo y asígnale el nombre Cuestionario . Haz clic en Connect y configura tu dispositivo (o emulador) para poder hacer pruebas en vivo (ya hablamos de cómo hacerlo en el tema cero: Requisitos Previos). Una vez conectado, desde la ventana de diseño, en el panel de propiedades, cambia el título de la Screen1 por El Gran Concurso de los Presidentes.
Interfaz de nuestra app vista en el emulador
La interfaz de nuestra app es realmente sencilla, de todos modos, la imagen siguiente muestra cuáles son exactamente los componentes que hemos usado y sus respectivos nombres.
s e t n e d i s e r P e d o s r u c n o C
Juan Francisco Fuster
n a r G l E
2
Componentes de la interfaz
Como puedes comprobar en la imagen anterior, la app dispone de los siguientes componentes: •
•
•
•
•
Un primer componente HorizontalArrangement (que aparece numerado con el número 2). Ajusta su propiedad Width al valor FillParent y su propiedad AlignHorizontal AlignHorizonta l al valor Center , de ese modo, las imágenes que coloquemos en su interior quedarán centradas. Un componente Image dentro del HorizontalArrangement2 . Fija su propiedad al valor 200 píxeles. En la sección Width al valor 250 píxeles y la propiedad Height al Media, sube al servidor de App Inventor las imágenes que vamos a usar en esta app y que puedes descargar desde la carpeta de Descargas de este tema. Asigna a la propiedad Source del componente Image1 la imagen roosChurch.gif . Debajo del HorizontalArrangement2, crea un componente Label (etiqueta) y asígnale a su propiedad Text la frase Pregunta 1. Renómbralo por LblPregunta . Usaremos esta etiqueta para mostrar las distintas preguntas del cuestionario. A continuación, crea un nuevo componente HorizontalArrangement , el que puedes ver en la imagen con el número 1. Dentro del componente anterior, inserta un TextBox. Cambia su nombre por TxRespuesta y su propiedad Hint al texto Escribe tu respuesta, esta frase será el
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
3
texto que puede leer el usuario dentro del espacio donde deberá escribir su respuesta a la pregunta. •
•
•
A la derecha del componente anterior, crea un Button. Renómbralo a BtResponder y asigna la palabra Responder a su propiedad Text . El usuario deberá pulsar este botón después de escribir su respuesta en el cuadro de texto para poder ser evaluada. Debajo, fuera del HorizontalArrangement1, crea una nueva etiqueta ( Label ). ). Llámala EtCorregir puesto que la usaremos para mostrar al usuario si su respuesta a la pregunta es o no correcta. Deja su propiedad Text en blanco. Por último, debajo de la etiqueta anterior crea un botón. Llámale BtSiguiente y cambia su propiedad Text a la palabra Siguiente .
Definir el comportamiento de los componentes
Nuestra app necesitará los siguientes comportamientos: •
•
•
•
Cuando se inicia la app, aparecerá la primera pregunta y también la imagen correspondiente. Si el usuario toca el botón BtSiguiente entonces aparecerá la segunda pregunta junto con su imagen. imagen . Si vuelve a tocar el mismo botón, bo tón, aparecerá la tercera, ter cera, y así sucesivamente. Llegados a la última pregunta, si el usuario vuelve a tocar el mismo botón entonces deberá mostrarse nuevamente la primera de ellas junto con su imagen. Si el usuario responde a una pregunta, la app debe informar si la respuesta es o correcta o no.
Lo primero que haremos será crear dos variables de tipo lista. En la primera guardaremos el texto de cada pregunta ( ListaPreguntas ). En la segunda tendremos la respuesta correcta (ListaRespuestas ).
Lista de preguntas y de respuestas
Aún necesitamos una variable más, la llamaremos indice y debemos inicializarla al valor numérico 1. La utilizaremos para recorrer la lista de preguntas y, de ese modo, saber cuál es la siguiente pregunta que debemos mostrar si el usuario toca el botón BtSiguiente . Esta variable nos servirá como índice tanto para la lista de preguntas como para la de respuestas, y más adelante, también para la de imágenes.
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
4
Declaración de la variable que servirá para recorrer las listas
Mostrar la primera pregunta
Igual que hemos hecho en otro temas, el trabajo de desarrollo de una app se hace más fácil si nos centramos en una parte cada vez. Nosotros, de momento, dejaremos de lado el tema de mostrar las imágenes de cada pregunta y nos centraremos en las propias preguntas y las respuestas del usuario. Además, es especialmente interesante que nuestros bloques de código funcionen siempre independientemente de cuáles sean las preguntas y/o las respuestas. Así, si en un futuro quieres cambiar las preguntas (y las respuestas) bastará con definirlas en sus listas respectivas. En resumen, no debemos escribir directamente la pregunta en la etiqueta que hemos creado a tal efecto en la interfaz de la app, sino que tendremos que buscar el texto de la pregunta dentro de la lista correspondiente ( ListaPreguntas ). Pero como la lista tiene distintas preguntas, ¿cuál de ellas debemos mostrar? La respuesta es fácil, aquélla que se corresponda con la posición que indica la variable indice (recuerda que la inicializamos al valor 1). En la imagen siguiente puedes comprobar que, cuando se abra la app, se obtendrá la primera pregunta de la ListaPreguntas gracias al bloque select list item list . El texto de la pregunta se asigna a la etiqueta LblPregunta y, en consecuencia, aparecerá en la pantalla de la app.
El evento Initialize siempre cargará la primera pregunta de la lista
Iterar a través de las preguntas
Como ya hemos mencionado, si el usuario toca el botón BtSiguiente la app debe buscar y mostrar la siguiente pregunta de la lista. Podemos saber qué pregunta será exactamente si sumamos 1 al valor de la variable indice, por ejemplo, si indice tiene el valor 1 y le sumamos 1, el resultado nos indica que debemos buscar la segunda pregunta de la lista. Fíjate en los bloques de la imagen siguiente:
s e t n e d i s e r P e d o s r u c n o C
Mostrar la siguiente pregunta de la lista
Juan Francisco Fuster
n a r G l E
5
Cuando el usuario toca el botón BtSiguiente se ejecutará el evento Click. Primero, sumaremos 1 a la variable indice y, después, buscaremos la siguiente pregunta de la lista correspondiente usando el mismo bloque de antes: select list item list. Fíjate bien que el índice que debemos usar en este caso será el valor de la variable indice. Por ejemplo, la primera vez que el usuario toque el botón, la variable pasará a valer 2 (1+1), de forma que la app seleccionará la segunda pregunta de la lista ( ¿Qué ). La siguiente presidente otorgó o torgó reconocimiento reconoc imiento oficial a la China comunista en 1979? ). vez que el usuario toque el mismo botón, la variable indice pasará del valor 2 a 3, y la app buscará la tercera pregunta de la lista ( ¿Qué presidente presiden te renunció por po r el escándalo ). Watergate? ).
Nota
Antes de continuar, compara los bloques que hemos creado para los eventos BtSiguiente.Click y Screen1.Initialize . En el caso del evento Initialize, la app selecciona una pregunta de la lista a partir de un número concreto (1). En cambio, en BtSiguiente.Click la app selecciona una pregunta de la lista en base al valor de una variable ( indice ), es decir, no se selecciona ni el primero, ni el segundo, ni ningún valor concreto de la lista sino que elige la pregunta que se corresponde con el valor que tenga en ese momento la variable indice ; de este modo, cada vez que se toca el botón BtSiguiente se seleccionará una pregunta distinta de la lista. Es una práctica habitual usar un índice de este modo para recorrer una lista y poder acceder a todos sus elementos. El problema de nuestra app, en su versión actual, es que siempre se incrementa el valor de la variable índice para pasar a la siguiente pregunta sin preocuparse por comprobar si hemos llegado al final del cuestionario. De hecho, si estamos en la pregunta 3 y el usuario toca otra vez el botón BtSiguiente, la app debería volver a la pregunta 1 en lugar de tratar de buscar en la lista una pregunta 4 que, en su nuestra app, no existe. Así pues, ¿cómo podemos hacer para que la app sepa que ha llegado al final de la lista y debe volver a empezar?
Prueba tu app
Prueba el comportamiento del botón BtSiguiente para ver si la app está funcionando correctamente. Si tocas el botón de siguiente, la app mostrará la segunda pregunta. Y si lo haces otra vez, mostrará la tercera. Pero si lo vuelves a hacer se producirá un error puesto que estarás tratando de obtener el cuarto elemento de una lista de 3.
Para solucionar el problema expuesto anteriormente, la app tiene que hacerse una pregunta: ¿es la variable indice superior a 3? Si la respuesta es sí, debe establecer el valor de dicha variable a 1 para que se vuelva a mostrar la primera pregunta. De lo contrario, es decir, si es menor o igual que 3, debe mostrar la pregunta que corresponde al valor de la variable. Observa los bloques de la imagen siguiente:
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
6
Nueva versión que comprueba si se ha llegado al final del cuestionario y, en tal caso, vuelve a empezar desde la primera pregunta
En los bloques anteriores puedes apreciar que cuando se toca el botón siguiente, la app incrementa el valor de la variable tal y como ya hacía antes. Pero después, se comprueba su valor para saber si es superior a 3 ( if ), ), en cuyo caso, se vuelve asignar el valor uno a la variable (parte correspondiente al then). Finalizada la comprobación del if-then, y ahora que ya estamos seguros que la variable indice nunca podrá tomar un valor superior a 3, se procede a seleccionar la siguiente pregunta del mismo modo que hacíamos antes.
Facilitar la modificación del cuestionario
Antes de continuar, añadimos una pregunta más a la lista de preguntas y una respuesta más a su lista correspondiente:
Añadimos una pregunta y una respuesta más
Si pruebas nuevamente la app en el móvil te encontrarás con un nuevo problema; la cuarta pregunta nunca aparece porque cuando llegamos a la tercera y el usuario toca el botón siguiente entonces se vuelve a mostrar la primera. ¡Claro! Eso es justamente lo que tiene que pasar porque así hemos programado el evento BtSiguiente.Click. Si queremos que la cuarta pregunta también se muestre, tendremos que modificar nuevamente el evento BtSiguiente.Click y sustituir el 3 por un 4. Así, la app ya mostrará la pregunta número 4. Aunque el procedimiento descrito en el párrafo anterior es perfectamente válido, lo cierto es que es poco eficiente puesto que nos obliga a modificar este evento cada vez que añadamos o eliminemos alguna pregunta. Además, si el número de preguntas y respuestas se puede modificar de forma dinámica (como haremos en el tema 11) entonces el método que hemos usado para calcular la variable índice ya no resulta útil.
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
7
Así pues, para que la app sea más general, no se deben usar números concretos (ni el 3 ni el 4) en la comprobación del bloque if-then. Lo que debemos hacer es comprobar cuántos elementos hay en la lista y, si hemos llegado al último, volver a empezar desde el primero. Observa los bloques siguientes:
Versión mejorada del evento BtSiguiente.Click
Fíjate que apenas hemos realizado un único cambio con respecto a la versión anterior de este mismo evento. En lugar de escribir un número concreto, el 3 (ó 4, 5 ó el número de preguntas que tengamos), usamos una función que nos permite calcular la cantidad de elementos de la lista.: length of list list . Con esta nueva versión ya no importa cuántas preguntas tengamos, es más, podremos modificar la cantidad de preguntas y respuestas siempre que queramos y los bloques seguirán funcionando correctamente siempre.
Prueba tu app
Pon a prueba la nueva versión de tu app. Cuando hagas clic en el botón siguiente sucesivas veces, la app debe rotar de la primera a la última pregunta y volver a empezar.
Cambiar la imagen para cada pregunta
Ahora que ya hemos programado todos los comportamientos para que la app pueda moverse a través de las preguntas y, además, hemos hecho el código más inteligente y más flexible, y consecuentemente más abstracto, ha llegado el momento de hacer que las imágenes también vayan cambiando. Actualmente, la app muestra la misma imagen en pantalla independientemente de la pregunta que se está formulando. Nuestro próximo objetivo es que la imagen vaya cambiando cuando el usuario toque el botón BtSiguiente . Para conseguirlo, necesitaremos una nueva variable de tipo lista que podemos llamar ListaImagenes y que guardará el nombre de los archivos de imagen que se deben mostrar en cada pregunta. Como siempre, los archivos de imagen están disponibles en la sección de descargas de este tema y debes descargarlas a tu ordenador y, después, subirlas al servidor de App Inventor usando el botón Upload File. Después, ya podremos crear la nueva variable:
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
8
Variable de lista que guardará los nombres de los archivos de imagen
Acto seguido, tendremos que modificar el evento BtSiguiente.Click una vez más para que cambie la imagen que aparece en pantalla en función de la pregunta. La propiedad Image1.picture será la que usaremos para cambiar la imagen que se muestra.
Mostrar una imagen distinta con cada pregunta
La variable que ya venimos usando ( indice) sirve tanto para determinar cuál es la siguiente pregunta como para seleccionar la imagen correspondiente de la ListaImagenes . Siempre que hayas configurado correctamente las listas de manera que la primera pregunta de su lista y la primera imagen de su respectiva lista, se correspondan, la segunda pregunta con la segunda imagen, y así sucesivamente, la app funcionará correctamente.
Prueba tu app
Cuando hagas clic en el botón siguiente debería cambiar la pregunta y también la imagen, ¿es así?
Comprobar las respuestas del usuario
Hasta ahora, hemos creado una app que simplemente se desplaza entre las preguntas mostrando distintas imágenes, y aunque es un buen ejemplo de app’s que utilizan listas, para ser una app funcional debe informar a los usuarios sobre si lo están haciendo bien o mal con sus respuestas.
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
9
Así que ahora vamos a añadir los bloques de código necesarios para informar al usuario de nuestra app si ha respondido correctamente o no a la pregunta que le planteamos. Recuerda diseñamos la app para que el usuario introduzca su respuesta en el cuadro de texto correspondiente y, después, toque el botón BtResponder . La app debe comparar el texto introducido por el usuario con la respuesta de la pregunta actual utilizando un bloque if-then-else . Para terminar, la etiqueta EtCorregir que creamos al principio en la interfaz, mostrará ahora si el usuario a acertado o no sencillamente con una palabra: correcto o incorrecto .
Comprobar la respuesta del usuario
Supongamos que la pregunta actual es la primera (la variable indice tiene el valor 1), la app comparará la respuesta del usuario con el elemento 1 de la lista de respuestas (ListaRespuestas ) pero antes de hacerlo convierte ambas palabras a mayúsculas usando la función upcase . Dicho de otro modo, primero se convierte a mayúsculas el texto de la respuesta número 1 de la lista ListaRespuestas , después se convierte a mayúsculas la respuesta del usuario y, por último, se realiza la comparación. Si el resultado de la comparación es cierto (parte del then) entonces la respuesta es correcta y se escribe ¡Correcto! en la etiqueta. De lo contrario (parte del else) se escribe la palabra ¡Incorrecto!
Prueba tu app
Intenta responder a una de las preguntas. La app debe informar si la respuesta que has escrito es correcta o no, y además, sólo dará la pregunta por correcta si escribes exactamente la misma palabra que existe en la lista de respuestas. Prueba también a introducir alguna respuesta incorrecta intencionadamente y comprueba si EtCorregir muestra la exclamación ¡Incorrecto!
La app debería funcionar, pero verás que después de hacer clic al botón siguiente y mostrarse la siguiente pregunta el texto ¡Correcto! o ¡Incorrecto! sigue sigue viéndose en pantalla, al igual que la respuesta del usuario a la pregunta anterior. Para solucionar este pequeño inconveniente tendremos que realizar un último cambio al evento BtSiguiente.Click que consistirá en limpiar el contenido del cuadro de texto TxRespuesta y también de la etiqueta EtCorregir . Observa la imagen siguiente:
s e t n e d i s e r P e d o s r u c n o C
Juan Francisco Fuster
n a r G l E
10
Borramos la respuesta del usuario y la palabra correcto/incorrecto antes de la siguiente pregunta
Mejorar la app
Puedes intentar mejorar la app de distintas formas, aquí te ofrecemos como ejercicio algunas opciones. 1. Para cada pregunta, además de mostrar la imagen correspondiente, intenta que la app lea el texto. Si quieres, en lugar de una imagen estática puede reproducir un pequeño vídeo. 2. La corrección de la respuesta del usuario es muy rígida puesto que tiene que coincidir exactamente con el texto que tenemos en la lista de las respuestas. Una forma de flexibilizar dicha corrección consiste en usar el bloque text.contains y comprobar si la respuesta del usuario está contenida en nuestra respuesta oficial. Otra forma, es aceptar múltiples respuestas a una misma pregunta y comprobar si la respuesta del usuario coincide con alguna de ellas.
Resumen
Algunos de los puntos más importantes que hemos desarrollado en este tema son: •
•
•
•
Hemos dividido la app en dos partes bien diferenciadas, por un lado los datos (que con mucha frecuencia se almacenan en una lista) y por otro los bloques encargados de controlar los eventos. Hemos utilizado un bloque if-then-else para comprobar si el usuario acertaba o no las preguntas del cuestionario. Para pasar de una pregunta a la siguiente hemos diseñado un conjunto de bloques totalmente abstracto que funcionará siempre independientemente del número de preguntas de nuestra app. Las variables índice hacen un seguimiento de un elemento dentro de una lista. Cuando se incrementa el índice, es muy importante comprobar con un bloque if-
Juan Francisco Fuster
s e t n e d i s e r P e d o s r u c n o C n a r G l E
11
thenque no excedamos del número máximo de elementos de la lista, puesto que de lo contrario la app provocará un error de ejecución.
s e t n e d i s e r P e d o s r u c n o C
Juan Francisco Fuster
n a r G l E
12