2010-12-17 124 views
12

是否有可能在一定時間後讓Delphi關閉ShowMessage或MessageDlg對話框?[x]秒後關閉Delphi對話框

我想在應用程序關閉時向用戶顯示消息,但不想停止應用程序關閉超過10秒鐘左右。

我可以獲得默認對話框以在指定時間後關閉,還是需要編寫自己的表單?

+0

http://blogs.msdn.com/b/oldnewthing/archive/2005/03/01/382380.aspx和http://blogs.msdn.com/b/oldnewthing/archive/2005/03/04 /385100.aspx – 2010-12-17 22:31:50

回答

10

當模態對話框或系統消息框或類似項處於活動狀態(或菜單打開時)時,您的應用程序實際上仍在工作,它只是一個正在運行的處理所有消息的輔助消息循環 - 所有消息已發送或已發佈並在必要時合成(並處理)WM_TIMERWM_PAINT消息。

所以沒有必要創建一個線程或通過任何其他跳火圈,你只需要安排其關閉這10秒鐘過去後要運行的消息框代碼。一個簡單的方法來做到這一點是調用SetTimer()沒有目標HWND,而是一個回調函數:

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; 

錯誤處理ommitted,但這應該讓你開始。

0

我想過使用一個單獨的線程,但它可能會讓你陷入很多不必要的代碼等等.Windows對話框根本就不是用於這個東西的。

你應該做你自己的形式。好的一面是,你可以通過像定時對話框那樣的倒數計時器來定製代碼/ UI。

7

好的。您有2個選擇:

1 - 您可以創建自己的MessageDialog表單。然後,您可以使用它並添加一個TTimer,以便在需要時關閉表單。

2 - 您可以繼續使用showmessage並創建一個使用FindWindow的線程(查找messadialog窗口),然後關閉它。

我建議你使用你自己的窗體上有一個計時器。它更乾淨,更容易。

+1

看看這個:http://www.delphipages.com/forum/showthread.php?t=166197 – 2010-12-17 15:59:07

+0

謝謝,這就是我認爲,並在窗體上添加一個計時器是我會走的方式 - 只是認爲我會檢查默認值:) – 2010-12-17 16:04:54

+0

請參閱我的答案(簡單)第三選擇。操作系統提供的消息框優於VCL消息對話框(外觀和感覺)。 – mghie 2010-12-17 19:53:52

0

不,ShowMessage和MessageDlg都是模式窗口,這意味着您的應用程序在顯示時基本暫停。

您可以設計自己的替換對話框,其上有一個定時器。在FormShow事件中,啓用計時器,並在FormClose事件中禁用它。在OnTimer事件中,禁用計時器,然後關閉窗體本身。

+1

我不知道你的意思是什麼「應用程序被暫停」,但它是錯誤的,-1。在模態窗口處於活動狀態時執行代碼是完全可能的。 – mghie 2010-12-17 19:49:43

7

試試這個:

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

我一直在使用這個相當長的一段時間;它工作的一種享受。

+0

嗯...當開發人員使用Windows API的**未公開**功能時,Raymond Chen不喜歡它。所以我不得不在這個問題上倒下。 – 2010-12-17 17:39:56

+1

沒關係;當它可供Microsoft使用時,我也使用它。給每個人自己。 – Restless 2010-12-20 16:16:31

+1

使用示例:http://edn.embarcadero.com/print/32736 – 2013-11-05 09:53:52

10

您可以嘗試使用標準的消息對話框。使用對話框中的CreateMessageDialog過程創建對話框,然後添加所需的控件。

在具有一個TButton形式與該限定的onClick:

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; 

的OnTimer屬性是這樣的:

procedure TForm1.MyOnTimer(Sender: TObject); 
begin 

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

定義的變量和程序:

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

而測試它。
當定時器最終CountDown時,窗體自動關閉。類似的,你可以添加其他類型的組件。

alt text

問候。

0

您可以掛鉤的Screen.OnActiveFormChange事件並使用Screen.ActiveCustomForm如果要掛鉤定時器來關閉它

{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} 

享受興趣形式

0

這工作正常與Windows 98和newers ...

我不使用 「MessageBoxTimeOut」,因爲舊的Windows 98,ME,沒有它...

這新的功能就像一個 「魅力」 ..

//添加此過程

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; 

//////////////////////// ////怎麼稱呼它//////////////////

DialogBoxAutoClose('報警」,「該消息將在10秒內關閉,10);

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

0

MessageBox的內部調用此函數,並傳遞作爲0xFFFFFFFF的超時參數,所以它被移除的可能性是最小的(由於莫里吉奧爲該)

0

最好的辦法是使用stayontop形式和管理計數器使用形式的alfpha混合屬性,在計數結束剛剛關閉的形式消失,但 控制將被傳遞到顯示窗體之前所需的主動控制,這種方式,用戶將有一條消息自動消失,並且不會阻止下一個功能的使用,對我來說非常酷的技巧。