2014-09-11 3 views
-2

Я хочу, чтобы моя форма закрылась, когда дело дошло до 06:00, 12:00 и 24:00. Но перед закрытием я хотел бы отобразить индикатор выполнения, показывающий , сколько времени осталось до закрытия формы (когда ход бар достигает 100% - форма закрывается). Как я могу это сделать?Заполните форму на определенное время дня

Edit: я делал это:

procedure TMainForm.Timer1Timer(Sender: TObject); 
begin 
Timer1.Enabled := False; 
AdvOfficeStatusBar1.Panels[4].Progress.Position := AdvOfficeStatusBar1.Panels[4].Progress.Position +1; 
if AdvOfficeStatusBar1.Panels[4].Progress.Position = 100 then begin 
MainForm.Close; 
end; 
Timer1.Enabled := True; 
end; 

Так что мне нужно, это, возможно, еще один таймер, который обнаруживает бы время дня и огня на определенное время прогресс бар (Timer1.Enabled: = True ;). Как вы определяете правильное время в коде?

+0

Поставьте таймер и индикатор. В интервале таймера вычислите оставшееся время и соответствующим образом обновите индикатор выполнения. Когда вы достигнете 100%, закройте. –

+0

Я не уверен, как это сделать. Вам нужны 2 таймера? Один, чтобы определить время и другое, чтобы манипулировать индикатором выполнения? – user3927897

+0

Какова горизонтальная шкала времени в баре? –

ответ

5

Я предлагаю вам исследовать Waitable таймеры. Они могут быть настроены на срабатывание по истечении определенного периода времени (например, обычного TTimer) или в указанное время суток, что в точности соответствует именно вам.

В вашей форме создайте/покажите событие, создайте ожидаемый таймер и установите его в требуемое время, которое вы хотите, чтобы он «загорелся» (это будет только один из ваших ближайших кандидатов, т. Е. Следующий из них произойдет после текущее время). В вашем случае, я полагаю, вы упомянули, что обратный отсчет начинается за 90 секунд до закрытия, так что это ваше «время» для ожидаемого таймера (следующий T - 90 секунд).

Необходимое время должно быть указано в FILETIME и должно быть в UTC, а не по местному времени. Это неудобно, но не особенно сложно.

Рассчитать следующее время автоспуска, менее 90 секунд. Затем используйте DateTimeToSystemTime (localTDateTime, localSYSTEMTIME) к полученному TDateTime значение в SYSTEMTIME представления в которой вы можете перейти к TzSpecificLocalTimeToSystemTime() преобразовать в UTC SYSTEMTIME.

Оттуда вы просто затем преобразовать ваш UTC SYSTEMTIME к FILETIME (SystemTimeToFileTime() в SysUtils).

Обратный вызов proc - это первый класс proc, а не метод формы и должен соответствовать ожидаемой сигнатуре обратного вызова.

Обратный вызов будет вызываться в отдельном потоке, поэтому ваша реализация обратного вызова для запуска таймера обратного отсчета должна быть потокобезопасной. Самый простой способ добиться этого - использовать очереди сообщений и просто отправить (или отправить) сообщение в форму, которая в свою очередь отвечает, запустив таймер обратного отсчета. Чтобы обеспечить использование дескриптора правого окна, это может быть передано процессу обратного вызова. Так как HWND вписывается в указатель, вы можете просто передать HWND в указателе напрямую, путем приведения типов.

Ваш обратный вызов прок будет выглядеть примерно так:

procedure TimerCallbackProc(aData: Pointer; aTimerLo, aTimerHi: DWORD); 
begin 
    PostMessage(HWND(aData), MM_STARTCOUNTDOWNTIMER, 0, 0); 
end; 

Где MM_STARTCOUNTDOWNTIMER является частным, WM_USER на основе сообщений о том, что форма ручки для запуска таймера обратного отсчета:

ПРИМЕЧАНИЕ: Ваша форма должна отменить таймер обратного вызова, когда он закрыт, либо до того, как таймер «выстрелил», либо в результате этого.

Собираем все это вместе, вы должны в конечном итоге что-то вроде:

const 
    MM_STARTCOUNTDOWNTIMER = WM_USER + 1; 


type 
    TMyForm = class(TForm) 
    fCloseCountdownTimer: TTimer; 
    fCloseTimer: HANDLE; 
    .. 
    procedure MMStartCountdownTimer(var aMessage: TMessage); message MM_STARTCOUNTDOWNTIMER; 
    end; 


    procedure TMyForm.FormCreate(Sender: TObject); 
    begin 
    .. 

    .. 
    fCloseTimer := CreateWaitableTimer(..); 
    SetWaitableTimer(fCloseTimer, dueTime, 0, TimerCallbackproc, Pointer(Handle), TRUE); 
    end; 


    procedure TMyForm.FormClose(Sender: TObject); 
    begin 
    CancelWaitableTimer(fCloseTimer); 
    end; 


    procedure TMyForm.MMStartCountdownTimer(var aMessage: TMessage); 
    begin 
    fCloseCountdownTimer.Enabled := TRUE; 
    end; 

ПРИМЕЧАНИЕ: Окончательное ИСТИНА параметр в вызове SetWaitableTimer() в коде выше гарантирует, что если система приостанавливается во время срабатывания таймера, затем система будет разбухать для обработки таймера. Если это не то, что вы хотите, просто пропустите FALSE, и таймер не разбудит спящую систему (но ваша форма не будет автоматически закрываться, если время истекло, когда система спала).

Для дальнейших и более конкретных деталей, я предлагаю вам обратиться к Waitable Timer API documentation from Microsoft

+1

Я знаю, что это более надежное решение, но у меня такое впечатление, что это довольно сложно понять и реализовать ОП. –

+2

Я попытался предоставить достаточно подробностей, чтобы вести их. Если это немного для OP, это может быть хорошей вещью - ведь растяжение себя - это эффективный способ обучения. :) – Deltics

0

Я думаю, аккуратный способ будет положить требуемое время в базе данных, и есть таблица проверки раза:

procedure TForm1.Timer1Timer(Sender: TObject); 
begin 
if FDTable1.Locate('Time',StrToTime(FormatDateTime('hh:mm:ss',now))]),[]) then 
begin 
.... 
+0

Я не понимаю, как это отвечает на ваш вопрос. –

+0

Таймерные проверки с таблицей, если требуется, в базе данных. Время, равное желаемому времени, затем запускает индикатор выполнения. – user3927897

+0

Это определение времени, которое вы хотите закрыть. Это другой вопрос. В приведенном выше вопросе задается вопрос о том, что индикатор прогресса отображается. –

1

Вам нужен только один таймер. Этот таймер будет сравнивать текущее время с временем (точками) назначения, определяя количество секунд между каждым временем. Если он находится в определенном диапазоне, он показывает и устанавливает индикатор выполнения. В противном случае он скрывает его.

Ниже приведена демонстрационная версия. Сохраните оба этих файла и добавьте их в свой проект. Когда вы запустите его, подождите 30 секунд, чтобы начать отсчет времени (время установлено на 2 минуты, а отсчет длится 90 секунд до закрытия).

Unit1.dfm

object Form1: TForm1 
    Left = 310 
    Top = 121 
    Caption = 'Form1' 
    ClientHeight = 188 
    ClientWidth = 562 
    Color = clBtnFace 
    Font.Charset = DEFAULT_CHARSET 
    Font.Color = clWindowText 
    Font.Height = -11 
    Font.Name = 'Tahoma' 
    Font.Style = [] 
    OldCreateOrder = False 
    OnCreate = FormCreate 
    PixelsPerInch = 96 
    TextHeight = 13 
    object Label1: TLabel 
    Left = 41 
    Top = 28 
    Width = 44 
    Height = 13 
    Caption = 'Close At:' 
    end 
    object Label2: TLabel 
    Left = 216 
    Top = 28 
    Width = 44 
    Height = 13 
    Caption = 'Warning:' 
    end 
    object lblSecondsLeft: TLabel 
    Left = 41 
    Top = 143 
    Width = 62 
    Height = 13 
    Caption = 'Seconds Left' 
    Visible = False 
    end 
    object ProgressBar1: TProgressBar 
    Left = 41 
    Top = 120 
    Width = 448 
    Height = 17 
    TabOrder = 0 
    Visible = False 
    end 
    object dtTime: TDateTimePicker 
    Left = 96 
    Top = 24 
    Width = 97 
    Height = 21 
    Date = 41893.905071574070000000 
    Time = 41893.905071574070000000 
    Kind = dtkTime 
    TabOrder = 1 
    end 
    object BitBtn1: TBitBtn 
    Left = 392 
    Top = 25 
    Width = 97 
    Height = 21 
    Caption = 'Save' 
    TabOrder = 2 
    OnClick = BitBtn1Click 
    end 
    object txtWarning: TEdit 
    Left = 272 
    Top = 25 
    Width = 97 
    Height = 21 
    TabOrder = 3 
    Text = '90' 
    end 
    object Timer1: TTimer 
    OnTimer = Timer1Timer 
    Left = 360 
    Top = 72 
    end 
end 

Unit1.pas

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ComCtrls, 
    Vcl.ExtCtrls; 

type 
    TForm1 = class(TForm) 
    ProgressBar1: TProgressBar; 
    dtTime: TDateTimePicker; 
    BitBtn1: TBitBtn; 
    Timer1: TTimer; 
    Label1: TLabel; 
    Label2: TLabel; 
    txtWarning: TEdit; 
    lblSecondsLeft: TLabel; 
    procedure BitBtn1Click(Sender: TObject); 
    procedure Timer1Timer(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    private 

    public 
    CloseTime: TDateTime; 
    SecondsToClose: Integer; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

uses 
    DateUtils; 

procedure TForm1.BitBtn1Click(Sender: TObject); 
begin 
    Timer1.Enabled:= False; 
    CloseTime:= dtTime.Time; 
    SecondsToClose:= StrToIntDef(txtWarning.Text, 90); 
    txtWarning.Text:= IntToStr(SecondsToClose); //sanity check 
    ProgressBar1.Max:= SecondsToClose; 
    Timer1.Enabled:= True; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    dtTime.DateTime:= DateUtils.IncMinute(Now, 2); 
    BitBtn1Click(nil); 
end; 

procedure TForm1.Timer1Timer(Sender: TObject); 
var 
    T: TDateTime; 
    Secs: Integer; 
begin 
    T:= Now; 
    Secs:= SecondsBetween(T, CloseTime); 
    if T >= CloseTime then begin 
    if Secs < 30 then //Only if within 30 seconds of close time 
     Close; 
    end else 
    if (Secs <= SecondsToClose) then begin 
    ProgressBar1.Visible:= True; 
    lblSecondsLeft.Visible:= True; 
    ProgressBar1.Position:= ProgressBar1.Max - Secs; 
    lblSecondsLeft.Caption:= IntToStr(Secs)+' Seconds Before Close'; 
    end else begin 
    ProgressBar1.Visible:= False; 
    lblSecondsLeft.Visible:= False; 
    end; 
end; 

end. 
+1

Учитывайте, что происходит, когда система меняет время перехода на летнее время. Или когда пользователь вручную меняет дату. Вы не должны полагаться на системное время. – TLama

Смежные вопросы