# Marco de ventana

> Tu propia barra de título, botones de ventana y menús. Un componente nativo de Pyzed para GUIs de escritorio en Python, con vista previa, ejemplos y su API.

Source: https://albakore.github.io/pyzed/es/library/window-frame/

:::tip[En pocas palabras]
Dibuja la barra superior de la propia ventana, con sus menús y los botones de minimizar, maximizar y cerrar.
:::

Dibuja el marco completo de una ventana abierta sin decoraciones del sistema (`frame = "custom"`): una barra de título que mueve la ventana (doble clic la maximiza), los botones de minimizar, maximizar y cerrar con el estilo de una plataforma, menús a la izquierda (`ui.Menu`) y bordes que cambian el tamaño de la ventana. `ui.window_title_bar` es la barra sola, `ui.window_controls` los tres botones y `ui.system_platform()` dice qué estilo usa este sistema.

`ui.window_frame` · Categoría: [Espacio de trabajo](https://albakore.github.io/pyzed/es/library/#espacio-de-trabajo) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#window_frame)

**Código:**

```python
ui.window_frame(
    ui.editor("frame-main", "import pyzed as pz\n\npz.run(App)\n", path="main.py"),
    title="notes.py",
    menus=[ui.Menu("File", [ui.MenuItem("Open…", on_open, keys="ctrl-o")]),
           ui.Menu("Edit", [ui.MenuItem("Undo", on_undo, keys="ctrl-z")])],
    start=[ui.title_button("pyzed", on_projects, chevron=True)],
    style="windows",
)
```

:::note[Nuevo]
Este componente se añadió hace poco. Cuéntanos qué tal te funciona en el [gestor de incidencias](https://github.com/albakore/pyzed/issues).
:::

## Cuándo usarlo

- Para apps que quieren una ventana como la de un editor moderno: menús y selectores en la barra de título en lugar del marco del sistema. Mira [Marcos de ventana](https://albakore.github.io/pyzed/es/guides/windows/#marcos-de-ventana-tu-propia-barra-de-título).
- Sin callbacks, `ui.window_title_bar` y `ui.window_controls` solo se muestran: úsalos para previsualizar una ventana con el marco de cada plataforma.

## Uso

```python
import pyzed as pz
from pyzed import ui

class Notes(pz.App):
    title = "Notes"
    frame = "custom"  # or "macos", "windows", "gnome", "ubuntu", "kde"

    def view(self):
        return ui.window_frame(
            self.editor(),
            menus=[ui.Menu("File", [ui.MenuItem("Open…", self.open, keys="ctrl-o"), ui.SEPARATOR,
                                    ui.MenuItem("Quit", self.close)])],
            start=[ui.title_button("pyzed", chevron=True)],
            end=[ui.button("Run", self.run, icon="play", size="sm")],
        )
```

## 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.
:::

### Estilo de plataforma

```python
pz.container(ui.window_title_bar("notes.py", style="windows"), width=420)
```

```python
pz.container(ui.window_title_bar("notes.py", style="macos"), width=420)
```

```python
pz.container(ui.window_title_bar("notes.py", style="gnome"), width=420)
```

```python
pz.container(ui.window_title_bar("notes.py", style="kde"), width=420)
```

```python
pz.container(ui.window_title_bar("notes.py", style="ubuntu"), width=420)
```

### Estado

```python
pz.container(ui.window_title_bar("notes.py", style="windows", focused=False), width=420)
```

```python
ui.window_controls("windows", maximized=True)
```

```python
ui.window_controls("macos")
```

## Eventos

Marco de ventana tiene **5 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 | De | El handler recibe | Cuándo |
| --- | --- | --- | --- |
| `on_drag` | `ui.window_title_bar` | `()` | Se llama al arrastrar la parte vacía de la barra (devuelve `Command.drag_window()`). |
| `on_minimize` | `ui.window_title_bar`, `ui.window_controls` | `()` | Botón de minimizar. |
| `on_maximize` | `ui.window_title_bar`, `ui.window_controls` | `()` | Botón de maximizar y doble clic en la barra. |
| `on_close` | `ui.window_title_bar`, `ui.window_controls` | `()` | Botón de cerrar. |
| `on_menu` | `ui.window_title_bar` | `()` | Clic derecho en la barra. |

**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 Notes(pz.App):
    frame = "custom"                     # Pyzed draws the title bar

    def view(self):
        bar = ui.window_title_bar(
            "notes.py",
            on_drag=lambda: self.drag(),                 # the empty part of the bar
            on_minimize=lambda: self.minimize(),
            on_maximize=lambda: self.toggle_maximize(),  # also a double click on the bar
            on_close=lambda: self.close(),
            on_menu=lambda: print("window menu"),        # right click on the bar
            maximized=self.window_maximized,
        )
        return pz.column([bar, main_view()])
```

**Declarativo:**

```python
class Notes(pz.App):
    frame = "custom"

    def update(self, message):           # the commands are returned from update
        match message:
            case "drag":
                return self.drag()
            case "minimize":
                return self.minimize()
            case "maximize":
                return self.toggle_maximize()
            case "close":
                return self.close()

    def view(self):
        return pz.column([ui.window_title_bar("notes.py", on_drag="drag", on_minimize="minimize",
                                              on_maximize="maximize", on_close="close"), main_view()])
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    title: str = "notes.py"

def view(state, set_state):
    # A handler can return a command: Pyzed runs it.
    return pz.column([ui.window_title_bar(state.title, on_drag=lambda: pz.Command.drag_window(),
                                          on_close=lambda: pz.Command.exit()), main_view()])
```

## Consejos

:::tip
Si solo necesitas menús, define `frame_menus()` en la ventana y no llames a `ui.window_frame`: el entorno de ejecución enmarca la vista por ti. `style` toma por defecto el `frame` de la ventana, o el estilo de este sistema.
:::

## Propiedades y API

### `ui.window_frame`

```python
window_frame(
    content,
    *,
    title=None,
    menus=None,
    menu_button=True,
    start=(),
    center=None,
    end=(),
    style=None,
    window=None,
    height=None,
    resize_border=6.0,
    resize_edges=True,
    bg=None,
    theme=None,
)
```

El marco entero de una ventana abierta con `frame="custom"`: una barra de título que mueve la ventana (doble clic maximiza, clic derecho abre el menú del sistema en Windows), los botones de minimizar, maximizar y cerrar con el estilo de una plataforma, menús a la izquierda y bordes que cambian el tamaño de la ventana.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `content` | *obligatorio* | El contenido de la ventana, bajo la barra de título. |
| `title` | `None` | Título de la barra. Por defecto el `title` de la ventana. |
| `menus` | `None` | Menús a la izquierda de la barra: una lista de `ui.Menu`. |
| `menu_button` | `True` | Muestra los menús tras un botón ☰ (`False` muestra siempre sus nombres). |
| `start` | `()` | Elementos después de los menús (proyecto, rama…). |
| `center` | `None` | Tu propio widget en el centro en lugar del título (un buscador, Run y Stop…); la barra sigue arrastrándose a ambos lados. |
| `end` | `()` | Elementos antes de los botones de ventana. |
| `style` | `None` | `"macos"`, `"windows"`, `"gnome"`, `"ubuntu"` o `"kde"`. Por defecto el `frame` de la ventana, o el del sistema. |
| `window` | `None` | La ventana sobre la que actúan los botones. Por defecto aquella cuyo `view()` se está ejecutando. |
| `height` | `None` | Alto de la barra. Por defecto el de la plataforma. |
| `resize_border` | `6.0` | Ancho en píxeles de los bordes que cambian el tamaño de la ventana. |
| `resize_edges` | `True` | `False` deja los bordes de redimensionar a tu cargo (`pz.window_edges`), para ponerlos encima de menús y diálogos. |
| `bg` | `None` | Color de fondo (`"#rrggbb[aa]"`, `(r, g, b[, a])` o `"transparent"`). |
| `theme` | `None` | Tema a usar en lugar del actual (`pyzed.theme.current()`). |

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

### `ui.Menu`

```python
@dataclass
class Menu(label, items=[])
```

Un menú de la barra de menús de un marco de ventana: un nombre y sus elementos (`ui.MenuItem`, `ui.SEPARATOR` o un texto de cabecera).

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `label` | *obligatorio* | El nombre del menú. |
| `items` | `[]` | Sus elementos: `ui.MenuItem`, `ui.SEPARATOR` o un texto de cabecera. |

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#menu-1)

### `ui.window_title_bar`

```python
window_title_bar(
    title=None,
    *,
    style=None,
    start=(),
    center=None,
    end=(),
    on_drag=None,
    on_minimize=None,
    on_maximize=None,
    on_close=None,
    on_menu=None,
    maximized=False,
    focused=True,
    width='fill',
    height=None,
    bg=None,
    border=True,
    theme=None,
)
```

La barra de título de una ventana, sola: botones de ventana con el estilo de `style` (a la izquierda en macOS), elementos `start`, el título y elementos `end`. Sin callbacks solo se muestra, que es como Pyzed Design previsualiza un formulario con el marco de cada plataforma.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `title` | `None` | Título (centrado, o a la izquierda en Windows). |
| `style` | `None` | `"macos"`, `"windows"`, `"gnome"`, `"ubuntu"` o `"kde"` (`None`: el del sistema). |
| `start` | `()` | Elementos al principio. |
| `center` | `None` | Widget en el centro en lugar del título; la barra sigue arrastrándose a ambos lados. |
| `end` | `()` | Elementos al final. |
| `maximized` | `False` | Muestra el símbolo de restaurar. |
| `focused` | `True` | `False` la atenúa como una ventana en segundo plano. |
| `width` | `"fill"` | Ancho: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `height` | `None` | Alto. Por defecto el de la plataforma. |
| `bg` | `None` | Color de fondo (`"#rrggbb[aa]"`, `(r, g, b[, a])` o `"transparent"`). |
| `border` | `True` | Línea bajo la barra. |
| `theme` | `None` | Tema a usar en lugar del actual (`pyzed.theme.current()`). |

Eventos: `on_drag`, `on_minimize`, `on_maximize`, `on_close`, `on_menu` ([eventos](#eventos)).

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

### `ui.window_controls`

```python
window_controls(
    style=None,
    *,
    on_minimize=None,
    on_maximize=None,
    on_close=None,
    maximized=False,
    focused=True,
    height=None,
    theme=None,
)
```

Los botones de minimizar, maximizar y cerrar con el estilo de una plataforma. Un botón sin callback se dibuja pero no hace nada.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `style` | `None` | `"macos"`, `"windows"`, `"gnome"`, `"ubuntu"` o `"kde"` (`None`: el del sistema). |
| `maximized` | `False` | Muestra el símbolo de restaurar. |
| `focused` | `True` | `False` los atenúa. |
| `height` | `None` | Alto. |
| `theme` | `None` | Tema a usar en lugar del actual (`pyzed.theme.current()`). |

Eventos: `on_minimize`, `on_maximize`, `on_close` ([eventos](#eventos)).

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

### `ui.system_platform`

```python
system_platform()
```

El estilo de los botones de ventana de este sistema: `"macos"`, `"windows"`, `"kde"`, `"ubuntu"` o `"gnome"` (otros escritorios Linux). En WSL es `"windows"`.

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

## Relacionados

- [Barra de título](https://albakore.github.io/pyzed/es/library/title-bar/): La barra superior con los selectores de proyecto y rama.
- [Espacio de trabajo](https://albakore.github.io/pyzed/es/library/workspace/): La disposición de una ventana estilo editor: barra de título, docks, centro y barra de estado.
- [Menú](https://albakore.github.io/pyzed/es/library/menu/): Un menú contextual con iconos, atajos y marcas.
