delphi - trabajar - maximizar formulario access
Los formularios wsMaximized no aparecen maximizados (5)
¡Guauu! no vi en la publicación:
ShowWindowAsync (Handle, SW_MAXIMIZE);
Gracias por eso, con eso mi problema se resuelve mucho mejor que con un temporizador, pero no perfecto, todavía causa un pequeño parpadeo (la ventana se muestra en el render incompleto, luego va al estado maximizado), es mucho mejor que el temporizador , menos tiempo mostrado en estado no maximizado.
Y es compatible con un SetBounds anterior () en el método OnShow.
Deseo: establecer el tamaño inicial (ancho, alto) y tal vez también la posición inicial (izquierda, arriba) de un formulario antes de mostrarlo, pero ese formulario debe mostrarse maximizado; tal posición y tamaño son para cuando el usuario no maximiza la ventana.
Ese ShowWindowAsync
funciona perfecto para tal objetivo, y no es necesario agregar un temporizador feo (con interval = 1 y .Enabled = False en su código como primera oración).
¡Cómo podría extrañarlo cuando leí la publicación!
Entonces, ahora voy a usar (solo como ejemplo, el tamaño inicial relativo al monitor):
procedure TtheForm.FormShow(Sender: TObject);
var
theInitialDefaultWidth,theInitialDefaultHeight:Integer;
begin
theInitialDefaultWidth:=Round(Screen.Width*3/5);
theInitialDefaultHeight:=Round(Screen.Height*3/5);
WindowState:=wsNormal; // So it can still have at design time wsMaximized, this is for the SetBounds to work on a non maximized state
SetBounds((Screen.Width-theInitialDefaultWidth)div 2,(Screen.Height-theInitialDefaultHeight)div 2,theInitialDefaultWidth,theInitialDefaultHeight); // Set default position and default size as i wish
ShowWindowAsync(Handle,SW_MAXIMIZE); // Make the window to be shown maximized when it will be visible
// ... // Rest of actions for the FormShow method
end;
Funciona perfecto! No necesito tocar las propiedades del tiempo de diseño, puedo dejarlas tal como están (WindowState = wsMaximized, Position = poScreenCenter, etc.). Solución de código 100% para el problema.
¡Muchas gracias!
PD: ¿Funcionará en Linux? Quiero decir, cuando el código se compila para Linux (en Lazarus), debo probarlo y ver si funciona, será un gran avance en lo que estaba usando hasta ahora.
Establecer un formulario para WindowState = wsMaximized
a veces hará que el formulario se maximice pero no:
Error de larga duración: esta es una pregunta que hice por primera vez en los grupos de noticias de Borland en 2003:
y luego nuevamente en 2006:
y luego nuevamente en 2008:
Alguien lo preguntó en los foros de Embarcadero en 2012:
Ahora es el momento de convertir el error de 18 años a Stackoverflow. Quizás alguien finalmente descubrió una solución alternativa.
Pasos para reproducirse :
Mis publicaciones contenían media docena de modos de falla, pero la más fácil es:
Coloque una
Label
y unaEdit
en un formulario:Agregue un evento
OnEnter
para elTEdit
:procedure TForm1.Edit1Enter(Sender: TObject); begin Label1.Font.Style := Label1.Font.Style + [fsBold]; end;
y establecer la forma:
-
WindowState
a wsMaximized -
AutoScroll
a falso
-
Y bazinga, falla.
Uno de los otros pasos de la publicación de 2008:
- Crea una nueva aplicación y un formulario.
- Establezca el formulario maximizado (WindowState = wsMaximized) en el momento del diseño.
- Coloque un control ListView en el formulario
Durante OnShow, agregue 20 elementos vacíos a la vista de lista:
procedure TForm1.FormShow(Sender: TObject); var i: Integer; begin for i := 1 to 20 do ListView1.Items.Add; end;
Establezca la propiedad AutoScroll del formulario en false (AutoScroll = False) en el momento del diseño
Por supuesto, lo que no busco es "arreglado en la versión n
de RadStudio. Solo use eso" . Estoy buscando una solución real (si hay una); que podría incluir la cita de cambios relevantes a la fuente de VCL cuando CodeGear finalmente lo solucionó. (Si es incluso fijo).
Nota: Cambiar la Position
de poDesigned a cualquier otra cosa no lo soluciona.
Solución
Una solución horrible, fea, horrible, repugnante, que había estado usando era iniciar un temporizador durante OnShow
, y luego, cuando el temporizador se dispara, maximiza la forma:
procedure TForm1.tmrVclMaximizeHackTimer(Sender: TObject);
begin
Self.WindowState := wsMaximized;
end;
Más tarde, mejoré este truco para publicar un mensaje durante OnShow
; que es esencialmente lo mismo que un mensaje de temporizador, sin tener que usar un temporizador:
const
WM_MaximizeWindow = WM_APP + $03;
procedure TForm1.FormShow(Sender: TObject);
begin
if (Self.WindowState = wsMaximized) then
begin
Self.WindowState := wsNormal;
PostMessage(Self.Handle, WM_MaximizeWindow , 0, 0);
end;
end;
private
procedure WMMaximizeWindow(var Message: TMessage); message WM_MaximizeWindow;
procedure TForm1.WMMaximizeWindow(var Message: TMessage);
begin
Self.WindowState := wsMaximized;
end;
A veces invento el evento OnAfterShow
que Delphi nunca hizo:
const
WM_AfterShow = WM_APP + $02;
procedure TForm1.FormShow(Sender: TObject);
begin
PostMessage(Self.Handle, WM_AfterShow, 0, 0);
if (Self.WindowState = wsMaximized) then
begin
Self.WindowState := wsNormal;
FMaximizeNeeded := True;
end;
end;
private
procedure WMAfterShow(var Message: TMessage); message WM_AfterShow;
procedure TForm1.WMAfterShow(var Message: TMessage);
begin
if FMaximizeNeeded then
begin
FMaximizeNeeded := False;
Self.WindowState := wsMaximized;
end;
end;
Pero ningún hack es mejor que hacks.
Espero que la solución que uso ayude a otros (la ventana conocida se muestra por primera vez con el tamaño del tiempo de diseño):
- Agregue un temporizador con intervalo tan solo como 1 (no ponga 0).
- Código para ello:
theTimer.Enabled:=False;WindowState:=wsMaximized;
Nunca me falla.
Tan pronto como se muestre la forma y todas las tareas pendientes para dicho espectáculo hayan finalizado, se activarán los disparadores del temporizador y se maximizará la ventana.
Hace algún tiempo, estaba usando el truco de enviar un clic del mouse donde estaba el botón Maximizar, pero descubrí que comprobar la versión del sistema operativo Windows, los complementos (en Linux), etc. hace que la cosa sea tan difícil. Ese trabajó exactamente como si el usuario pidiera maximizar la ventana.
El temporizador que uso ahora hace exactamente lo mismo, pero evita la verificación del sistema operativo, etc.
Sin mencionar: Ponga WindowState en wsNormal en DesignTime (no lo configure en wsMinimized ni en wsMaximized).
No creo que esto sea un error en Delphi, sino un error (o simplemente un comportamiento extraño) en la función Windows CreateWindow. Si busca CreateWindow y WS_MAXIMIZE que no funciona, encontrará conversaciones y discusiones muy similares entre personas que llaman a CreateWindow o CreateWindowEx pasando WS_MAXIMIZE en el parámetro de estilo y no viendo una ventana maximizada cuando ejecutan la aplicación.
Extracto de un viejo hilo de gamedev.net
el problema es que WS_MAXIMIZE aparentemente no se aplica cuando se usa WS_OVERLAPPEDWINDOW. si reemplaza WS_OVERLAPPEDWINDOW con WS_POPUP, obtendrá una ventana maximizada. por supuesto, esto puede no aplicarse a todas las versiones de Windows, o incluso a todas las versiones de la interfaz de usuario del shell de Windows.
WS_OVERLAPPEDWINDOW es el "tipo" de ventana predeterminado de MS y aparentemente codificó CreateWindow / Ex para ignorar ciertos estilos, pensando que ShowWindow se llamaría con SW_SHOWDEFAULT, lo que hace que la ventana se muestre de acuerdo con los parmetros de información de inicio de CreateProcess. esto finalmente le da al usuario el control de cómo se mostraría la ventana principal de una aplicación utilizando la configuración de acceso directo del shell.
La solución alternativa es simplemente llamar a ShowWindow. Debería funcionar en Delphi, también:
procedure TForm1.FormShow(Sender: TObject);
begin
ShowWindow(Handle, SW_MAXIMIZE);
end;
Puedo reproducir con D7 / Win7.
No utilizo wsMaximized
en absoluto (problemas aleatorios similares a los que describes).
Solución alternativa: use OnActivate
-> ShowWindow(Handle, SW_MAXIMIZE)
por ejemplo:
procedure TForm1.FormActivate(Sender: TObject);
begin
// Maximize only once when the Form is first activated
if not FMaxsimized then
begin
FMaxsimized := True;
ShowWindow(Handle, SW_MAXIMIZE);
end;
end;
Este método no funcionará durante OnShow
.
Mejor solución alternativa: use ShowWindowAsync
durante OnShow
o OnCreate
por ejemplo:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowWindowAsync(Handle, SW_MAXIMIZE);
end;
Esto establece el estado del espectáculo de una ventana sin esperar a que se complete la operación.
Solo probé la primera carcasa de reproducción (con D7, D2007, XE2) y puedo duplicar el problema con D7 y D2007 pero no con XE2.
El problema, según lo veo, es que la etiqueta, al cambiar su fuente, solicita a su padre que se vuelva a alinear. Esto finalmente lleva a una llamada a SetWindowPos
en el formulario (en TWinControl.AdjustSize
) con ancho / alto restaurado aunque el formulario ya esté maximizado, lo que lleva a que la forma extraña, maximizada en el comportamiento pero no maximizada visualmente , se asiente en la pantalla.
TWinControl.AlignControls
es diferente entre las dos versiones. Lo que importa específicamente es la última declaración. D2007:
procedure TWinControl.AlignControls(AControl: TControl; var Rect: TRect);
..
{ Apply any constraints }
if Showing then AdjustSize;
end;
XE2:
procedure TWinControl.AlignControls(AControl: TControl; var Rect: TRect);
..
// Apply any constraints
if FAutoSize and Showing then
DoAdjustSize;
end;
Espero que esto, de alguna manera, te ayude a diseñar / decidir qué solución usar.
La solución alternativa que podría sugerir (aunque no lo he probado a fondo) es forzar a mostrar la forma maximizada tempranamente:
procedure TForm1.FormCreate(Sender: TObject);
var
wplc: TWindowPlacement;
begin
if not AutoScroll and (WindowState = wsMaximized) then begin
wplc.length := SizeOf(wplc);
GetWindowPlacement(Handle, @wplc);
wplc.rcNormalPosition.Right := wplc.rcNormalPosition.Left + Width;
wplc.rcNormalPosition.Bottom := wplc.rcNormalPosition.Top + Height;
wplc.showCmd := SW_MAXIMIZE;
SetWindowPlacement(Handle, @wplc);
end;
end;
Lo anterior funciona porque obliga a establecer el foco en el control de edición (evento OnEnter
) antes de que la VCL establezca el indicador visible para la forma. A su vez, la solicitud de alineación de la etiqueta no da como resultado el ajuste del tamaño del formulario. Además, dado que, cuando VCL llama a ShowWindow
la ventana del formulario ya está visible, no hace que el formulario se muestre en estado restaurado en ningún momento.
Sin embargo, no sé si ayudaría con diferentes escenarios de reproducción.
Finalmente, aunque puedo ver que el comportamiento se corrige en las versiones más nuevas de Delphi, no consideraría que esto sea un error en el VCL. En mi opinión, el código de usuario debe ser responsable de no causar el ajuste de la ventana mientras que la ventana que muestra el estado está cambiando. El curso de acción que tomaría para el escenario específico sería diferir para modificar la fuente de la etiqueta hasta que el VCL termine de mostrar el formulario.