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..
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.
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.
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.