Curso de Brython en Español - Manejo de Eventos



Responder a eventos en aplicaciones Brython


En lo que llevamos de curso hemos visto cosas interesantes, pero todavía no tenemos la sensación de estar creando aplicaciones.

Hasta ahora, todo lo que hemos hecho podría haberse implementado solamente escribiendo un archivo html estático.

Ha llegado el momento de dotar de funcionalidad real a nuestras aplicaciones.

Crea un archivo index.html con el esqueleto básico para ejecutar brython (tal como vimos en el primer capítulo del curso), y ejecuta un servidor http local con python -m http.server. Abre el navegador en la dirección http://localhost:8000 y refresca la página cada vez que apliques cambios en la app.

Lo primero que haremos será añadir un button al documento. Podría declararse desde html pero vamos a hacerlo todo en brython:

from browser import document
from browser.html import *

boton = BUTTON('Haz Click y verás!')

document <= boton

Este script muestra un botón que no hace nada. A continuación veremos como hacer que suceda algo al hacer click en el botón.



Dar funcionalidad a un botón


Primero veremos cómo se harían las cosas en javascript (pero desde código brython). Posteriormente utilizaremos el estilo brython.


1 - Al estilo de javascript

Todos los elementos html tienen un atributo onclick. El valor de este atributo debe ser una función que reciba un parámetro. Por convención, a este parámetro le llamaremos e o ev, ya que hace referencia al propio evento.

Por tanto, crearemos una función que reciba un parámetro y la asignaremos al atributo onclick del botón:

from browser import document, alert
from browser.html import *

def mostrar_alerta(e):
    alert('Has picado!! jajaja')

boton = BUTTON('Haz Click y verás!')
boton.onclick = mostrar_alerta

document <= boton

Dado que la función mostrar_alerta se ejecuta en respuesta a un evento (en este caso, al evento click), se dice que esta función es un manejador de eventos (o controlador de eventos).

Ya que nuestro manejador de eventos es muy sencillo, vamos a expresarlo como una función lambda:

from browser import document, alert
from browser.html import *

boton = BUTTON('Haz Click y verás!')
boton.onclick = lambda e: alert('Has picado!! jajaja')

document <= boton

También puedes registrar un manejador de eventos utilizando addEventListener:

from browser import document, alert
from browser.html import *

boton = BUTTON('Haz Click y verás!')

boton.addEventListener('click', lambda e: alert('Has picado!! jajaja'))

document <= boton

Puedes registrar varios manejadores para un mismo evento:

from browser import document, alert
from browser.html import *

boton = BUTTON('Haz Click y verás!')

boton.addEventListener('click', lambda e: alert('Has picado!! jajaja'))
boton.addEventListener('click', lambda e: alert('jajajaja me parto!!'))

document <= boton


2 - Al estilo de brython

En brython, para hacer que el código sea mas pythonico, los elementos además soportan el método bind, que funciona exactamente igual que addEventListener:

from browser import document, alert
from browser.html import *

boton = BUTTON('Haz Click y verás!')

boton.bind('click', lambda e: alert('Hola Dude!!'))

document <= boton

Este ha sido un ejemplo muy sencillo. Compliquemos un poco el manejador del evento click:

from browser import document
from browser.html import *

def add_elements(e):

    if len(document.select('p')) == 0:
        document <= P('El texto del botón era: ' + SPAN(e.target.text, style={'color':'red'}))

    document <= P(STRONG(':)'))
    e.target.text = f'Has hecho click {len(document.select("strong"))} veces'


boton = BUTTON('Haz Click y verás!')
boton.bind('click', add_elements)
document <= boton

Fíjate en que dentro de add_elements estoy utilizando e.target para referirme al disparador del evento, es decir, al elemento sobre el que se ha producido el evento (en este caso es el botón).

En cualquier momento pues desvincular un manejador de eventos utilizando en método unbind:

from browser import document, alert
from browser.html import *

def add_elements(e):

    n_parrafos = len(document.select('p'))

    if n_parrafos == 0:
        document <= P('El texto del botón era: ' + SPAN(e.target.text, style={'color':'red'}))

    document <= P(STRONG(':)'))
    n_strongs = len(document.select("strong"))
    e.target.text = f'Has hecho click {n_strongs} veces'

    if n_parrafos == 10:
        e.target.unbind('click', add_elements)
        e.target.bind('click', lambda e: alert('FIN'))



boton = BUTTON('Haz Click y verás!')
boton.bind('click', add_elements)
document <= boton

Puedes listar los manejadores asociados a un evento, sobre un elemento, utilizando el método events:

from browser import document
from browser.html import *

def controlador(e):
    click_events = e.target.events('click')
    if len(click_events) > 5:
        e.target.unbind('click')
        e.target.bind('click', list_handlers)
        div.clear()

def list_handlers(e):
    btn.bind('click', controlador)
    div.clear()
    div <= UL([LI(str(i)[1:-1]) for i in e.target.events('click') if i != list_handlers])

btn = BUTTON('Click Me!')
div = DIV()

document <= btn + div

btn.bind('click', list_handlers)

En ocasiones definirás un manejador de eventos solamente para un elemento html. En estos casos puede que te interese utilizar browser.bind como un decorador:

from browser import document, bind
from browser.html import *

boton = BUTTON('Haz Click y verás!')

@bind(boton, 'click')
def add_elements(e):
    document <= P(f'document.body contiene {len(document.children)} elementos', style=dict(
        color=('yellow' if len(document.children) % 2 else 'black'), backgroundColor=('black' if len(document.children) % 2 else 'yellow')
        ))

document <= boton



Aplicación de ejemplo (calculadora)


Hay muchos otros eventos que podemos manejar (por ejemplo la pulsación de teclas del teclado), pero eso lo veremos en otro capítulo.

Para dejarte con mas ganas de brython voy a mostrarte el código para crear una calculadora básica:

from browser import document, alert, window
from browser.html import *

document.select_one('title').text = 'Calculadora Básica'

document <= STYLE('''

*:not(button) {
    margin: 0px;
    padding: 0px;
    border: 0px;
    outline: none;
    user-select: none;
}

body {
    width: 100vw;
    height: 100vh;
    box-sizing: border-box;
}

input {
    width: 100%;
    text-align: center;
    height:10%;
    font-size: 1.5em;
}

table {
    width: 100%;
    height: 90%;
}

tr {
    height: 25%;
}

button {
    width: 100%;
    height: 100%;
    font-size:1.5em;
}


''')

textbox = INPUT(type='text', placeholder='0')
document <= textbox

botones = [
    ['7', '8', '9', '/'],
    ['4', '5', '6', '*'],
    ['1', '2', '3', '-'],
    ['0', '.', '=', '+']
]

document <= TABLE([TR([TD(BUTTON(celda)) for celda in fila]) for fila in botones])


def add_digit(e):
    textbox.value += e.target.text

def calc_result(e):
    try:
        textbox.value = eval(textbox.value)
    except Exception as e:
        alert(f'ERROR:\n\n{e}')
        textbox.value = '0'


for button in document.select('table > tr > td > button'):
    if button.text != '=':
        button.bind('click', add_digit)
    else:
        button.bind('click', calc_result)

El objetivo de este capítulo no es explicar cómo funciona esta calculadora. Realmente la mayor parte del código son los estilos css.

Espero que te hayas quedado con mas ganas de Brython !!



Atributos y métodos que debes conocer

Para obtener información mas detallada visita la web oficial de brython (eventos).



Tipos de Eventos

Hay muchos otros eventos que puedes manejar además de click: