[x] 秒后关闭 Delphi 对话框

发布于 2024-10-08 07:04:58 字数 147 浏览 0 评论 0原文

是否可以让 Delphi 在一定时间后关闭 ShowMessage 或 MessageDlg 对话框?

我想在应用程序关闭时向用户显示一条消息,但不想让应用程序关闭超过 10 秒左右。

我可以让默认对话框在定义的时间后关闭,还是需要编写自己的表单?

Is it possible to get Delphi to close a ShowMessage or MessageDlg Dialog after a certain length of time?

I want to show a message to the user when the application is shut down, but do not want to stop the application from shutting down for more than 10 seconds or so.

Can I get the default dialog to close after a defined time, or will I need to write my own form?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

寄风 2024-10-15 07:04:59

如果您想连接计时器以关闭它,您可以连接 Screen.OnActiveFormChange 事件并使用

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

Screen.ActiveCustomForm

You can hook up the Screen.OnActiveFormChange event and use Screen.ActiveCustomForm if it is a interested form that you want to hook up the timer to close it

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

enjoy

青春有你 2024-10-15 07:04:59

最好的方法是使用stayontop表单并使用表单的alpha混合属性管理计数器消失,在计数结束时只需关闭表单,但是
该控件将在显示表单之前传递给所需的活动控件,这样,用户将收到一条自动消失的消息,并且不会阻止使用下一个功能,这对我来说非常酷的技巧。

Best way is to use a stayontop form and manage a counter to disappear using the alfpha blend property of the form, at the end of the count just close the form, but
the control will be passed to the active control needed before showing the form, this way, user will have a message which disappears automatically and wont prevent the usage of the next feature, very cool trick for me.

软糯酥胸 2024-10-15 07:04:59

您可以使用 WTSSendMessage 来执行此操作。

您可以在 中找到此内容JWA 库,或者您自己调用它。

You can do this with WTSSendMessage.

You can find this in the JWA libraries, or call it yourself.

蘸点软妹酱 2024-10-15 07:04:58

当模式对话框或系统消息框或类似活动(或打开菜单)时,您的应用程序实际上仍在工作,只是正在运行一个辅助消息循环来处理所有消息 - 发送或发布到它的所有消息,以及必要时它也会合成(并处理)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;

忽略了错误处理,但这应该可以帮助您开始。

Your application is actually still working while a modal dialog or system message box or similar is active (or while a menu is open), it's just that a secondary message loop is running which processes all messages - all messages sent or posted to it, and it will synthesize (and process) WM_TIMER and WM_PAINT messages when necessary as well.

So there's no need to create a thread or jump through any other hoops, you simply need to schedule the code that closes the message box to be run after those 10 seconds have elapsed. A simple way to do that is to call SetTimer() without a target HWND, but a callback function:

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 handling ommitted, but this should get you started.

夏九 2024-10-15 07:04:58

您可以尝试使用标准消息对话框来完成此操作。使用对话框中的 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;

并测试它。
当计时器倒计时结束时,窗体自动关闭。与此类似,您可以添加其他类型的组件。

alt text

问候。

You can try to do it with a standard Message dialog. Create the dialog with CreateMessageDialog procedure from Dialogs and after add the controls that you need.

In a form with a TButton define onClick with this:

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;

An the OnTimer property like this:

procedure TForm1.MyOnTimer(Sender: TObject);
begin

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

Define the variables and procedure:

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

And test it.
The form close automatically when the timer final the CountDown. Similar this you can add other type of components.

alt text

Regards.

分開簡單 2024-10-15 07:04:58

试试这个:

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

我已经使用这个有一段时间了;它是一种享受。

Try this:

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

I've been using this for quite some time; it works a treat.

温馨耳语 2024-10-15 07:04:58

好的。您有 2 个选择:

1 - 您可以创建自己的 MessageDialog 表单。然后,您可以使用它并添加一个 TTimer,它将在您需要时关闭表单。

2 - 您可以继续使用 showmessage 并创建一个将使用 FindWindow (查找消息对话框窗口)的线程,然后将其关闭。

我建议您使用自己的带有计时器的表格。它更干净、更容易。

OK. You have 2 choices:

1 - You can create your own MessageDialog form. Then, you can use it and add a TTimer that will close the form when you want.

2 - You can keep using showmessage and create a thread that will use FindWindow (to find the messadialog window) and then close it.

I recommend you to use you own Form with a timer on it. Its cleaner and easier.

≈。彩虹 2024-10-15 07:04:58

这在 Windows 98 和更新版本中工作得很好...

我不使用“MessageBoxTimeOut”,因为旧的 Windows 98 ME 没有它...

这个新函数的工作方式就像“CHARM”..

//add this过程

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('Alert'', "此消息将在 10 秒后关闭',10);

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

This works fine with windows 98 and newers...

I don't use the " MessageBoxTimeOut" because old windows 98, ME, doesn't have it...

this new function works like a "CHARM"..

//add this procedure

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;

////////////////////////////How Call It//////////////////

DialogBoxAutoClose('Alert'', "This message will be closed in 10 seconds',10);

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

养猫人 2024-10-15 07:04:58

MessageBox 在内部调用此函数并传递 0xFFFFFFFF 作为超时参数,因此它被删除的可能性很小(感谢 Maurizio)

MessageBox calls this function internally and pass 0xFFFFFFFF as timeout parameter, so the probability of it being removed is minimal (thanks to Maurizio for that)

心是晴朗的。 2024-10-15 07:04:58

我考虑过使用单独的线程,但它可能会让您陷入许多不必要的代码等。Windows 对话框根本不是为此而设计的。

你应该做你自己的表格。从好的方面来说,您可以使用带有倒计时功能的自定义代码/UI,就像定时对话框一样。

I thought about using a separate thread, but it's probably going to get you into a lot of unnecessary code etc. Windows dialogs were simply not made for this thing.

You should do your own form. On the good side, you can have custom code/UI with a countdown like timed dialog boxes do.

謸气贵蔟 2024-10-15 07:04:58

不会。ShowMessage 和MessageDlg 都是模态窗口,这意味着您的应用程序在显示它们时基本上处于暂停状态。

您可以设计自己的带有计时器的替换对话框。在 FormShow 事件中启用计时器,并在 FormClose 事件中禁用计时器。在 OnTimer 事件中,禁用计时器,然后关闭窗体本身。

No. ShowMessage and MessageDlg are both modal windows, which means that your application is basically suspended while they're displayed.

You can design your own replacement dialog that has a timer on it. In the FormShow event, enable the timer, and in the FormClose event disable it. In the OnTimer event, disable the timer and then close the form itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文