¿Qué es TApplication.Handle
?
- ¿De dónde viene?
- ¿Por qué existe?
- Y lo más importante: ¿por qué todos los formularios lo tienen como identificador de ventana principal?
La ayuda de Delphi dice:
TApplication.Handle
Proporciona acceso al identificador de ventana del formulario principal (ventana) de la aplicación.
property Handle: HWND;
Descripción
Use Handle cuando llame a las funciones de la API de Windows que requieren un identificador de ventana principal. Por ejemplo, una DLL que muestra sus propias ventanas emergentes de nivel superior necesita una ventana principal para mostrar sus ventanas en la aplicación. El uso de la propiedad Handle hace que dichas ventanas formen parte de la aplicación, por lo que se minimizan, restauran, habilitan y deshabilitan con la aplicación.
Si me concentro en las palabras " el identificador de ventana del formulario principal de la aplicación ", y considero que eso significa el identificador de ventana del formulario principal de la aplicación, entonces puedo comparar:
- "el identificador de ventana del formulario principal de la aplicación", con
- la manija de la ventana de la
MainForm
de laApplication
Pero no son los mismos:
Application.MainForm.Handle: 11473728
Application.Handle: 11079574
Entonces, ¿qué es Application.Handle
?
- ¿De dónde viene?
- ¿Qué identificador de ventana de Windows® es?
- Si es el identificador de ventana de Windows® de
Application
'sMainForm
, ¿por qué no coinciden? - Si no es el identificador de ventana de
Application
'sMainForm
, ¿qué es? - Más importante aún: ¿Por qué es el padre propietario final de cada formulario?
- Y lo más importante: ¿Por qué todo se vuelve loco si trato de que un formulario no tenga un propietario (para que pueda aparecer en la barra de tareas), o trato de usar algo como IProgressDialog?
Realmente lo que estoy preguntando es: ¿Cuál es la razón de diseño que hace que Application.Handle exista? Si puedo entender el por qué, el cómo debería volverse obvio.
Entendiendo a través de un juego de veinte preguntas:
Al hablar sobre la solución de hacer que una ventana aparezca en la barra de tareas haciendo que su propietario null
, Peter Below en 2000 dijo:
Esto puede causar algunos problemas con los formularios modales que se muestran a partir de formularios secundarios.
Si el usuario sale de la aplicación mientras un formulario modal está activado y luego vuelve al formulario que lo mostró, el formulario modal puede ocultarse debajo del formulario. Es posible lidiar con esto asegurándose de que la forma modal esté subordinada [sic; quiso decir propiedad] a la forma que lo mostró (usando
params.WndParent
como arriba)
Pero esto no es posible con los cuadros de diálogo estándar de la Dialogs
unidad y las excepciones, que necesitan más esfuerzo para que funcionen correctamente (básicamente, el manejo Application.OnActivate
, la búsqueda de formularios modales vinculados a Application via GetLastActivePopup
y llevarlos a la parte superior del orden Z via SetWindowPos
).
- ¿Por qué un formulario modal termina atascado detrás de otros formularios?
- ¿Qué mecanismo normalmente trae una forma modal al frente y por qué no es funcional aquí?
- Windows® se encarga de mostrar las ventanas apiladas. ¿Qué salió mal para que Windows® no muestre las ventanas correctas?
También habló sobre el uso del nuevo estilo extendido de Windows que obliga a que una ventana aparezca en la barra de tareas (cuando las reglas normales para hacer que no sea de propiedad son insuficientes, poco prácticas o indeseables), agregando el WS_EX_APPWINDOW
estilo extendido:
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams( params );
Params.ExStyle:= Params.ExStyle or WS_EX_APPWINDOW;
end;
Pero luego advierte:
Si hace clic en un botón de la barra de tareas de formularios secundarios mientras otra aplicación está activa, se mostrarán todos los formularios de las aplicaciones al frente. si no quieres eso hay opcion
Quién está trayendo todos los formularios al frente cuando el propietario del formulario todavía está Application.Handle
. ¿ La aplicación está haciendo esto? ¿Por qué está haciendo esto? En lugar de hacer esto, ¿no debería estar haciendo esto? ¿Cuál es la desventaja de no hacer esto? Veo la desventaja de hacerlo (la propiedad del menú del sistema no funciona, las miniaturas de los botones de la barra de tareas son inexactas, el shell de Windows® no puede minimizar las ventanas.
In another post dealing with the Application
, Mike Edenfield says that the parent window sends other window's their minimize, maximize and restore messages:
Esto agregará el botón de la barra de tareas para su formulario, pero hay algunos otros detalles menores que manejar. Lo más obvio es que su formulario aún recibe minimizar/maximizar que se envía al formulario principal (el formulario principal de la aplicación). Para evitar esto, puede instalar un controlador de mensajes para WM_SYSCOMMAND agregando una línea como:
procedure WMSysCommand(var Msg: TMessage); WM_SYSCOMMAND;
procedure TParentForm.WMSysCommand(var Msg: TMessage);
begin
if Msg.wParam = SC_MINIMIZE then
begin
// Send child windows message, don't
// send to windows with a taskbar button.
end;
end;
Tenga en cuenta que este controlador va en la forma PADRE del que desea que se comporte independientemente del resto de la aplicación, para evitar pasar el mensaje de minimización. Puedes añadir código > similar para SC_MAXIMIZE, SC_RESTORE, etc.
¿Cómo es que los mensajes de minimización/maximización/restauración de mis ventanas de Windows® no van a mi ventana? ¿Es esto porque los mensajes destinados a una ventana son enviados por Windows® al propietario de la ventana? Y en este caso, todos los formularios en una aplicación Delphi son "propiedad" de Application
? ¿Eso no significa que hacer que el propietario sea nulo:
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent:= 0; //NULL
end;
se eliminará Application
y su controlador de ventana no interferirá con mi formulario, y Windows debería volver a enviarme mis mensajes de minimización/maximización/restauración.
Quizás si comparamos y contrastamos ahora una aplicación de Windows "normal" hace cosas, con la forma en que Borland diseñó inicialmente las aplicaciones Delphi para hacer cosas, con respecto a este Application
objeto y su bucle principal.
- ¿Qué solución estaba
Application
resolviendo el objeto? - ¿Qué cambio se hizo con versiones posteriores de Delphi para que estos mismos problemas no existan?
- ¿El cambio en versiones posteriores de Delphi no introdujo otros problemas que el diseño inicial de la aplicación se esforzó tanto en resolver?
- ¿Cómo pueden esas aplicaciones más nuevas seguir funcionando sin que la aplicación interfiera con ellas?
Obviamente, Borland se dio cuenta de la falla en su diseño inicial. ¿Cuál fue su diseño inicial, qué problema estaba resolviendo, cuál es la falla, cuál fue el rediseño y cómo resuelve el problema?
Solución del problema
El motivo de la ventana de la aplicación tiene una historia un poco sórdida. Cuando desarrollamos Delphi 1, sabíamos que queríamos usar el modelo de interfaz de usuario "SDI" (ventanas dispersas por todo el escritorio) para el IDE. También sabíamos que Windows apestaba (y aún lo hace) en ese modelo. Sin embargo, también notamos que Visual Basic en ese momento empleaba ese modelo y parecía funcionar bien. Luego de un examen más detallado, encontramos que VB usaba una ventana de estacionamiento "oculta" especial que se usaba como "propietario" (Windows difumina la noción de padre y propietario a veces, pero la distinción es similar a VCL) para todas las otras ventanas visibles.
Así es como solucionamos el "problema" en el que las ventanas que contenían el menú principal rara vez estaban enfocadas, por lo que procesar Alt-F para el menú Archivo simplemente no funcionaba. Al utilizar esta ventanilla de estacionamiento central como intermediario, podríamos rastrear y enrutar los mensajes más fácilmente a las ventanillas correspondientes.
Esta disposición también resolvió otro problema en el que normalmente varias ventanas de nivel superior eran completamente independientes. Al hacer que la aplicación maneje al "propietario" de todas estas ventanas, todas se comportarán en conjunto. Por ejemplo, es posible que haya notado que cuando selecciona cualquiera de las ventanas de la aplicación, todas las ventanas de la aplicación se mueven al frente y conservan su orden z entre sí. Esto también haría que la aplicación se minimizara y restaurara como una agrupación funcional.
Esa es una consecuencia de usar este modelo. Podríamos haber hecho todo este trabajo manualmente para mantener las cosas en orden, pero la filosofía de diseño era no reinventar Windows, sino aprovecharlo donde pudiéramos. Esa es también la razón por la que un TButton o un TEdit son realmente una clase y un estilo de ventana BUTTON y EDIT de "Usuario" de Windows, respectivamente.
A medida que Windows evolucionó, ese modelo "SDI" comenzó a caer en desgracia. De hecho, el propio Windows comenzó a volverse "hostil" a ese estilo de aplicación. Comenzando con Windows Vista y continuando con 7, el shell de usuario no parece funcionar bien con una aplicación que usa una ventana de estacionamiento. Entonces, nos dispusimos a mezclar las cosas en VCL para eliminar la ventana de estacionamiento y mover su función al formulario principal. Esto presentaba varios problemas de "huevo y gallina" por los que necesitamos tener la ventana de estacionamiento disponible lo suficientemente temprano en la inicialización de la aplicación para que otras ventanas puedan "adherirse", pero es posible que el formulario principal no se construya lo suficientemente pronto. TApplication tiene que pasar por algunos obstáculos para que esto funcione, y ha habido algunos casos sutiles que han causado problemas, pero la mayoría de los problemas han sido resueltos. Sin embargo, para cualquier aplicación que avance, seguirá usando el modelo anterior de ventana de estacionamiento.
No hay comentarios.:
Publicar un comentario