Timer ile programı kapatma

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
brs
Üye
Mesajlar: 626
Kayıt: 04 Eki 2012 03:52

Timer ile programı kapatma

Mesaj gönderen brs »

İyi akşamlar timer ile comboboxda verdiğim saat gelince programın kendini kapatmasını istiyorum fakat bir türlü şartlar eşit olmasına rağmen işlem gerçekleşmiyor...

Kod: Tümünü seç

procedure TForm1.KapatTimerTimer(Sender: TObject);
var
  Saat, Kapat: TDateTime;
begin
  Saat := Now;
  Kapat := StrToTime(SaatComboBox.Text);
  if Saat = Kapat then
  begin
    Showmessage('Kapandı');
  end;
end;
Not: Şartlar üstü ve eşit olduğunda değil sadece eşit olduğunda gerçekleşecek...
İşi bilen yardım eder, az bilen akıl verir, bilmeyen eleştirir, yapamayan ise çamur atar...
thelvaci
Kıdemli Üye
Mesajlar: 770
Kayıt: 11 Tem 2010 07:17
Konum: Istanbul
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen thelvaci »

Kesin hassasiyet ve sonuç için size CreateWaitableTimer öneririm. Aynı zamanda boş yere TTimer nesnesi de kullanmazsınız.

Aşağıdaki linkten malumat elde edebilirsiniz;

viewtopic.php?f=2&t=33188&p=179027#p179027
Kullanıcı avatarı
brs
Üye
Mesajlar: 626
Kayıt: 04 Eki 2012 03:52

Re: Timer ile programı kapatma

Mesaj gönderen brs »

Selam evet dediğiniz gibi timer tam zamanı yakalamalı, bende timerin tam zamanı yakalayamadığını düşüyorum verdiğiniz örneği inceledim oradaki işlem çok farklı...
İşi bilen yardım eder, az bilen akıl verir, bilmeyen eleştirir, yapamayan ise çamur atar...
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen mrmarman »

Bekleme süresince başka işlem yapılacak mıdır yoksa örneğin bir işlemin süresini tutumak gibi o iş bitene kadar zamanlanacak mıdır?

Bekleme hassasiyetini de belirtirsen iyi olur, saniye mertebesinde, milisaniye mertebesinde vb. hangisi ise ondan daha hızlı bir saat hızına ihtiyaç duyulur. Örneğin Dakika mertebesinde bir hassasiyet için Saniye, Saniye mertebesinde bir hassasiyet için MiliSaniye cinsinden takip gerekir.

10 saniye bekleyeceksin mesela, Timer'in intervalini 1000 verirsen olmaz. Bu yine 1 saniye 1 saniye takip edecektir. Bunu maksimum 500 olarak yani 1/2 saniye hassasiyette yapman gerekir. Sendeki TIMER'in intervalini bilmiyorum ama bence eşitliği tutturamamanın sebebi bu olmalı. :idea:

Eşitlik konusunda da diyeceğin bir şey var, saat, tarih sorgulamalarında eşittir hiç kullanmayı tercih etme. Büyüktür veya küçüktür içeren bir while işini sağlama almalısın.

Şimdi sana bir bekleme fonksiyonu örneği vereyin... Timer değil Windows'un gettickcount'undan nemalanacağız. Fonksiyonun dönüşü sana milisaniye cinsinden sapmayı söyleyecek... Testlerini yaparsın, seni kurtarırsa kullanırsın.

Kod: Tümünü seç

function Bekle( cSureSn:Cardinal ):Cardinal;
Var
  Bitis: Cardinal;
begin
  Bitis := GetTickCount + (cSureSn*1000);
  while GetTickCount < Bitis do
  begin
    Sleep(1);
    Application.ProcessMessages;
  end;
  Result := GetTickCount - Bitis;
end;
Kullanımı :

Kod: Tümünü seç

procedure TForm1.BitBtn1Click(Sender: TObject);
Var
  Basla, Bitis:TTime;
  Sapma : Cardinal;
begin
  Basla := Now;
  Sapma := Bekle(10);
  Bitis := Now;
  ShowMessageFmt('Başla: %s, Bitiş: %s'#13'Beklerkenki Sapma = %d milisaniye', [TimeToStr(Basla), TimeToStr(Bitis), Sapma]);
end;
aşağıda ardışık bir kaç deneme yaptım. Ekseriyetle (0) milisaniye sapma ile başarılı sonuç geldi ama (2) defa (15) milisaniyelik gecikme oldu.
Tabi ölçme değerlendirme de de milisaniyelik sapma vardır. Onun için QueryPerformanceFrequency ve QueryPerformanceCounter ikilisini kullanırız. Diğer forumda rastgele sayı üretme ve sıralama hızları testinde konu olmuştu belki rastlamışsındır.
Resim
Resim
Resim ....Resim
thelvaci
Kıdemli Üye
Mesajlar: 770
Kayıt: 11 Tem 2010 07:17
Konum: Istanbul
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen thelvaci »

brs yazdı:Selam evet dediğiniz gibi timer tam zamanı yakalamalı, bende timerin tam zamanı yakalayamadığını düşüyorum verdiğiniz örneği inceledim oradaki işlem çok farklı...
Çok farklı ?
thelvaci
Kıdemli Üye
Mesajlar: 770
Kayıt: 11 Tem 2010 07:17
Konum: Istanbul
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen thelvaci »

Aşağıdaki kodu inceleyebilirsiniz;

Kod: Tümünü seç

  TScheduler = record
  public
    class procedure Schedule(const ADateTime : TDateTime; const AProc : TProc); static;
  end;

{ TScheduler }

class procedure TScheduler.Schedule(const ADateTime: TDateTime; const AProc: TProc);
begin
  TThread.CreateAnonymousThread(
                                procedure
                                type
                                  TInt64Rec = record
                                    Lo : DWord;
                                    Hi : DWord;
                                  end;
                                var
                                  SysTime       : TSystemTime;

                                  Target,
                                  FileTime      : TFileTime;

                                  I             : Int64;

                                  InternalTimer : THandle;

                                  wYear,
                                  wMonth,
                                  wDay,

                                  wHour,
                                  wMinute,
                                  wSecond,
                                  wMilliseconds  : Word;
                                begin
                                  DecodeDateTime(ADateTime, wYear, wMonth, wDay, wHour, wMinute, wSecond, wMilliSeconds);

                                  InternalTimer := CreateWaitableTimer(nil, false, nil);

                                  SysTime.wYear         := wYear;
                                  SysTime.wMonth        := wMonth;
                                  SysTime.wDayOfWeek    := 0;
                                  SysTime.wDay          := wDay;
                                  SysTime.wHour         := wHour;
                                  SysTime.wMinute       := wMinute;
                                  SysTime.wSecond       := wSecond;
                                  SysTime.wMilliseconds := wMilliseconds;

                                  SystemTimeToFileTime(SysTime, FileTime);
                                  LocalFileTimeToFileTime(FileTime, Target);

                                  TInt64Rec(I).Lo := Target.dwLowDateTime;
                                  TInt64Rec(I).Hi := Target.dwHighDateTime;

                                  SetWaitableTimer(InternalTimer, I, 0, nil, nil, false);
                                  WaitForSingleObject(InternalTimer, INFINITE);

                                  TThread.Synchronize(
                                                      TThread.CurrentThread,

                                                      procedure
                                                      begin
                                                        AProc;
                                                      end
                                                     );
                                end
                               ).Start;
end;
Kullanımı;

Kod: Tümünü seç

procedure TForm1.Button2Click(Sender: TObject);
var
  ADateTime : TDateTime;
begin
  ADateTime := EncodeDateTime(2014, 12, 14, SpinEdit1.Value, SpinEdit2.Value, SpinEdit3.Value, 0);

  TScheduler.Schedule(
                      ADateTime,

                      procedure
                      begin
                        form1.Memo1.Lines.Add('Occured at ' + DateTimeToStr(ADateTime));
                      end
                     );
end;
thelvaci
Kıdemli Üye
Mesajlar: 770
Kayıt: 11 Tem 2010 07:17
Konum: Istanbul
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen thelvaci »

Belki TThread.Synchronize kullanmak yerine TThread.Queue kullanmayı da tercih edebilirsiniz. Main thread bir başka thread'i WaitForSingleObject vb. bekleme metodları ile bekliyor ise; tam bu noktada Scheduler'da Synchronize çağrımında bulunur ise bir deadlock oluşma ihtimali kuvvetle muhtemeldir. Kodunuzu en iyi siz biliyorsunuz, dolayısı ile tercih sizin.
Kullanıcı avatarı
brs
Üye
Mesajlar: 626
Kayıt: 04 Eki 2012 03:52

Re: Timer ile programı kapatma

Mesaj gönderen brs »

Selam, Bilgisayarda sorun çıktı format atmak zorunda kaldım bu nedenden cevap yazamadım, yardımda bulunan thelvaci ve Muharrem üstada çok teşekkür ederim...
Kodların fazla kendime göre ufak değişiklik yapmadım, iki zamanın eşit olması yeterli oldu...

Kod: Tümünü seç

function Bekle(cSureSn: Cardinal): Cardinal;
var
  Bitis: Cardinal;
begin
  Bitis := GetTickCount + (cSureSn * 1000);
  while GetTickCount < Bitis do
  begin
    Sleep(1);
    Application.ProcessMessages;
  end;
  Result := GetTickCount - Bitis;
end;

procedure TForm3.Timer1Timer(Sender: TObject);
var
  Basla, Bitis: TTime;
  Sapma: Cardinal;
begin
  Basla := Now;
  Sapma := Bekle(0);
  Bitis := StrToTime(SaatComboBox.Text);
  if (TimeToStr(Basla) = TimeToStr(Bitis)) then
  begin
    Showmessage('Kapandı');
  end;
end;
İşi bilen yardım eder, az bilen akıl verir, bilmeyen eleştirir, yapamayan ise çamur atar...
thelvaci
Kıdemli Üye
Mesajlar: 770
Kayıt: 11 Tem 2010 07:17
Konum: Istanbul
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen thelvaci »

Tüm verdiğim örneklere rağmen yine Timer kullanmak hususunda ısrar ediyorsunuz sanırım, siz bilirsiniz elbette. Lâkin hatırlatmakta fayda var. Uzun süren bir işlem yapıyorsanız uygulamanızın main thread'inde; ve bu işlem sırasında GetMessage, PeekMessage çağrımlarına neden olan herhangi bir metodu çağırmıyorsanız; o süreç boyunca Timer mesajlarını almayacaksınız demektir. Bu da süre karşılaştırmasını yaptığınız timer kodunuzu risk altına sokacaktır.

Timer mesajları düşük öncelikli mesajlardır ve her daim üretilmezler. Uygulamanın ana thread'inin mesaj kuyruğunda daha yüksek öncelikli mesajlar var ise önce onlarla ilgilenilir. Ki, uygulamanın ana thread'inin mesaj kuyruğunun kontrol edilmediği durumlarda asla WM_TIMER mesajlarını alamayacaksınız, çünkü üretilmemiş olacaklar.

Örneğin; uygulamanızda mevcut çalışan bir TTimer'ınız ve onun bir OnTimer eventi olsun. Formunuza bir button atın ve altına Sleep(5000) gibi bir kod yazın. Timer intervaliniz 1000 ise; button'a bastığınız zaman 5 adet timer eventinin tetikleneceğini yada kuyruğa 5 adet timer mesajının ekleneceğini düşünüyor olabilirsiniz. Ancak bunun olmadığını göreceksiniz.

İçim elvermedi, bilgilendireyim istedim.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen mrmarman »

Benim mesajla da yanlış ifade ettim sanırım. Ben sadece milisaniye cinsinden bakış açısı sunmaya çalıştım. Oradaki bekle fonksiyonuna gerek yoktu çünkü.

Kendi kodunuzun bu haliyle sadece timer intervalini 1000'den düşük tutmanız yeterliydi.

Bekle fonksiyonunu kaldırın gitsin.

Tek dikkat edilecek husus; eşitlik kontrolünüz, 1000'in kaçta kaçı oranında ise o kadar defa tetiklenecektir. İşlem yapılırken bir daha yapılmaya çalışılacaktır. Arada eşitlik oluştuğu blokta timeri durdurun.
Resim
Resim ....Resim
Kullanıcı avatarı
esistem
Üye
Mesajlar: 464
Kayıt: 02 Eki 2007 11:22
İletişim:

Re: Timer ile programı kapatma

Mesaj gönderen esistem »

Selam,
Bu konuya bir başka bakış açısıda benden olsun. Bu tip bir işlemde ben olsam kesin sonuç için şunu yapardım.

Kod: Tümünü seç

Var // genel var bloğu
say : INTEGER;

procedure TForm1.FormCreate(Sender: TObject);
var
t1,t2:TDateTime;
Saat, Dakika, Saniye, Salise: Word;
begin
say:=0;
t1:=StrToDateTime(SaatComboBox.Text); // kapanış tarihi ve saati 

IF t1>Now THEN BEGIN
t2:=t1-now;
DecodeTime(t2, Saat, Dakika, Saniye, Salise);
SAY:=(Saat*60*60)+(Dakika*60)+Saniye;
                        END;
end;

// timer ın intervali pekte önemli değil 1 sn yada 5 sn olması pek fark etmez, milisaniye tutmaz ise sadece istediğiniz zamandan 5 sn sonra yada 10 sn sonra kapanır, ama kesin kapanır :)

procedure TForm1.Timer1Timer(Sender: TObject);
begin
IF SAY>0 THEN SAY:=SAY-1; 
IF SAY<=1 THEN BEGIN // 1 ise zaman geldi işlemi yap
Showmessage('Kapandı'); // veya terminate
                        END;  // 1 ise zaman geldi işlemi yap
end;
Cevapla