Mega Code Archive

 
Categories / Delphi / Strings
 

Delphide formlarla çalışmak

DELPHI’DE FORMLARLA ÇALIŞMAK Windows 98 tabanlı programlar genellikle pencere içinde çalışırlar. Delphi literatüründe bu çalışma pencereleri form olarak adlandırılırlar. Bir delphi programı genellikle bir veya birkaç formun birbirine bağlanması ile oluşur. Bu yazıda formların özellikleri, türleri ve kendileri hakkında bilinmesi gereken önemli bilgilerle birlikte, ilave olarak formlar arasında bilgi transferinin nasıl yapılacağı ve formların birbirine nasıl bağlanacağı konuları üzerinde duracağım. Başlamadan önce sizlere delphi ile çalışırken ihtiyacınız olabilecek ve işinizi daha kolaylaştıracak bazı ip uçları vermeye çalışayım. Ayrıca başlangıçta dikkat ettiğinizde projelerinizin ileriki dönemlerinde işinizi kolaylaştıracak bazı bilgileri de burada bulacaksınız. Öncelikle bir projeye başlamadan önce, bu projeyle ilgili bütün dosyaları içinde tutacağınız bir klasör açın. Ben genellikle belki gözümden bir şey kaçar diye bu klasörü kök dizinde açıyorum. Çünkü proje bittiğinde kullanıcılara dağıtılması gerekir. Kullanıcıları da sizin kullandığınız klasörü kullandırmaya yönelirseniz oluşabilecek bazı hataları daha ortaya çıkmadan önlemiş olursunuz. Bu sitede üzerinde çalışacağımız bütün örnekler için C: sürücüsünün kökünde oluşturduğum ve adı WORK olan bir dizin kullanacağım. Eğer projenizde veritabanı dosyaları kullanacaksanız bu dosyalarınızın program kaynak dosyaları ile karışmaması için çalışma dizininizin içinde ( benimki C:\WORK) DATA diye bir dizin oluşturmanız yararınıza olur. Ben genellikle 1024x768 çözünürlükte çalışıyorum. Eğer ekran kartınız müsaade ediyorsa sizde en az bu çözünürlükte çalışmaya özen gösterin. Aslında 1024x768 uygun bir çözünürlüktür, bu çözünürlükte çalışırken form için kullanabileceğiniz alan 800x600 ebadında bir form için yeterlidir. Ve genellikle kullandığınız formlar için en fazla 800x600 boyutlarını kullanın. Çünkü programınızı kullanan herkesin yüksek çözünürlükleri destekleyebilecek bir ekran kartı veya zevki olmayabilir. Kendiniz için bazı kurallar koyun. Mesela formlarınızın isimleri Delphi’nin standart isimlerinden Form1, Form2, ... gibi isimleri kullanmak yerine her zaman bu formlarınıza aklınıza kolay gelebilecek isimler koyun. Formlarınıza Frm ile başlayan isimler koymanız uygun olur. Bunu kendiniz için bir standart haline getirdiğinizde ilerleyen dönemlerde işlerinizin daha da kolaylaştığını göreceksiniz. Eğer mümkünse ana form üzerine açılan formlarınızın boyutu ana formunuzdan daha küçük olsun. Delphi’de Çok Formlu Uygulamalar Tek bir form ve birkaç bileşenle tamamen işlevsel uygulamalar geliştirilmesi mümkün olsa da, birden fazla forma sahip olan uygulamalara çok daha fazla rastlanır. Aslında pratik olarak delphi uygulamalarınızı geliştirebilmeniz için iki farklı form tekniği kullanır. Bunlardan birincisine örnek olarak Microsoft Word uygulamasında olduğu gibi ana bir pencere çerçevesi içinde bu pencere tarafından oluşturulmuş birden fazla pencerenin var olabileceği MDI olarak adlandırılan formlar vardır. İkinci form şekli ise Ana form tarafından oluşturulan ancak ana form içinde yer almayan birden fazla formların kullanıldığı uygulamalardır. Birkaç örnek olarak Paint, WordPad, Notepad gibi uygulamaları gösterebiliriz. Bu yazımızda ikinci tekniği kullanacağız . Bir programın içinde bir çok form vardır. Bu formlardan bir tanesini uygulama çalıştığında görüntüye gelen form oluşturur. Bu form ana form olarak nitelendirilirse diğer formlar bu ana formdan türerler. Şimdi yazacağımız uygulamada bir ana form ve bu ana form tarafından oluşturulacak 3 tane form olacak. Bunun için Delphi’yi çalıştırın ve karşınıza gelen Form1 formuna ilave olarak üç tane daha form ilave edin. Şimdi ilk olarak neye dikkat etmemiz gerektiğine bakalım. Project | Options menüsünü çalıştırdığınızda karşınıza Project Options penceresi gelir. Bu pencerenin bizim programımız için görünümü aşağıdaki gibiydi. Kaynak : Marco Cantû, Herkes İçin Delphi 3 Steve Teixeira & Xavier Pacheco, Borland Delphi 4 Developer’s Guide Yukarıdaki görüntüye dikkat ettiğinizde ilk göze çarpan Main form olarak Form1’in tanımlı olduğudur. Bunun anlamı programı çalıştırdığınızda sadece Form1 görüntüye gelecek. Auto-create forms başlığı altında ise program çalıştığında otomatik olarak yaratılacak formların listesini görüyoruz. Bizim tanımladığımız diğer formlar program çalıştığında görüntüye gelmediği halde otomatik olarak yaratılıyor. Bize düşen sadece gerektiğinde bu formları görüntüye getirecek komutu gerekli yere yazmaktır. Ancak otomatik olarak yaratılan formların sayısı arttığı müddetçe bu formların hafızada kapladıkları toplam alan oldukça yüksek bir değere ulaşır. Bu doğru bir mantık değildir. program Project1; uses Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}, Unit3 in 'Unit3.pas' {Form3}, Unit4 in 'Unit4.pas' {Form4}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.CreateForm(TForm2, Form2); Application.CreateForm(TForm3, Form3); Application.CreateForm(TForm4, Form4); Application.Run; end. Yukarıdaki kodlar projemizin formları oluştururken kullandığı kodlardır. Bu kodlara dikkat ederseniz bütün formlar yaratıldıktan sonra uygulama çalıştırılıyor. Dolayısı ile bütün formların oluşturulması programın ilk çalışma anını uzatıyor. Program çalışırken görünen formun dışındaki formlar hafızada yaratılmış şekilde durduğunda bu formların görüntüye getirilip kapatılması (gizlenmesi) son derece hızlı olur ancak bu aşırı hız hafıza problemini de beraberinde getirmektedir. Ana formumuz Form1 olduğuna göre diğer formları Available forms bölümüne aktarmamız daha mantıklıdır. Böylece programımız çalıştığında sadece Form1 yaratılacak ve görüntülenecek. Diğer formlar ise ihtiyaç duyulduklarında yaratılmak ve görüntülenmek için hazır durumda bekleyecekler. Bu şekilde kurulan bir yapıda hafıza tasarrufu daha rahat yapılabilir. Gerekli düzenlemeyi yaptıktan sonraki Project Options penceresinin görünümü ve projenin kaynak kodu aşağıdaki gibi olur. program Project1; uses Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}, Unit3 in 'Unit3.pas' {Form3}, Unit4 in 'Unit4.pas' {Form4}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. Proje kodunun son haline dikkat ettiğimizde program çalışmadan önce sadece Form1 oluşturulmuş. Form1 isimli forma diğer üç formla bağlantı kurabilmek için üç tane button yerleştirdim. Ana form olarak kullandığım formun görünümü aşağıdaki gibidir. Button2’ye basıldığında Form2, Button3’e basıldığında Form3, Button4’e basıldığında Form4 görüntülenecek. Button1’i programı kapatmak için kullanacağız. Bunun için Button1’in üzerine Kapat yazdım. İlk olarak Kapat buttonunun görevini hazırlayalım. Bir pencereyi kapatmanın birçok yolu vardır. Eğer kapatılan pencere ana form olarak tanımlıysa bu aynı zamanda programın çalışmasının sona ermesine sebep olur. Bunun için gerekli kodu Kapat button’unun onclick olayına yazdım. Kod aşağıdaki gibidir. procedure TForm1.Button1Click(Sender: TObject); begin Application.Terminate; end; Application.Terminate satırına sadece Close veya Form1.Close yazmak da aynı şeyi yapıyor. Bunun sebebi ana pencereyi kapatmakla uygulamayı sonlandırmanın aslında aynı şey olduğudur. Şimdi Button2 düğmesine Form2’yi görüntüye getirecek kodu yazalım. Ama daha önce Form2 formuna da bir kapat button’u yerleştirip bu button’un onClik olayına Form2.Close veya sadece Close yazalım ki uygulamayı çalıştırıp Form2’yi görüntülediğimizde tekrar kapatabilelim. Button2 düğmesinin onClick olayına aşağıdaki kodları sırayla yazalım ve her kodun ne anlama geldiğini görelim. procedure TForm1.Button2Click(Sender: TObject); begin Form2:=TForm2.Create(Form1); //1 Form1 ifadesi yerine Application yazabilirsiniz. Form2.Showmodal; //2 Form2.Free; //3 end; Öncelikle Form2’yi görüntüye getirmek için yaratılması lazım. (1) numaralı satır Form2’yi yaratıyor parantez içindeki (Form1) ifadesi ise Form2’nin kim tarafından yaratıldığını gösteriyor. Bizim örneğimizde Form2’yi Form1 yarattığı için buraya Form1 yazdım. Bu parametreye genelde fazla dikkat edilmez ancak çok önemlidir. Mesela yaratılan ikinci formun kendisini oluşturan formun ekrandaki pozisyonu ne olursa olsun tam ortasına gelmesini istiyorsak Form2’nin Position özelliğini poDesigned değil de poOwner FormCenter yaparsak istediğimiz olur. Form1’i çalışma modunda iken istediğiniz yere taşıyın Button2’ye basmanız Form2’yi tam Form1’in ortasında gösterir. İkinci numaralı satırda Form2’yi modal olarak görüntüledik. Bunun anlamı Form2 kapatılmadan önce, Form2’yi oluşturan formun disable durumda olacağıdır. Yani daha başka bir ifade ile Form2 kapatılmadan Form1’deki hiçbir görsel bileşen kullanılamaz. Üçüncü satırda ise Form2 modal olarak gösterildikten sonra Form2’nin kapatılmasını takiben onu hemen hafızadan silmemizi sağlayan Free komutu kullandık. Bu komutu kullanmadığımızda program gene çalışır ama her seferinde oluşturulan form hafızadan atılmadığı için hafıza sürekli şişer. Button2’nin onClick olayına yukarıdaki komutları yazdıktan sonra programı çalıştırmak istediğinizde aşağıdaki gibi bir mesaj görüntüye gelir. Bu mesajın tam karşılığı sudur. “ Form1 formu Unit2 içinde tanımlanmış olan Form2’ye gönderme yapıyor fakat bu sizin USES listenizde yok. Eklemek ister misiniz ? ” bu soruya Yes cevabını verdiğinizde Unit1’in uses listesine Unit2 eklenir. Tekrar çalıştırdığınızda ise program çalışır. Şimdi Form3’ü görüntüleyelim. Ancak bu formu görüntülerken formu tıpkı bir diyalog kutusuymuş gibi kullanalım. Bunun için Form3’e bir Label bileşeni ekleyelim ve üç tane de düğme koyalım. Bu düğmelerin Kind özelliğini sırasıyla bkYes, bkNo ve bkCancel yapalım. Formun boyutunu uygun bir düzeye getirdiğimizde aşağıdaki görüntü oluşur. İsterseniz her düğme için Caption ifadesine Evet, Hayır ve Vazgeç yazabilirsiniz. Asıl dikkat etmemiz gereken düğmelerin Kind ve ModalResult özellikleridir. Kind özelliğine daha önceden tanımlı değerleri yerleştirdiğinizde ilgili düğme bir bitbtn bileşeni ise düğmeye bir resim de ilave edilir. Ayrıca ModalResult değeri de düğmenin kind’iyle (kind=tür) aynı değeri gösterecek şekilde değişir. Bu üç düğme için kod yazmadığımız halde üç düğme de Form3 formunu kapatır. Çünkü Form3’ü modal olarak göstereceğiz ve modal olarak gösterilen bir formda ModalResult değeri mrNone’den farklı bir değer aldığında form kapatılır ve değer geri gönderilir. Şimdi Form1 üzerindeki button3 için kodları yazalım. procedure TForm1.Button3Click(Sender: TObject); Var Sonuc : Integer; begin {1} Form3:=TForm3.Create(Form1); {2} Form3.Label1.Caption:='Bu bilgi Form1den geldi'; {3} Sonuc:=Form3.ShowModal; {4} Case Sonuc of {5} mrYes : ShowMEssage('Pencere Yes düğmesi ile kapandı'); {6} mrNo : ShowMEssage('Pencere No düğmesi ile kapandı'); {7} mrCancel : ShowMEssage('Pencere Cancel düğmesi ile kapandı'); {8} End; {9} Form3.Free; end; Birinci satırda form3 form1 tarafından yaratılıyor. ( gösterime hazır hale geliyor). İkinci satırda Form3’te yar alan Label1’e bir bilgi atanıyor. Üçüncü satırda form3 modal olarak görüntüleniyor ve formun kapandığında gönderdiği ModalResult değeri sonuc degişkenine aktarılıyor. 4,5,6,7 ve 8 numaralı satırlarda Sonuc içine gelen değer kontrol edilip pencerenin kapanış şekli görüntüleniyor ve dokuzuncu satırda form3 hafızadan atılıyor. Not : Form3’ün borderstyle özelliğini bsDialog yaparsanız maksimize ve minimize düğmeleri de ortadan kalkacaktır. Son olarak Form4’ü görüntüleyeceğiz. Ancak Form4 içine bazı bileşenler ekledim. Form4’ün görünümü aşağıdadır. Düğmelerin birinin Kind’ini bkOk diğerininkini de bkCancel yaptım. Bu formu görüntüye getireceğiz ve bu formu hafızadan silmeden önce Edit1 bileşeni içerisindeki ifadeyi Form1’e geçireceğiz. Bu işlemi yapmak için gerekli kodu Button4’ün onClick olayına aşağıdaki gibi yazdım. Yazılan kodu biraz incelerseniz Form4 içindeki Edit1 bileşeninin değerini Form4’ü Free ile hafızadan atmadan hemen önce aldım. procedure TForm1.Button4Click(Sender: TObject); begin Form4:=TForm4.Create(Form1); If Form4.ShowModal = mrOk Then ShowMessage('Form4.Edit1 içeriği:'+Form4.Edit1.Text); Form4.Free; end; Bu örnekte formları birbirine nasıl bağladığımızı ve değer geçişlerini nasıl yaptığımızı öğrendik. Programın bitmiş şeklini buraya tıklayarak alabilirsiniz. Formlarla İlgili Birkaç İpucu ve Not ActiveControl Bileşeni Bir formun ActiveControl bileşeni, ilgili form aktif durumda olduğunda; form üzerinde yer alan bileşenlerden hangisinin seçili durumda olacağını gösterir. Eğer ActiveControl’de gösterilen bileşen bir düğme ise form üzerinde herhangi bir yerde Enter tuşuna basmakla ActiveControl olarak belirlenmiş düğmeye basmak aynı anlama gelir. Kod Yazarak Bir Bileşeni Aktif Hale Getirmek Kod yazarak form üzerindeki bir bileşeni seçili duruma getirebilirsiniz. Bunun için Tform nesnesinin SetFocus nesnesini kullanabilirsiniz. Bu komutu kayıt ekleme düğmesine bastığınızda klavye imlecinin ilk giriş alanına konumlanmasını sağlayabilirsiniz. Bunun için yazmanız gereken kodun bir örneği şu şekildedir. SetFocus:=DBEdit1; Başlık Çubuğunda Sistem Saatinin Gösterilmesi Formunuza ait başlık çubuğunda sistem saatini görüntüye getirebilirsiniz. Bunun için Formunuza bir Timer bileşeni ekleyin. Bu bileşenin Interval özelliği görüntüdeki saatin yenilenme aralığını belirler ve 1000 değeri yaklaşık olarak 1 saniyeye karşılık gelir. Formunuzun ana Var bölümünde hdc tipinde ve dc isminde bir değişken tanımlanmalı. Bunu unutmayın. Timer bileşeninin onTimer olayına, formunuzun ise onCreate ve onClose olayına gerekli kodları yazıp programı çalıştırdığınızda başlık çubuğunuzun tam ortasında saniyesi olan bir saat göreceksiniz. Unit’in komple kodu aşağıdadır. ( Kaynak : Melsoft Pufler.Doc) unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Mask, Buttons; type TForm1 = class(TForm) BitBtn1: TBitBtn; MaskEdit1: TMaskEdit; Timer1: TTimer; procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private public end; var Form1: TForm1; dc:hdc; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin dc:=getwindowdc(handle); end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin releasedc(handle,dc); end; procedure TForm1.Timer1Timer(Sender: TObject); var thetime: array[0..80] of char; begin strpcopy(Thetime,timetostr(time)); canvas.font.color:=clred; textout(dc,width div 2,5,thetime,strlen(thetime)); end; end. //Başlık Çubuğuna Bir Button Eklenmesi Formunuzun başlık çubuğunda genelde üç tane düğme vardır. Bunlar kapat, Tamekran ve önceki boyut düğmesi bulunur. Bunların hemen sol tarafına bu düğmeler gibi yeni bir düğme eklemek için gerekli kodlar aşağıda verilmiştir. ( Kaynak : Melsoft Pufler.Doc) unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Mask, Buttons; type TForm1 = class(TForm) BitBtn1: TBitBtn; MaskEdit1: TMaskEdit; procedure FormResize(Sender: TObject); private CaptionBtn : TRect; procedure DrawCaptButton; procedure WMNCPaint(var Msg : TWMNCPaint); message WM_NCPaint; procedure WMNCActivate(var Msg : TWMNCActivate); message WM_NCACTIVATE; procedure WMSetText(var Msg : TWMSetText); message WM_SETTEXT; procedure WMNCHitTest(var Msg : TWMNCHitTest); message WM_NCHITTEST; procedure WMNCLButtonDown(var Msg : TWMNCLButtonDown); message WM_NCLBUTTONDOWN; public { Public declarations } end; var Form1: TForm1; dc:hdc; implementation const htCaptionBtn = htSizeLast + 1; {$R *.DFM} procedure TForm1.DrawCaptButton; var xFrame,yFrame,xSize,ySize : Integer; R : TRect; begin //Form eni ve boyu xFrame := GetSystemMetrics(SM_CXFRAME); yFrame := GetSystemMetrics(SM_CYFRAME); //Başlık butonlarının eni ve boyu xSize := GetSystemMetrics(SM_CXSIZE); ySize := GetSystemMetrics(SM_CYSIZE); //Yeni butonun yeri CaptionBtn := Bounds(Width - xFrame - 4*xSize + 2,yFrame + 2, xSize - 2, ySize - 4); //Forma ait DC 'yi kullanarak, //üzerine çizim yapılacak tuvali bul Canvas.Handle := GetWindowDC(Self.Handle); Canvas.Font.Name := 'Symbol'; Canvas.Font.Color := clBlue; Canvas.Font.Style := [fsBold]; Canvas.Pen.Color := clYellow; Canvas.Brush.Color := clBtnFace; try DrawButtonFace(Canvas, CaptionBtn, 1, bsAutoDetect, False, False, False); R := Bounds(Width - xFrame - 4 * xSize + 2, yFrame + 3, xSize - 6, ySize - 7); with CaptionBtn do Canvas.TextRect(R, R.Left + 2, R.Top - 1, 'W'); finally ReleaseDC(Self.Handle, Canvas.Handle); Canvas.Handle := 0; end; end; procedure TForm1.WMNCPaint(var Msg : TWMNCPaint); begin inherited; DrawCaptButton; end; procedure TForm1.WMNCActivate(var Msg : TWMNCActivate); begin inherited; DrawCaptButton; end; procedure TForm1.WMSetText(var Msg : TWMSetText); begin inherited; DrawCaptButton; end; procedure TForm1.WMNCHitTest(var Msg : TWMNCHitTest); begin inherited; with Msg do if PtInRect(CaptionBtn, Point(XPos - Left, YPos - Top)) then Result := htCaptionBtn; end; procedure TForm1.WMNCLButtonDown(var Msg : TWMNCLButtonDown); begin inherited; if (Msg.HitTest = htCaptionBtn) then ShowMessage('Hoops... yeni butona bastın'); end; procedure TForm1.FormResize(Sender: TObject); begin //Başlık çubuğunun yeniden çizilmesini sağla Perform(WM_NCACTIVATE, Word(Active), 0); end; end. Pencerenin Taşınması Windows pencereleri, ekran üzerinde başlıklarından tutularak taşınırlar. Pencere alanından tutularak da taşınabilmeleri için, WM_NCHITTEST mesajının yakalanıp, yordamının değiştirilmesi gerekir. Gerekli kod aşağıda gösterilmiştir. type TForm1 = class(TForm) public procedure WMNCHitTest(var M: TWMNCHitTest); message WM_NCHitTest; end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.WMNCHitTest(var M: TWMNCHitTest); begin inherited; if M.Result = htClient then M.Result := htCaption; end;