2010-12-17 20 views
12

¿Es posible obtener Delphi para cerrar un ShowMessage o MessageDlg de diálogo después de un cierto período de tiempo?Cerca de diálogo después de Delphi segundos [x]

Quiero mostrar un mensaje al usuario cuando se cierra la aplicación, pero no quiero que la aplicación deje de cerrarse durante más de 10 segundos más o menos.

¿Puedo obtener el cuadro de diálogo predeterminado para cerrar después de un tiempo definido, o tendré que escribir mi propio formulario?

+0

http://blogs.msdn.com/b/oldnewthing/archive/2005/03/01/382380.aspx y http://blogs.msdn.com/b/oldnewthing/archive/2005/03/04 /385100.aspx –

Respuesta

10

Su aplicación es en realidad todavía trabajando mientras que un cuadro de mensaje de diálogo o el sistema modal o similar está activa (o mientras un menú está abierto), es sólo que un bucle de mensajes secundaria se está ejecutando, que procesa todos los mensajes - todos los mensajes enviados o publicados a ella, y sintetizará (y procesará) los mensajes WM_TIMER y WM_PAINT cuando sea necesario también.

Así que no hay necesidad de crear un hilo o saltar a través de otros aros, simplemente necesita programar el código que cierra el cuadro de mensaje para ejecutar después de que hayan transcurrido esos 10 segundos. Una forma sencilla de hacerlo es llamar SetTimer() sin un objetivo HWND, sino una función de devolución de llamada: manejo

procedure CloseMessageBox(AWnd: HWND; AMsg: UINT; AIDEvent: UINT_PTR; 
    ATicks: DWORD); stdcall; 
var 
    Wnd: HWND; 
begin 
    KillTimer(AWnd, AIDEvent); 
    // active window of the calling thread should be the message box 
    Wnd := GetActiveWindow; 
    if IsWindow(Wnd) then 
    PostMessage(Wnd, WM_CLOSE, 0, 0); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    TimerId: UINT_PTR; 
begin 
    TimerId := SetTimer(0, 0, 10 * 1000, @CloseMessageBox); 
    Application.MessageBox('Will auto-close after 10 seconds...', nil); 
    // prevent timer callback if user already closed the message box 
    KillTimer(0, TimerId); 
end; 

error omitido, pero esto debe empezar.

0

Pensé en usar un hilo por separado, pero es probable que te meta en un montón de código innecesario, etc. Los diálogos de Windows simplemente no estaban hechos para esto.

usted debe hacer su propia forma. En el lado bueno, puede tener código personalizado/UI con una cuenta atrás como los cuadros de diálogo de tiempo.

7

OK. Tiene 2 opciones:

1 - Puede crear su propio formulario MessageDialog. Luego, puede usarlo y agregar un TTimer que cerrará el formulario cuando lo desee.

2 - Puede seguir usando showmessage y crear un hilo que usará FindWindow (para encontrar la ventana de messadialog) y luego ciérrelo.

Te recomiendo que utilice propio formulario con un contador de tiempo sobre ella. Es más limpio y más fácil.

+1

Mira esto: http://www.delphipages.com/forum/showthread.php?t=166197 –

+0

Gracias, eso es lo que pensé y agregando un temporizador en el formulario era como hubiera ido - solo pensé en verificar los valores predeterminados :) –

+0

Ver mi respuesta para una tercera opción (simple). El cuadro de mensaje proporcionado por el sistema operativo tiene ventajas sobre el cuadro de diálogo del mensaje VCL (apariencia). – mghie

0

No. ShowMessage y MessageDlg son ventanas modales, lo que significa que su aplicación se suspende básicamente mientras se muestran.

Usted puede diseñar su propio diálogo de reemplazo que tiene un contador de tiempo sobre ella. En el evento FormShow, habilite el temporizador y en el evento FormClose deshabilítelo. En el evento OnTimer, deshabilite el temporizador y luego cierre el formulario.

+1

No sé a qué se refiere exactamente con "la aplicación se está suspendiendo", pero está mal, -1. Es perfectamente posible que se ejecute código mientras una ventana modal está activa. – mghie

7

Prueba esto:

function MessageBoxTimeOut(hWnd: HWND; lpText: PChar; lpCaption: PChar; 
    uType: UINT; wLanguageId: WORD; dwMilliseconds: DWORD): integer; 
    stdcall; external user32 name 'MessageBoxTimeoutA'; 

He estado usando esto por bastante tiempo; funciona un placer.

+0

Hm ...A Raymond Chen no le gusta cuando los desarrolladores usan las características ** indocumentadas ** de la API de Windows. Así que tengo que rechazar este. –

+1

Eso está bien; cuando está disponible para que lo use Microsoft, yo también lo uso. A cada cual lo suyo. – Restless

+1

Ejemplo de uso: http://edn.embarcadero.com/print/32736 –

10

Usted puede tratar de hacerlo con un mensaje de diálogo estándar. Cree el diálogo con el procedimiento CreateMessageDialog desde Diálogos y luego agregue los controles que necesita.

En un formulario con un TButton definir onClick con esto:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    tim:TTimer; 
begin 
    // create the message 
    AMsgDialog := CreateMessageDialog('This is a test message.',mtWarning, [mbYes, mbNo]) ; 
    lbl := TLabel.Create(AMsgDialog) ; 
    tim := TTimer.Create(AMsgDialog); 
    counter := 0; 

    // Define and adding components 
    with AMsgDialog do 
    try 
    Caption := 'Dialog Title' ; 
    Height := 169; 

    // Label 
    lbl.Parent := AMsgDialog; 
    lbl.Caption := 'Counting...'; 
    lbl.Top := 121; 
    lbl.Left := 8; 

    // Timer 
    tim.Interval := 400; 
    tim.OnTimer := myOnTimer; 
    tim.Enabled := true; 

    // result of Dialog 
    if (ShowModal = ID_YES) then begin 
     Button1.Caption := 'Press YES'; 
    end 
    else begin 
     Button1.Caption := 'Press NO'; 
    end; 
    finally 
    Free; 
    end; 
end; 

Una propiedad AlCronómetro así:

procedure TForm1.MyOnTimer(Sender: TObject); 
begin 

    inc(counter); 
    lbl.Caption := 'Counting: ' + IntToStr(counter); 
    if (counter >= 5) then begin 
    AMsgDialog.Close; 
    end; 
end; 

definir las variables y procedimiento:

TForm1 = class(TForm) 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    AMsgDialog: TForm; 
    lbl:TLabel; 
    counter:integer; 
    procedure MyOnTimer(Sender: TObject); 
    end; 

Y Pruébalo.
El formulario se cierra automáticamente cuando el temporizador finaliza el CountDown. De manera similar, puede agregar otro tipo de componentes.

alt text

Saludos.

0

se puede conectar el evento Screen.OnActiveFormChange y utilizar Screen.ActiveCustomForm si se trata de una forma interesada que desea conectar el temporizador para cerrarla

{code} 
procedure abz.ActiveFormChange(Sender: TObject); 
var 
    Timer: TTimer; 
begin 
    if (Screen.ActiveCutomForm <> nil) and //valid form 
    (Screen.ActiveCutomForm.Tag = 0) and //not attached a timer yet 
    (Screen.ActiveCutomForm.ClassName = 'TMessageForm') //any interested form type check 
    then 
    begin 
    Timer := TTimer.Create(Screen.ActiveCutomForm); // let the form owned so it will be freed 
    Timer.Enabled := False; 
    Timer.Tag := Integer(Screen.ActiveCutomForm); // keep track to be used in timer event 
    .... setup any timer interval + event 
    Screen.ActiveCutomForm.Tag := Integer(Timer); 
    Timer.Enabled := True; 
    end; 
end; 
{code} 

disfrutar

0

Esto funciona bien con las ventanas 98 y newers ...

yo no uso el "MessageBoxTimeOut" porque los viejos windows 98, mE, no tiene que ...

este nueva función funciona como un "encanto" ..

// añadir este procedimiento

procedure DialogBoxAutoClose(const ACaption, APrompt: string; DuracaoEmSegundos: Integer); 
var 
    Form: TForm; 
    Prompt: TLabel; 
    DialogUnits: TPoint; 
    ButtonTop, ButtonWidth, ButtonHeight: Integer; 
    nX, Lines: Integer; 

    function GetAveCharSize(Canvas: TCanvas): TPoint; 
    var 
     I: Integer; 
     Buffer: array[0..51] of Char; 
    begin 
     for I := 0 to 25 do Buffer[I]   := Chr(I + Ord('A')); 
     for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a')); 
     GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result)); 
     Result.X := Result.X div 52; 
    end; 

begin 
    Form  := TForm.Create(Application); 
    Lines := 0; 

    For nX := 1 to Length(APrompt) do 
    if APrompt[nX]=#13 then Inc(Lines); 

    with Form do 
    try 
     Font.Name:='Arial';  //mcg 
     Font.Size:=10;   //mcg 
     Font.Style:=[fsBold]; 
     Canvas.Font := Font; 
     DialogUnits := GetAveCharSize(Canvas); 
     //BorderStyle := bsDialog; 
     BorderStyle := bsToolWindow; 
     FormStyle   := fsStayOnTop; 
     BorderIcons  := []; 
     Caption   := ACaption; 
     ClientWidth := MulDiv(Screen.Width div 4, DialogUnits.X, 4); 
     ClientHeight := MulDiv(23 + (Lines*10), DialogUnits.Y, 8); 
     Position   := poScreenCenter; 

     Prompt    := TLabel.Create(Form); 
     with Prompt do 
     begin 
     Parent   := Form; 
     AutoSize  := True; 
     Left    := MulDiv(8, DialogUnits.X, 4); 
     Top    := MulDiv(8, DialogUnits.Y, 8); 
     Caption  := APrompt; 
     end; 

     Form.Width:=Prompt.Width+Prompt.Left+50; //mcg fix 

     Show; 
     Application.ProcessMessages; 
    finally 
     Sleep(DuracaoEmSegundos*1000); 
     Form.Free; 
    end; 
end; 

//////////////////////// //// Cómo Call It //////////////////

DialogBoxAutoClose ('Alerta'', "Este mensaje se cerrará en 10 segundos, 10);

////////////////////////////////////////////// ///////////

0

MessageBox llama a esta función internamente y pasar 0xFFFFFFFF como parámetro de tiempo de espera, por lo que la probabilidad de que sea eliminado es mínima (gracias a Maurizio para eso)

0

mejor manera es para usar un formulario stayontop y administrar un contador para que desaparezca usando la propiedad alfpha blend del formulario, al final del conteo solo cierre el formulario, pero el control pasará al control activo necesario antes de mostrar el formulario, de esta manera , el usuario tendrá un mensaje que desaparecerá automáticamente y no evitará el uso de la siguiente función, un truco muy bueno para mí.

Cuestiones relacionadas