Saltar al contenido

Tamaño y posición: lógico frente a físico

El factor de escala y las dos unidades en que se puede medir una ventana. Por qué mezclarlas produce ventanas del doble de tamaño en unos monitores y no en otros, y cuál usar en cada caso.

El factor de escala

Cuando aparecieron las pantallas de alta densidad, los sistemas operativos tuvieron que resolver un problema: si una aplicación pide una ventana de ochocientos píxeles y la pantalla tiene el doble de densidad, esa ventana sale del tamaño de una tarjeta de visita.

La solución fue introducir una capa de indirección. La aplicación habla en píxeles lógicos, que son una unidad de tamaño aparente, y el sistema los multiplica por un factor para obtener píxeles físicos, que son los del hardware.

TXT
píxeles lógicos × factor de escala = píxeles físicos800 × 1.0 = 800    monitor normal800 × 2.0 = 1600   pantalla de alta densidad800 × 1.5 = 1200   Windows con escalado al 150 %

El factor no es siempre un número redondo: en Windows el usuario puede elegir escalados intermedios, y en un escritorio con dos monitores distintos el factor cambia al mover la ventana de uno a otro.

Qué devuelve cada llamada

Es lo que hay que memorizar, porque no es uniforme:

La forma de no equivocarse es que el tipo lo dice: en Rust hay un tipo para cada unidad, y la API te obliga a elegir uno al construir un tamaño o una posición. Ese es el mecanismo de defensa, y funciona si no lo cortocircuitas convirtiendo a números sueltos.

Rust
use tauri::{LogicalSize, PhysicalSize, Size};// El tipo dice la unidad. Esto es explícito y correcto.win.set_size(Size::Logical(LogicalSize::new(1100.0, 720.0)))?;// Y para convertir, hace falta el factor:let escala = win.scale_factor()?;let fisico: PhysicalSize<u32> = win.inner_size()?;let logico = fisico.to_logical::<f64>(escala);

El síntoma de haberlas mezclado

Es reconocible y siempre el mismo: la ventana sale del tamaño correcto en tu máquina y del doble o de la mitad en otra. O peor, sale bien y se descoloca al arrastrarla a un segundo monitor.

El caso clásico es guardar el tamaño al cerrar y restaurarlo al abrir:

Rust
// MAL: guarda físicos y restaura como si fueran lógicos.let tam = win.inner_size()?;                       // físicosguardar(tam.width, tam.height);// ... la próxima vez ...win.set_size(Size::Logical(LogicalSize::new(w, h)))?;  // los trata como lógicos

En un monitor con factor 1 no pasa nada, porque las dos unidades coinciden. En uno con factor 2, la ventana duplica su tamaño cada vez que se abre, hasta que no cabe en la pantalla. Es un fallo espectacular, no aparece en tu máquina si tu monitor es normal, y llega en forma de captura de pantalla de un usuario desconcertado.

Y una excepción que confunde

La posición es el caso raro. Las coordenadas del escritorio virtual —dónde está cada monitor respecto a los demás— son físicas, y no hay una alternativa lógica sensata cuando los monitores tienen factores distintos: no existe un origen común en unidades lógicas.

La consecuencia práctica: para colocar una ventana en un monitor concreto, se trabaja en físicos y se pregunta al monitor su posición y su tamaño, en vez de calcular. El nivel siguiente lo hace.