13 de abril de 2014

Controlar múltiples monitores

Artículo original: Handling Multiple Monitors
http://doughennig.blogspot.com/2007/04/handling-multiple-monitors.html
Autor: Doug Hennig
Traducido por: Ana María Bisbé York

Una de las cosas que hice con mi nuevo portátil fue configurarle múltiples monitores. Algunos desarrolladores que conozco y respeto lo han hecho desde hace años, así que supongo que ya sea hora de que yo también lo intente. No hay nada que decir, me gusta. Tengo generalmente el Examinador y explorador de Windows abiertos en el segundo monitor y mantengo el monitor primario para aquellas cosas que hago a lo largo del día (principalmente VFP y Outlook). Soy más productivo ahora que no tengo que moverme entre la pila de ventanas ni moverme o redimensionar constantemente una ventana.

Sin embargo, una de las cosas que he descubierto hoy, es que algunas de mis aplicaciones no respetan el segundo monitor. Por ejemplo, tengo una clase llamada SFPersistentForm que arrastro a la mayoría de mis formularios. Esta clase guarda el tamaño y posición del formulario cuando se cierra y lo restaura cuando se abre nuevamente, dando al usuario la experiencia que el espera al trabajar con este formulario. Sin embargo, he descubierto que si abro el formulario y lo muevo al segundo monitor, luego llo cierro, y cuando lo reabro el formulario se muestra sin embargo, en el primer monitor (es un formulario con Desktop = .T., por tanto puede existir fuera de la aplicación).

Rápidamente encontré la razón: el código intentaba evitar la situación en la que el formulario pudiera abrirse fuera de los límites de la pantalla, haciéndolo invisible. El siguiente código controla esto:
Thisform.Width = min(max(Thisform.Width, 0, Thisform.MinWidth), ;
  _screen.Width)
Thisform.Height = min(max(Thisform.Height, 0, Thisform.MinHeight), ;
  _screen.Height)
Thisform.Left = min(max(Thisform.Left, 0), _screen.Width - 50)
Thisform.Top = min(max(Thisform.Top, 0), _screen.Height - 50)
("-50"  se utiliza para garantizar que el formulario no comience exactamente  la derecha del borde del monitor, haciéndolo esencialmente invisible.)

Existen dos problemas con este código. Primero, la confiabilidad en _SCREEN asume que el formulario existe con _SCREEN, que es un formulario de nivel superior o uno con Desktop = .T., que no es necesariamente el caso. Segundo, si se maximiza _SCREEN, solo cabe en el monitor actual. Si el formulario está en el otro monitor, las dimensiones de _SCREEN son irrelevantes.

Inicialmente cambié el código:
if Thisform.Desktop or Thisform.ShowWindow = 2
  lnWidth = sysmetric(1)
  lnHeight = sysmetric(2)
else
  lnWidth = _screen.Width
  lnHeight = _screen.Height
endif Thisform.Desktop ...
Thisform.Width = min(max(Thisform.Width, 0, Thisform.MinWidth), ;
  lnWidth)
Thisform.Height = min(max(Thisform.Height, 0, Thisform.MinHeight), ;
  lnHeight)
Thisform.Left = min(max(Thisform.Left, 0), lnWidth - 50)
Thisform.Top = min(max(Thisform.Top, 0), lnHeight - 50)
Sin embargo, SYSMETRIC() sólo devuelve valores para el monitor primario. Entonces, cambié las sentencias a:
declare integer GetSystemMetrics in Win32API integer
#define SM_CXVIRTUALSCREEN 78 && Ancho Virtual 
#define SM_CYVIRTUALSCREEN 79 && Altura Virtual 
lnWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN)
lnHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN)
Ahora el formulario se reabre en la misma posición exacta, incluyendo el monitor donde estaba antes.

2 comentarios :

  1. Hola, yo estoy trbajando con una aplicación para competencias de karate donde se manejan 2 monitores, uno para el operador y otro para la cancha donde se lleva la competencia propiamente. pues yo resolvi el problema muy fácilmente:
    1) dile al windows que tienes 2 monitores y el secundario lo abres como escritorio extendido.
    2) en el formulario que quieres abrir en el monitor secundario debes buscar la propiedad LEFT del formulario (FORM1) y comenzar a probar con los valores superiores a 1200 hasta que te quede bien centrado.

    ResponderEliminar