Закрыть диалог Delphi через [x] секунд

можно ли заставить Delphi закрыть диалог ShowMessage или MessageDlg через определенное время?

Я хочу показать сообщение пользователю, когда приложение выключено, но не хочу останавливать приложение от выключения в течение более 10 секунд или около того.

могу ли я закрыть диалоговое окно по умолчанию после определенного времени или мне нужно будет написать собственную форму?

11 ответов


ваше приложение на самом деле все еще работает, пока модальное диалоговое окно или системное окно сообщений или подобное активно (или когда открыто меню), просто выполняется вторичный цикл сообщений, который обрабатывает все сообщения - все сообщения, отправленные или отправленные на него, и он будет синтезировать (и обрабатывать) WM_TIMER и WM_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,но это должно заставить вас начать.


вы можете попробовать сделать это со стандартным диалоговым окном сообщения. Создайте диалог с процедурой 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

С уважением.


OK. У вас есть 2 варианта:

1 - Вы можете создать свою собственную форму MessageDialog. Затем, вы можете использовать его и добавить TTimer, который закроет форму, когда вы хотите.

2-Вы можете продолжать использовать showmessage и создать поток, который будет использовать FindWindow (чтобы найти окно messadialog), а затем закрыть его.

Я рекомендую вам использовать собственную форму с таймером. Его чище и проще.


попробуйте это:

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

Я использую это в течение некоторого времени; она работает лечить.


MessageBox вызывает эту функцию внутренне и передает 0xFFFFFFFF в качестве параметра тайм-аута, поэтому вероятность ее удаления минимальна (спасибо Маурицио за это)


Я думал об использовании отдельного потока, но, вероятно, это приведет вас к большому количеству ненужного кода и т. д. Диалоги Windows просто не были созданы для этой вещи.

вы должны сделать свою собственную форму. С хорошей стороны, вы можете иметь пользовательский код/пользовательский интерфейс с обратным отсчетом, как это делают временные диалоговые окна.


нет. ShowMessage и MessageDlg являются модальными окнами, что означает, что ваше приложение в основном приостановлено во время их отображения.

вы можете создать свой собственный диалог замены, которые есть таймер на нем. В событии FormShow включите таймер, а в событии FormClose отключите его. В событии OnTimer отключите таймер и закройте саму форму.


вы можете подключить экран.Onactiveformchange событие и использовать экран.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}

наслаждайтесь


это отлично работает с windows 98 и newers...

Я не использую "MessageBoxTimeOut", потому что у меня нет старой windows 98...

эта новая функция работает как "очарование"..

//добавить эту процедуру

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);

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


лучший способ-использовать форму stayontop и управлять счетчиком, чтобы исчезнуть, используя свойство alfpha blend формы, в конце подсчета просто закройте форму, но элемент управления будет передан активному элементу управления, прежде чем показывать форму, таким образом, у пользователя будет сообщение, которое автоматически исчезнет и не предотвратит использование следующей функции, очень классный трюк для меня.


вы можете сделать это с помощью WTSSendMessage.

вы можете найти это в библиотеки JWA, или позвоните сами.