DefineProperties nedir, nasıl kullanılır..?

// 15 Mayıs 2009 // Delphi, Programlama

Sevgili Sadettin’in güzel anlatılmış nesne kopyalama örneğinden sonra Furkan arkadaşımızın yorumu bana bu makaleyi yazma ihtiyacı hissettirdi.Diyelim ki bir class tasarladık süsledik püsledik, cillop gibi oldu. Ama bu class’ımızı istediğimiz zaman hafızadaki o anki görünümü ile saklamak ve tüm özellikleri ile yine istediğimiz bir anda tekrar yüklemek istedik. Programcı değilmiyiz isteriz biz herşeyi ;)

Bunun için başladık araştırmalara nasıl saklarım nasıl yüklerim vs. diye..Birde baktık ki Sadettin bunun için birşeyler yazmış sağolsun.Biraz da Delphi Help’i kurcaladık, eh güzel artık yazabiliriz. Yazdık bitirdik, save de ettik. Bir yükledik baktıkkı sadece published property’ler saklanmış dolayısı ile onlar okunmuş.Haydaa dedik bu da ne ki şimdi..Object Inspector’a ihtiyacım yok ki benim bütün property’lerimi published tanımlayayım.. Hatta ben mazoşist birisiyim, private olan property’lerim bile saklansın abi! dediniz. Eee ne olacak şimdi ?

“O zaman kendin yazacaksın kardeşim!” diyor Delphi böyle sorulara cevap olarak. İyide onu nasıl yapacağız derseniz, eh onuda ben nacizane bilgilerime dayanarak sizlerle paylaşmaya çalışayım.

Öncelikle hiçbir iş yapmayan basit bir sınıf tasarlayalım sağına soluna bir kaç property serpiştirelim. Ama önce ne yapalım, Help’den DefineProperties’in tanımlandığı en üst sınıf hangisi onu bir kontrol edelim.Öyle ya bu metodu ezeceğiz.Gördük ki TPersistent’te tanımlanmış tam tahmin ettiğimiz gibi.. O halde biz de TComponent kullanabiliriz rahatlıkla demekki class’ımızı miras almak için.

TMyClass = class(TComponent)
private
  fAdi,
  fSoyadi : String;
  fYasi : Integer;

  property Adi 		: String read fAdi write fAdi;
  property Soyadi : String read fSoyadi write fSoyadi;
protected
  procedure OzellikOku(Reader : TReader);
  procedure OzellikYaz(Writer : TWriter);

  property Yasi : Integer read fYasi write fYasi;
public
  constructor Create(AOwner : TComponent); override;

  procedure DefineProperties(Filer : TFiler); override;
end;

Şimdi burada nasıl bir tanımlama olduğuna bakalım birlikte.İki adet private property, bir adet protected property var ve birde garip bir şey yani DefineProperties diye bir şey var.. Birde OzellikOku, OzellikYaz diye birşeyler var. Şimdi bu DefineProperties nasıl kullanılır ona bakalım.Kodlamaya devam..

constructor TMyClass.Create(AOwner : TComponent);
begin
  inherited Create(AOwner);
  fAdi := 'Adım';
  fSoyadi := 'Soyadım';
  fYasi := 333;
end;

procedure TMyClass.DefineProperties(Filer : TFiler);
begin
  inherited;
  Filer.DefineProperty('BenimNesneminTumOzellikleri', OzellikOku, OzellikYaz, true);
end;

Yukarıda gövdesi bulunan DefineProperties metodu ile biz Delphi’ye şöyle dedik: “Ey Delphi! sen bu nesnenin özelliklerini diske biryerlere yada memory’de biryerlere kaydederken bir zahmet OzellikYaz metodunu çalıştır, oralardan biryerlerden okurken de OzellikOku metodunu çalıştır.Anlaştık mı !” demiş oluyoruz.

Peki şimdi isterseniz OzellikOku ve OzellikYaz metodlarının gövdelerini yazalım.

procedure TMyClass.OzellikYaz(Writer : TWriter);
begin
  Writer.WriteListBegin;
    Writer.WriteString(Adi);
    Writer.WriteString(Soyadi);
    Writer.WriteInteger(Yasi);
  Writer.WriteListEnd;
end;

procedure TMyClass.OzellikOku(Reader : TReader);
begin
  Reader.ReadListBegin;
    Adi := Reader.ReadString;
    Soyadi := Reader.ReadString;
    Yasi := Reader.ReadInteger;
  Reader.ReadListEnd;
end;

Anlaşılır gibi görünüyor değil mi ? Yazarken ve okurken birden fazla property’nin içeriğini birden yazıp okuyacağım için liste kullandım.Eğer sadece bir tane property’nin içeriğini yazıp okumak isteseydik o zaman liste kullanmaya gerek kalmayacaktı.(WriteListBegin/ReadListBegin) Herneyse, şimdi sırada bu class’ımızdan oluşturulan nesneyi kaydetme işlemi var.Şimdi ne yapıyoruz, hemen Delphi Help’i açıyoruz ve ObjectBinaryToText yazıyoruz. Orada Delphi Example kısmına girdiğimizde birde ne görelim, iki adet function bizim için tanımlanmış, ee o zaman onları kullanalım. ;)

function ComponentToString(Component: TComponent): string;
var
  BinStream:TMemoryStream;
  StrStream: TStringStream;
  s: string;
begin
  BinStream := TMemoryStream.Create;
  try
    StrStream := TStringStream.Create(s);
    try
      BinStream.WriteComponent(Component);
      BinStream.Seek(0, soFromBeginning);
      ObjectBinaryToText(BinStream, StrStream);
      StrStream.Seek(0, soFromBeginning);
      Result:= StrStream.DataString;
    finally
      StrStream.Free;

    end;
  finally
    BinStream.Free
  end;
end;

function StringToComponent(Value: string): TComponent;
var
  StrStream:TStringStream;
  BinStream: TMemoryStream;
begin
  StrStream := TStringStream.Create(Value);
  try
    BinStream := TMemoryStream.Create;
    try
      ObjectTextToBinary(StrStream, BinStream);
      BinStream.Seek(0, soFromBeginning);
      Result := BinStream.ReadComponent(nil);

    finally
      BinStream.Free;
    end;
  finally
    StrStream.Free;
  end;
end;

Başlayalım kullanmaya…

var
  mClass : TMyClass;
  sComp : String;
begin
  mClass := TMyClass.Create(Self);
  {
    …  Artık ne işlemler yapacaksanız..
    …
    …
  }
  sComp := ComponentToString(mClass);
  ShowMessage(sComp);
  // Artık bu noktadan sonra ister bir text dosyaya yazın bu string’i ister veritabanına yazın isterseniz bir socket bağlantısı üzerinden
  // uzak bir sisteme gönderin orada create edin ne isterseniz...
end;

// Şimdide kaydettiğimiz yerden okuyalım..

var
 mClass : TMyClass;
 sComp : String;
begin
  // sComp := VeriyiBiryerlerdenOku; DB, text dosya vs.
  mClass := TMyClass.Create(Self);
  mClass := TMyClass(StringToComponent(sComp));
end;

İşte bu kadar sevgili arkadaşlar.Ben bu metodolojiyi geliştirdiğim componentlerde kullanıyorum.Umarım sizin için de faydalı olmuştur.

Saygılar, sevgiler..

“DefineProperties nedir, nasıl kullanılır..?” için 3 Yorum

  1. Seçgin ŞANLI diyor ki:

    Merhaba Tuğrul Bey.

    Öncelikle paylaşımınız için teşekkür ederim. Benim aşağıda belirttiğim bir sorunum var yardımcı olursanız sevirim. İyi çalışmalar.

    ComponentToString fonsiyonunu form tasarımını kaydetmek için kullandım. Bazı formlar başka bir formdan türetildiğinde bu fonksiyon “inherited” ifadelerini “object” ifadesine çeviriyor yani miras alınan formun özelliklerinide alıyor. Bunun engellemek için ne yapabilirim.

    • Tuğrul HELVACI diyor ki:

      Merhaba Seçgin bey, bu doğal olan davranış şekli. Bunu engellemek istiyorsanız, form’unuzda kaydetmek istediğiniz verilerinizi özelleştirmelisiniz. TReader, TWriter sınıflarına bakabilirsiniz.

      • Seçgin ŞANLI diyor ki:

        Türettiğim formun tasarım kodlarını aldıktan sonra base form ile karşılaştırıp base formda olanları silerek ve “inherited” olması gereken ama “object” ile başlayan nesneleri “name” özelliğinden bulup değiştirerek yapmayı düşünüyorum sonra çare olarak. Galiba bundan başka bir çıkar yolda yok. Belki özel bir kodu vardır delphinin benim gözden kaçırdığım diye düşünmüşdüm ama bize bırakmış bu işlemi :) teşekkür ederim ilginiz için iyi çalışmalar.

Tuğrul HELVACI için yorum yazın