# Área de ratón

> Hace que cualquier widget reaccione a clics, hover, arrastres y la rueda. Componente de Pyzed para GUIs de escritorio en Python, con ejemplos y API.

Source: https://albakore.github.io/pyzed/es/library/mouse-area/

:::tip[En pocas palabras]
Una capa invisible que permite que cualquier cosa (una imagen, una tarjeta, un dibujo) note los clics y el ratón.
:::

`pz.mouse_area` envuelve cualquier widget y avisa de lo que hace el ratón encima: pulsaciones (izquierda, derecha, central, doble clic), entrar y salir, moverse (`on_move(x, y)`) y la rueda (`on_scroll(dx, dy)`); `cursor` cambia el puntero. `pz.hover(base, top)` muestra `top` encima de `base` solo mientras el puntero está encima, y `pz.opaque` impide que los clics lleguen a lo que hay debajo de un widget en un `stack`.

`pz.mouse_area` · Categoría: [Acciones](https://albakore.github.io/pyzed/es/library/#acciones) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#mouse_area)

**Código:**

```python
pz.mouse_area(
    ui.card(pz.row([pz.icon("folder", size=20), ui.label("Open project…")], spacing=10, align="center"),
            width=280),
    on_press=on_open, on_right_press=on_menu, cursor="pointer",
)
```

## Cuándo usarlo

- Para que una tarjeta, una imagen o un dibujo propio se puedan pulsar sin convertirlos en botón.
- Para menús de clic derecho (`on_right_press`), gestos de arrastre (`on_move`) y zoom con la rueda.
- `pz.hover` para acciones que aparecen al pasar el ratón, como el botón de cerrar de una pestaña.

## Uso

```python
import pyzed as pz

class Board(pz.App):
    def __init__(self):
        self.pointer = (0, 0)
        self.zoom = 1.0

    def view(self):
        return pz.mouse_area(
            self.drawing(),
            on_move=lambda x, y: setattr(self, "pointer", (x, y)),
            on_scroll=lambda dx, dy: setattr(self, "zoom", max(0.1, self.zoom + dy * 0.1)),
            on_double_click=self.reset, cursor="crosshair",
        )
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Cursor

La forma del puntero solo se ve con un ratón real; la captura muestra el widget envuelto.

```python
pz.mouse_area(ui.card(ui.label("Click me"), width=180), on_press=on_open, cursor="pointer")
```

```python
pz.mouse_area(ui.card(ui.label("Drag me"), width=180), on_move=on_drag, cursor="grab")
```

```python
pz.mouse_area(pz.canvas([draw.circle(60, 40, 24, fill="#74ade8")], width=120, height=80),
              on_press=on_pick, cursor="crosshair")
```

### Contenido en hover

`pz.hover` solo dibuja su `top` mientras el puntero está encima: aquí, el botón de cerrar de una fila.

```python
pz.hover(ui.list_item("notes.py", on_open, icon="file-text"),
         pz.container(ui.icon_button("x", on_close, size="xs"), align_x="end", width="fill"))
```

```python
pz.hover(ui.list_item("notes.py", on_open, icon="file-text"),
         pz.container(ui.icon_button("x", on_close, size="xs"), align_x="end", width="fill"))
```

## Eventos

Área de ratón tiene **10 eventos propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

| Evento | El handler recibe | Cuándo |
| --- | --- | --- |
| `on_press` | `()` | Clic izquierdo (al pulsar). |
| `on_release` | `()` | Al soltar el botón izquierdo. |
| `on_right_press` | `()` | Clic derecho (menús contextuales). |
| `on_double_click` | `()` | Doble clic. |
| `on_enter` | `()` | El ratón entra. |
| `on_exit` | `()` | El ratón sale. |
| `on_move` | `(x, y)` | Se llama con `(x, y)` al mover el ratón. |
| `on_scroll` | `(dx, dy)` | Callable que recibe `(dx, dy)` en líneas al usar la rueda. |
| `on_middle_press` | `()` | Clic con el botón central. |
| `on_middle_release` | `()` | Se suelta el botón central (para desplazar la vista, por ejemplo). |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
class Board(pz.App):
    def __init__(self):
        self.pointer, self.hovering, self.zoom = (0, 0), False, 1.0

    def view(self):
        return pz.mouse_area(
            ui.card(ui.label(f"{self.pointer} · zoom {self.zoom:.1f}"), width=320),
            on_enter=lambda: setattr(self, "hovering", True),
            on_exit=lambda: setattr(self, "hovering", False),
            on_move=lambda x, y: setattr(self, "pointer", (round(x), round(y))),
            on_scroll=lambda dx, dy: setattr(self, "zoom", max(0.1, self.zoom + dy * 0.1)),
            on_double_click=lambda: setattr(self, "zoom", 1.0),
            on_right_press=lambda: print("context menu"),
            cursor="crosshair",
        )
```

**Declarativo:**

```python
from dataclasses import dataclass

@dataclass
class Moved:
    x: float
    y: float

class Board(pz.App):
    pointer = (0, 0)

    def update(self, message):
        match message:
            case Moved(x, y):
                self.pointer = (round(x), round(y))
            case "reset":
                self.pointer = (0, 0)

    def view(self):
        return pz.mouse_area(ui.card(ui.label(str(self.pointer)), width=320),
                             on_move=Moved, on_double_click="reset")
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    hovering: bool = False

def view(state, set_state):
    return pz.mouse_area(ui.card(ui.label("Hovering" if state.hovering else "Point at me"), width=320),
                         on_enter=lambda: set_state(hovering=True), on_exit=lambda: set_state(hovering=False))
```

## Consejos

:::tip
Los estados de hover y del puntero solo existen con un ratón real, así que las vistas previas los dibujan tal como se ven; mira los clips animados del [Showcase](https://albakore.github.io/pyzed/es/showcase/) para verlos en marcha.
:::

## Propiedades y API

### `pz.mouse_area`

```python
mouse_area(
    content,
    *,
    on_press=None,
    on_release=None,
    on_right_press=None,
    on_double_click=None,
    on_enter=None,
    on_exit=None,
    on_move=None,
    on_scroll=None,
    on_middle_press=None,
    on_middle_release=None,
    cursor=None,
)
```

Detecta eventos del ratón sobre su contenido.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `content` | *obligatorio* | Contenido: un `Widget`, un texto o un número (se convierte en texto). |
| `cursor` | `None` | `"pointer"`, `"text"`, `"grab"`, `"grabbing"`, `"crosshair"`, `"not-allowed"`, `"resize-horizontal"`, `"resize-vertical"`, `"move"` o `"default"`. |

Eventos: `on_press`, `on_release`, `on_right_press`, `on_double_click`, `on_enter`, `on_exit`, `on_move`, `on_scroll`, `on_middle_press`, `on_middle_release` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#mouse_area)

### `pz.hover`

```python
hover(base, top)
```

Muestra `top` encima de `base` solo mientras el ratón está encima (por ejemplo, el botón de cerrar de una pestaña).

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `base` | *obligatorio* | Widget de abajo. |
| `top` | *obligatorio* | Widget que aparece al pasar el ratón. |

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#hover)

### `pz.opaque`

```python
opaque(content)
```

Hace que un widget bloquee el ratón para lo que está debajo en un `stack`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `content` | *obligatorio* | Contenido: un `Widget`, un texto o un número (se convierte en texto). |

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#opaque)

## Relacionados

- [Botón](https://albakore.github.io/pyzed/es/library/button/): El botón con tema: variantes, tamaños, iconos y atajos.
- [Popover](https://albakore.github.io/pyzed/es/library/popover/): Contenido flotante en un punto: menús contextuales, selectores de color.
- [Pila](https://albakore.github.io/pyzed/es/library/stack/): Superpone los hijos; `pin` coloca uno en x, y.
