Aktif olmayan forma veri çekme

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
dogan
Üye
Mesajlar: 173
Kayıt: 17 Eki 2014 10:11

Aktif olmayan forma veri çekme

Mesaj gönderen dogan »

Merhabalar...


Projeme ek olarak hatırlatma ekliyorum, kullanıcıya belirlediği tarih ve saat de ekrana uyarı gelecek, buraya kadar sorun yok.

Tarih ve saat kontrol için timer kullandım; Databaseden verileri timer ile her saniye kontrol etmemek için verileri listviewe listeleyerek oradan kontrol ediyorum.

Hatırlatma tarih ve saat bilgileri form2 deki listviewde listelendiğin den bu form aktif olmadığında hatırlatma çalışmıyor; Bu durumu nasıl çözebilirim?

Timer kontrol

Kod: Tümünü seç

procedure TANAForm.TimerHatirlatmaTimer(Sender: TObject);
var
  Saat1, Saat2: String;
begin
  with TFDQuery.Create(Nil), Form2.ListViewHT do
    try
      if Items.Count < 0 then
      begin
        // TimerHatirlatma.Enabled := False;
      end;
      if Items.Count > 0 then
      begin
        for J := Items.Count - 1 downto 0 do
        begin
          Saat1 := Copy(Items[J].SubItems[1], 1, 5);
          Saat2 := FormatDateTime('hh:nn', Time); if (StrToTimeDef(Items[J].SubItems[0], Date) = (Date)) And  (Saat1 = Saat2) And (Pos(Items[J].SubItems[3], 'Yeni') > 0) then
          begin
            ImageMesaj.Visible := True;
          end;
        end;
      end;
    finally
    end;
end;
Form2 listview

Kod: Tümünü seç

procedure TForm2.HatirlatmaListele(Sender: TObject);
begin
  With TFDQuery.Create(Nil) do
  begin
    Connection := ANAForm.GenelConnection;
    Close;
    SQL.Clear;
    SQL.Add('Select * From HATIRLATMA');
    SQL.Add('Order By TARIH ASC, SAAT');
    SQL.Add('Limit 0,100');
    Prepared := True;
    Open;
    ListViewHT.Items.BeginUpdate;
    try
      ListViewHT.Items.Clear;
      while Not Eof do
      begin
        with ListViewHT.Items.Add do
        begin
          Caption := IntToStr(FieldByName('ID').AsInteger);
          SubItems.Add(FieldByName('TARIH').AsString);
          SubItems.Add(Copy(FieldByName('SAAT').AsString, 1, 5));
          SubItems.Add(FieldByName('HATIRLATMAMESAJI').AsString);
          SubItems.Add(FieldByName('DURUM').AsString);
          Next;
        end;
      end;
    finally
      ListViewHT.Items.EndUpdate;
    end;
  end;
end;
ertank
Kıdemli Üye
Mesajlar: 1711
Kayıt: 12 Eyl 2015 12:45

Re: Aktif olmayan forma veri çekme

Mesaj gönderen ertank »

Merhaba,

Öncelikle mevcut kod ile ilgili bir iki noktaya dikkat çekmek istiyorum.
1- Ana form içindeki kodunuzda hafıza kaçağı var. Create edilen FDQuery nesnesi Free edilmemiş.
2- Form2 içindeki kodunuzda da hafıza kaçağı mevcut. Yine create edilen FDQuery nesnesi Free edilmemiş.
3- Mümkün olduğunca "with" ifadesini kullanmaktan kaçının. Kodu karmaşıklaştırır.
4- Mümkünse hiçbir zaman "with TFDQuery.Create(nil) do" şeklinde bir kod yazmayın. Bunun yerine değişken tanımlayarak. Bu değişkene yeni create edilen bir TFDQuery nesnesini atayarak ve try..finally bloğu içinde kod yazmaya gayret edin. Form2 için yazmış olduğunuz kod aşağıdaki gibi yazılabilir. Böylece hafıza kaçağını önlemiş olursunuz

Kod: Tümünü seç

procedure TForm2.HatirlatmaListele(Sender: TObject);
var
  Query: TFDQuery;
begin
  Query := TFDQuery.Create(nil);
  try
    Query.Connection := ANAForm.GenelConnection;
    Query.SQL.Add('Select * From HATIRLATMA');
    Query.SQL.Add('Order By TARIH ASC, SAAT');
    Query.SQL.Add('Limit 0,100');
    Query.Prepared := True;
    Query.Open();
    Query.First();
    ListViewHT.Items.BeginUpdate();
    try
      ListViewHT.Items.Clear();
      while Not Query.Eof do
      begin
        with ListViewHT.Items.Add do
        begin
          Caption := IntToStr(Query.FieldByName('ID').AsInteger);
          SubItems.Add(Query.FieldByName('TARIH').AsString);
          SubItems.Add(Copy(Query.FieldByName('SAAT').AsString, 1, 5));
          SubItems.Add(Query.FieldByName('HATIRLATMAMESAJI').AsString);
          SubItems.Add(Query.FieldByName('DURUM').AsString);
          Query.Next();
        end;
      end;
    finally
      ListViewHT.Items.EndUpdate();
    end;
  finally
    Query.Free();
  end;
end;
Kod yazma alışkanlığınıza istinaden projenizde başka yerde/yerlerde de hafıza kaçağı olabileceğini düşünüyorum. Bu anlamda kodunuzu incelemenizde fayda var. Uygulamada hafıza kaçağı kontrolü için Project->View Source kısmına gelerek gelen kod ekranında begin ifadesinin hemen altına

Kod: Tümünü seç

ReportMemoryLeaksOnShutdown := True;
ifadesini eklemeniz yeterli. Bu durumda uygulama tamamen kapatıldığı zaman hafıza kaçağı varsa eğer ekrana bunu gösteren bir mesaj gelecektir. Hafıza kaçağı yoksa herhangi bir mesaj gelmez. Ancak bu şekilde uygulama içinde girip çıktığınız tüm ekranlardaki tüm kaçaklar listelenecektir. Bu anlamda nereleri açıp kapattığınızı veya tıkladığınızı hatırlamanız, her defasında sadece bir formu kontrol etmeniz ve sorun yok ise diğer forma geçmeniz gerekebilir.

Esas sorunuza gelince:
A- Database içinde hatırlatma tarih ve saati saklandığı yazılan kod içinden anlaşılıyor. Kullanıcı bir kayıt ekleyip daha sonra bu kayda ait tarih ve/veya saati değiştirdiğini düşünün. Eğer database kopyasını hafızada tutar iseniz bu durumda yanlış zamanda hatırlatma yapmış olursunuz.

Diğer bir olasılık ise; kullanıcı bir hatırlatma ekledi. Uygulama hatırlatmaları hafızaya aldı. Daha sonra kullanıcı bir hatırlatma daha ekledi. Üstelik bu ikinci eklediği hatırlatmayı daha yakın bir zaman için ekledi. Uygulama bu durumda da hatırlatma olmasına rağmen ekranda göstermiyor olabilir. Bu anlamda her kontrol zamanında hatırlatma mesajlarını database'den sorgulamak en doğrusu olacaktır.

B- Database sisteminin sürekli sorgulanmasını engellemek adına hatırlatma zamanlarını kayıt esnasında 15 dakika aralıklar ile (0, 15, 30, 45nci dakikalar gibi) yapılmasını zorlar iseniz Timer sadece 15 dakikada bir çalışabilir. Bu da sistem ve database yükünü oldukça azaltacaktır. Eğer 15 dakika uzun ise 10 veya 5 dakikalık aralıkları zolayabilirsiniz. Diğer taraftan 15 dakikanın oldukça yeterli olacağını düşünüyorum. Unutulmamalıdır ki sürekli çalışan ve/veya internet bağantısına sahip bilgisayar saatleri dahi birkaç dakikalık fark ile çalışabilmektedir (Anlık dahi olsa CPU yoğunluğu sistem saatinin normalden azar azar sapmasına sebep olur). Her halukarda saniyelik kontrol yapılmasına gerek olmayacaktır. Yazılan kod saniyelik kısımları kontrol etmiyor.

C- Kontrol yapılacak kodu (OnTimer içine yazılan kod) yazarken tüm kaytıları listelemek yerine sadece zamanı gelmiş ve geçmiş kayıtları listeler iseniz database üzerinden okunacak veri çok daha az ve işlem daha hızlı olacaktır. Bununla birlikte eğer eski mesajlar önemli değil ise tablodan silinmeleri, önemli ise farklı bir tablo/database içine arşivlenmeleri sorgu performansını artıracaktır.

D- Performansı birazcık daha artırmak adına kontrol için kullanılan Query form üzerinde dizayn aşamasında oluşturulup sadece parametreleri değiştirilerek çalıştırılabilir. Böylece her OnTimer çalıştığında TFDQuery nesnesi oluşturmasına gerek kalmayıp prosesin daha çabuk bitmesini sağlayabilirsiniz.

Yukarıdaki tavsiyeler göz önünde bulundurularak aşağıdaki gibi bir kod yazmak mümkün olabilir.

Ana form create kısmına yazılacak kod (form üzerinde MessageCheckQuery adında bir FDQuery nesnesi olduğunu varsayıyor)

Kod: Tümünü seç

procedure TANAForm.FormCreate(Sender: TObject);
begin
  MessageCheckQuery.Close();
  MessageCheckQuery.Connection := GenelConnection;
  MessageCheckQuery.SQL.Clear();
  MessageCheckQuery.SQL.Add('Select * From HATIRLATMA');
  MessageCheckQuery.SQL.Add('where Tarih <= :Tarih and Saat <= :Saat');
  MessageCheckQuery.SQL.Add('and DURUM=''Yeni''');
  MessageCheckQuery.Prepared := True;
end;
Timer kısmına yazılacak kod

Kod: Tümünü seç

procedure TANAForm.TimerHatirlatmaTimer(Sender: TObject);
var
  ControlTime: TDateTime;
begin
  // Kontrol başlat başlamaz Timer durdurulmalı
  TimerHatirlatma.Enabled := False;
  ControlTime := now;

  MessageCheckQuery.Close();
  MessageCheckQuery.Params[0].AsDate := DateOf(ControlTime);
  MessageCheckQuery.Params[1].AsTime := TimeOf(ControlTime);
  MessageCheckQuery.Open();
  if MessageCheckQuery.RecordCount > 0 then
  begin
    MessageCheckQuery.First();
    while not MessageCheckQuery.Eof do
    begin
      // Her bir hatırlatma için tek tek ekrana mesajları göster
      ImageMesaj.Visible := True;
      MessageCheckQuery.Next();
    end;
  end;

  MessageCheckQuery.Close();

  TimerHatirlatma.Enabled := True;
end;
Kullanıcı avatarı
dogan
Üye
Mesajlar: 173
Kayıt: 17 Eki 2014 10:11

Re: Aktif olmayan forma veri çekme

Mesaj gönderen dogan »

Çok teşekkür ederim gerçek anlamda faydalı bir bilgi oldu. Allah işinizi rast getirsin...
Cevapla