Закрыть диалог 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;
и проверить его.
Форма закрывается автоматически, когда таймер завершает обратный отсчет. Подобный это можно добавить другие типы компонентов.
С уважением.
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, или позвоните сами.