Aynı formu ortak kullanan birden çok form ile ilgili..

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Glen
Üye
Mesajlar: 277
Kayıt: 12 Eki 2005 11:58

Aynı formu ortak kullanan birden çok form ile ilgili..

Mesaj gönderen Glen »

Merhaba..

Başlık bulamadım sanırım saatten ve uykusuzlugumdan kaynaklaniyor :)

"Aynı formu ortak kullanan birden çok formda, ortak kullanan formlardan çağıranı bulmak" yazacaktım da konunun uzunluğu yetmedi :) Herneyse sorunuma geçiyim daha doğru öğrenmek istediğim şeye..

Mesela, 4 tane form düşünün

A,B,C VE X
X Formu Ortak kullanılan form olsun.. yani A, B,C den X formu create edilerek bir işlem yaptırılıp sonucu hangi formdan açıldıysa ona döndürmek istiyorum..

Bu A, B, C formlarında 30 tane edit olsun, bunlarin 20 tanesi aynı, geri kalan 10 tanesi birbirinden farklı bir bilgiyi simgelesin...

Ben bu tip çağırmaları, X formuna global bir "gonderenform" değeri atıyorum ve formu create ederken diyorum ki,

A -> gonderenform = 0
B -> gonderenform = 1
C -> gonderenform = 2

Ve X ile ilgili işlemleri yansıtmak istediğimde,

if gonderenform = 0 then
.
.
else
if gonderenform = 1 then
.
.
else
if gonderenform = 2 then
.
.
end;

seklinde bir yapim olusuyor.. Ama ben istiyorum ki bu olayi global bir değişken ile degil, daha profesyonel bir cozumle cozeyim.. Ve mesela bu A,B,C formlarinda ortak Editleri su sekilde halledebileyim..

Sender.Adi.text := 'Ahmet';
Sender.DogumYeri.text := 'Tekirdağ';

gibi.. Yardımlarınızı bekliyorum.. Herkese kolay gelsin..
Kullanıcı avatarı
rsimsek
Admin
Mesajlar: 4482
Kayıt: 10 Haz 2003 01:48
Konum: İstanbul

Mesaj gönderen rsimsek »

Formu oluşturduktan sonra A formundan çağıracaksan frm_X.Tag := 0, B formundan çağıracaksan frm_X.Tag := 1, C formundan çağıracaksan frm_X.Tag := 2 gibi frm_X.Tag ı kullanarak yapabilirsin. frm_X formu içinde de

Kod: Tümünü seç

if frm_X.Tag = 0 then
.
.
else
if frm_X.Tag = 1 then
.
.
else
if frm_X.Tag = 2 then
.
.
end; 
şeklinde yapabilirsin.

Ortak Edit lerin kullanımını da;

Kod: Tümünü seç

(Sender as TEdit).Text := 'abc...';
şeklinde yapabilirsin. Fakat buradaki Sender frm_X in kendisi veya içindeki herhangi bir bileşendir :idea: A, B ve C formlarını kullanmak istiyorsan PUBLIC/genel altında frm_Gonderen: TForm; adında oluşturacağın bir değişkene frm_X i oluşturma/create dan sonra frm_X.frm_Gonderen := Self; deyip gönderen formu atayabilirsin. Ortak Edit lerin kontrolu de şu şekle gelir;

Kod: Tümünü seç

(frm_Gonderen.Edit1.Text := 'abc...'; // vs.
Bilgiyi paylaşarak artıralım! Hayatı kolaylaştıralım!!
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3071
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Hile yapalım

Mesaj gönderen sabanakman »

Hileli kodlar :)

Kod: Tümünü seç

OrtakForm.Tag:=Integer(CagiranForm);
OrtakForm.Show;
şimdi tag değeri çağıran formu tutuyor. Bunu elde etmek için ise

Kod: Tümünü seç

ShowMessage(TForm(OrtakForm.Tag).Name);
kodu kullanılabilir. Başka bir yöntem de var. Bunun için delphi versiyonu en az 2005 olmalı.

Kod: Tümünü seç

OrtakForm.PopupParent:=CagiranForm;
OrtakForm.Show;
kullanmak için de

Kod: Tümünü seç

ShowMessage(OrtakForm.PopupParent.Name);
şeklinde kullanılabilir. Formun PopupParent özelliği delphi 2005 ve sonraki versiyonlarda bulunuyor. Ayrıca ekranda gösterilen form, çağrılan formun üzerinde kaldığı için daha sağlıklı görüntüler elde ediliyor.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Glen
Üye
Mesajlar: 277
Kayıt: 12 Eki 2005 11:58

Mesaj gönderen Glen »

İlk oncelikle tesekkür ederim cevapladiginiz icin...

Şaban bey sizin verdiginiz kodu deneme imkanim olmadi cünkü delphi versionum maalesef 7 .. (maalesef mi yoksa ne mutlu mu gerci orasi da mechul :))
Recep bey sizin verdiginiz kodu calistiramadim

Kod: Tümünü seç

(frm_Gonderen.Edit1.Text := 'abc...'; // vs.
Yalniz bu bana bir ilham verdi, ne diyecek olursaniz..

Kod: Tümünü seç

TCxButtonEdit(frm_GonderenFORM.FindComponent('ok'+gonderenEdit+'kodu')).Text := ListeQueryKODU.Text;
İşimi görüyor... Ancak tek bir sorunum kaldi, componentlere bu sekilde ulasabiliyoruz peki.... GonderenFormlarin hepsinde ortak olarak

ok1refno, ok2refno, ok3refno, ok4refno diye 4 tane integer alan (global degisken olarak tanimlanmis) var..
Peki bu integer alanlara nasil ulasabilirim? yani

Integer(frm_GonderenForm.FindComponent('ok'+gonderenEdit+'refno')) := 15;

gibi bir kod lazim.. Bir yolu var mi acaba?
Kullanıcı avatarı
rsimsek
Admin
Mesajlar: 4482
Kayıt: 10 Haz 2003 01:48
Konum: İstanbul

Mesaj gönderen rsimsek »

Çalışmayan yerde bir parantez kalmış. Diğer sorduğunuz kısım hakkında bir fikrim yok :?
Bilgiyi paylaşarak artıralım! Hayatı kolaylaştıralım!!
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3071
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Tag

Mesaj gönderen sabanakman »

Yukarıda 2 teknik anlattım, 1.si (Tag yöntemli olan) delphinin tüm versiyonlarında çalışır.

Senin anlattığından:

Kod: Tümünü seç

type
  TForm1 = class(TForm)
    .
    .
    .
  private
    { Private declarations }
  public
    { Public declarations }
    ok1refno, ok2refno, ok3refno, ok4refno:Integer;
  end;
gibi bir tanımın çağıran tüm formlarda olduğunu anladım ve bu değişkenlere çağırdığın ortak formdan, hangi formdan çağrılmışsa o forma değerleri yazmak istiyorsun. Soru buysa ortak formu çağıran formları şu şekilde yazman gerekecek:

Kod: Tümünü seç

type
  TForm1 = class(TForm)
    .
    .
    .
  private
    { Private declarations }
    Fok1refno, Fok2refno, Fok3refno, Fok4refno:Integer;
  public
    { Public declarations }
  published
    property ok1refno:Integer read Fok1refno write Fok1refno;
    property ok2refno:Integer read Fok2refno write Fok2refno;
    property ok3refno:Integer read Fok3refno write Fok3refno;
    property ok4refno:Integer read Fok4refno write Fok4refno;
  end;
buradan ortak formu çağırırken de yazman gereken kod:

Kod: Tümünü seç

OrtakForm.Tag:=Integer(CagiranForm); {OrtakForm.Tag:=Integer(Self);'te olur}
OrtakForm.Show;
Artık ortak çağırdığın formdan nereden çağrılmışsa oraya 4 değeri yazmak içinde şu kodları yazarsan çözüme ulaşılacaktır (soruyu doğru anlamışsam). SetPropValue prosedürünün çalışması için uses kısmına TypInfo ünitesi eklenmeli. [->uses TypInfo;<-]

Kod: Tümünü seç

SetPropValue(TForm(Tag),'ok1refno',15);
SetPropValue(TForm(Tag),'ok2refno',2);
SetPropValue(TForm(Tag),'ok3refno',3);
SetPropValue(TForm(Tag),'ok4refno',4);
artık bu form nereden çağrılmışsa orada bulunan ok1refno özelliğinin değeri 15, ok2refno 2, ok3refno 3 ve ok4refno özelliğinin değeri de 4 olacaktır fakat çağıdığın formda eğer bu isimde (ok?refno) özellikler (Property) yoksa programda hata çıkacaktır. Bunu engellemek için "SetPropValue(TForm(Tag),'ok1refno',15);" satırları yerine "if IsStoredProp(TForm(Tag),'ok1refno') then SetPropValue(TForm(Tag),'ok1refno',15);" satırlarını yazarsanız kontrol ederek yazmış olacağınız için bir sorun çıkmayacaktır.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Glen
Üye
Mesajlar: 277
Kayıt: 12 Eki 2005 11:58

Mesaj gönderen Glen »

İlk oncelikle bu kadar zahmet edip bu kadar uzun ve detaylı yazıp uğraştığınız için çok teşekkür ederim..

Aynen yaptım dediklerinizi hatta tekrar gözden geçiriyorum bir hata mı yaptım diye ama Access Violation hatası veriyor :(

Tüm formlara propertyleri ekledim vs. ancak bir sorun oluştu..

Bu arada ben public kısmına değil

Var kısmına yazmıştım,

Kod: Tümünü seç

[b]var[/b]
XForm : TXform;
ok1refno, ok2refno, ok3refno, ok4refno : integer;
Şeklinde yani
normalde bu sağlıksız mı olur? çünkü hep böyle kullanıyorum yani genel degisken olarak atıyorum.
Bunun disinda tag kullanmadan bu,

frm_GonderenForm mantigi ile bu isin icinden siyrilmanin bir yolu var mi cünkü tag kullanmayi pek sevmiyorum da..[/b]
Glen
Üye
Mesajlar: 277
Kayıt: 12 Eki 2005 11:58

Mesaj gönderen Glen »

Tamamdir calisti kod,

SetPropValue(TForm(ortak.tag),'ok'+n+'refno',5);

seklinde yaptim calisti... ;)

Bu arada tag kısmından kastım şuydu, yani ana form ve bütün formlarin default tag'ı 0
yani hepsine ayrı ayrı numara vermek zorundamıyım?

1) Çünkü hepsini 0 yaptım yine bu kod çalıştı.. yarın öbür gün bana bir sorun çıkarır mı acaba???

2) Bunu property dışında VAR kısmı altına atanmış genel bir değişkenle yapmak mümkün mü? Çünkü eğer propery şeklinde yaparsam bir çok değişiklik yapmak zorunda kalıcam :(
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3071
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Tag Değeri

Mesaj gönderen sabanakman »

1. Burada işin sırrı formların tag değerinin ne olduğu değil, ortak çağrılan formun tagına çağıran formun gösterilmeden atanması.

Kod: Tümünü seç

ortak.tag:=Integer(Self);//<-göstermeden önce çağıran forma ayarla.
ortak.show;//<-göster
bu ayardan başka suya sabuna dokunmana gerek yok.
2.SetPropValue ancak published bloğunda bulunan Property'lere değer yazar. Bu işlem başka yoldan sadece bildiğiniz klasik yöntemlerle yapılabilir.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Glen
Üye
Mesajlar: 277
Kayıt: 12 Eki 2005 11:58

Mesaj gönderen Glen »

Anladim... ve ok1refno yu değerini de okumak için Fok1refno yu kullaniyoruz çağıran formdan sanırım..

Çok teşekkür ediyorum, şimdilik herşey istedigim gibi çalışıyor.. Tekrar tekrar yardım eden herkese teşekkürler..

Kolay gelsin
Glen
Üye
Mesajlar: 277
Kayıt: 12 Eki 2005 11:58

Mesaj gönderen Glen »

arkadaşlar ek bir soru daha sormak istiyorum başka konu açmıyım dedim çünkü aynı konuyla alakalı
peki çağıran formdaki ortak procedure ve functionlari kullanmak gibi bir şansımız var mı?
Kullanıcı avatarı
rsimsek
Admin
Mesajlar: 4482
Kayıt: 10 Haz 2003 01:48
Konum: İstanbul

Mesaj gönderen rsimsek »

PUBLIC altında tanımlanmışsa neden olmasın :wink:
Bilgiyi paylaşarak artıralım! Hayatı kolaylaştıralım!!
Glen
Üye
Mesajlar: 277
Kayıt: 12 Eki 2005 11:58

Mesaj gönderen Glen »

Recep abi normalde ismini bildigim formdaki bir function'i ve procedure'ü kullanabiliyorum ancak bu durumda ismini bilmedigim bir formdaki ismini bildigim bir procedure'ü nasil kullanacagim? :)
Kullanıcı avatarı
rsimsek
Admin
Mesajlar: 4482
Kayıt: 10 Haz 2003 01:48
Konum: İstanbul

Mesaj gönderen rsimsek »

Doğrusu şu an hiç bir fikrim yok :? Biraz kafa yormak gerekebilir. Daha önce böyle bir şey yapmadım. Bu soruya yukarıda detaylı açıklayan @sabanakman bir cevap verir sanırım :wink:
Bilgiyi paylaşarak artıralım! Hayatı kolaylaştıralım!!
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3071
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Zorlamaya Devam

Mesaj gönderen sabanakman »

Bu çok teknik bir konu aslında. Bu iki şekilde olabilir. 1. si nesneye yönelik programlama tekniği kullanarak 2. si ise Arabirimleri (Interface) kullanarak. 2. teknik Delphi 7 ve sonrasında desteklenen bir teknik olduğu için daha önceki delphi versiyonlarında çalışmaz.
----------------
1. Nesne Programlama Kullanarak:
Önce basit temel bir nesne hazırlayalım:

Kod: Tümünü seç

type

THesapla=class;
public
  function Hesapla:Real;virtual;abstract;
end;
bu nesne için function THesapla.Hesapla:Real; fonksiyonu tanımlanmaz "abstract" anahtar sözcüğü bunun bu nesnede değil de bundan türeyen nesnelerde tanımlanacağını belirtir. "virtual" anahtar sözcüğü ise "Hesapla" metodunun bundan türeyen nesnelerde değiştirilebileceğini belirtir. Şimdi FIFO, LIFO ve ORTALAMA ya göre hesaplama yapan 3 nesne türetelim.

Kod: Tümünü seç

TFIFO=class(THesapla);
public
  function Hesapla:Real;override;
end;

TLIFO=class(THesapla);
public
  function Hesapla:Real;override;
end;

TORT=class(THesapla);
public
  function Hesapla:Real;override;
end;
.
.
function TFIFO.Hesapla:Real;
begin
.
.
  Result:=??;
end;

function TLIFO.Hesapla:Real;
begin
.
.
  Result:=??;
end;

function TORT.Hesapla:Real;
begin
.
.
  Result:=??;
end;
artık elimizde değişik yöntemlere göre hesap yapabilen 3 tane nesne bulunuyor. Burada "override" anahtar sözcüğü ise önceden "virtual" ya da "dynamic" olarak tanımlanan fonksiyon yada prosedürleri veya "constructor" metotları çocuk nesne de daha değişik şekilde çalışmasını sağlamaya yarar. Eğer ata nesne içinde bulunan kodlarıda kullanmak istersek (mesela TComponent'ten türemeler de Create kodlarının çalışması gerekir) "inherited Hesapla;" dememiz gerecekti ama ben "abstract" olarak tanımladığım için bu satır çalışma anında hata çıkarır. Çünkü THesapla nesnesinde Hesapla isimli fonksiyonun kodu bulunmamaktadır. Basit bir örnek yazarsak:

Kod: Tümünü seç

var Hesap:THesapla;
begin
  try
    if FIFO.Checked then Hesap:=TFIFO.Create
    else if LIFO.Checked then Hesap:=TLIFO.Create
    else Hesap:=TORT.Create;
    ShowMessage(FloatToStr(Hesap.Hesapla));{burada yapılan seçim neyse ona göre hesaplama yapacaktır.}
  finally
    Hesap.Free;
  end;
end;
görüldüğü küçük nesneler yazarak ve hesaplamaları bunlara dağıtarak bir yığın koddan kurtulduk. Bunu basit bir örnek olsun diye yazdım. Senin form üzerinde uygulayacağın teknik olarak çözüm üretirsek aşağıda ki gibi bir kod yaz ve myForm.pas olarak kaydet.

Kod: Tümünü seç

unit myForm;

interface

uses Forms;

type
  TForm=class(Forms.TForm)
  public
    procedure OrtakMetot1;virtual;abstract;
    function OrtakMetot2:Boolean;virtual;
    function OrtakMetot3:Boolean;virtual;abstract;
  end;

implementation

function TForm.OrtakMetot2: Boolean;{abstract; kullanılmadığı zaman kodu yazılarak tanımlanır}
begin
end;
  Caption:='Çalıştırıldım';
  //Result:=True;
end.
projendeki tüm paslarda üstte uses satırında en sona (Forms'tan sonraki bir yere) myForm ünitesini ekle. Artık tüm formlarında OrtakMetot1 prosedürü ve OrtakMetot2 fonksiyonu olacaktır (Form1.OrtakMetot2 vs.). Şimdi bir formda bunun çalışmasını yazmak veya değiştirmek istersen şu şekilde o forma yazmalısın.

Kod: Tümünü seç

type
  TForm1=class(TForm)
  .
  .
  public
    procedure OrtakMetot1;override;
    function OrtakMetot2:Boolean;override;
    function OrtakMetot3:Boolean;override;
  end;

implementation

procedure TForm1.OrtakMetot1;
begin
....
end;

function TForm1.OrtakMetot2: Boolean;
begin
...
{"inherited;" veya "inherited OrtakMetot2;" yazılırsa TForm nesnesinde yazılan OrtakMetot2 fonksiyonu da çalışacaktır.}
end;

function TForm1.OrtakMetot3: Boolean;
begin
...
end;

end.
bu tanımlamadan sonra, tanımlaması yapılan tüm formlarda OrtakMetot1,OrtakMetot2 ve OrtakMetot3 metotlarını THesapla örneğinde olduğu gibi çalıştırılabilir.
----------------
Bu çok karışık geldiyse o zaman 2. yönteme göz at. Bu yöntemi Delphi 7 ve sonrası desteklemektedir.
----------------
2.Arabirimleri (Interface) Kullanarak:
Burada nesnelerin yapısında hiç bir değişiklik yapmana gerek yoktur. Sadece yapısı class'tan biraz farklı olan interface tanımlaman gerekecek ve bu arayüzde ortak olması gereken prosedür ve fonksiyonların sadece tanımlamalarını yazman gerekecek. (begin-end; bloğu içinde kodlar gerekmez çünkü interface sadece özet bilgi amaçlıdır)

Kod: Tümünü seç

unit Genel;

interface

uses SysUtils, Forms;

type
  IFormGenel=interface(IUnknown)
    ['{24497238-ADE0-4381-953E-808699155BB3}']
    procedure OrtakMetot1;
    function OrtakMetot2:Boolean;
    function OrtakMetot3:Boolean;
  end;

implementation

end.
yukarıda farklı olarak ['{24497238-ADE0-4381-953E-808699155BB3}'] yazan satır bulunmaktadır. Bu değeri elde etmek için Ctrl+Shift+G tuşlarına basman gerekecek. Değerin işlevi bu arayüze dünyada bulunan diğer arayüzlerden farklı bir sayısal değer vermek ama bizim için bunun önemi yok. Yukarıda Genel.pas isimli dosya oluşturulduktan sonra bu ortak metotları tanımlayacak tüm formaları şu şekilde yapılandırmalısın. Uses satırında Genel'i eklememiz gerekecek.

Kod: Tümünü seç

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Genel;

type
  TForm1 = class(TForm, IFormGenel)
    .
    .
  private  
    { Private declarations }
  public
    { Public declarations }
    procedure OrtakMetot1;
    function OrtakMetot2:Boolean;
    function OrtakMetot3:Boolean;
{eğer IFormGenel arabirimi kullanılarak nesne türetilirse IFormGenel içinde bulunan tüm metotlar aynı IFormGenel'de tanımlı olduğu şekilde bu nesnede tanımlanmalıdır.(OrtakMetot1,OrtakMetot2,OrtakMetot3)}
  end;

implementation

procedure TForm1.OrtakMetot1;
begin
....
end;

function TForm1.OrtakMetot2: Boolean;
begin
...
end;

function TForm1.OrtakMetot3: Boolean;
begin
...
end;

end.
şimdi tanımlamalar yapıldıktan sonra ortak bir noktadan bu nesnedeki bu metotları kullanmak istediğimizde şu kodları yazmamız gerekecek.

Kod: Tümünü seç

//uses ta SysUtils kullanılıyor;

function MetotlariCalistir(const Form:TObject):Boolean;
var i:Integer; GenelForm:IFormGenel;
begin
  Result:=True;
  if Assigned(Form) then try    
    if Supports(Form,IFormGenel,GenelForm) then begin
      GenelForm.OrtakMetot1;
      GenelForm.OrtakMetot2;
      GenelForm.OrtakMetot3;
    end;
  except
    Result:=False;
  end;
end;
ben burada MetotlariCalistir(Form1) dediğim zaman TForm1 içindeki OrtakMetot1,OrtakMetot2 ve OrtakMetot3 çalışacaktır. Hatta:

Kod: Tümünü seç

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Genel;

type
  TDenemeNesnesi = class(TComponent, IFormGenel)
  private
    { Private declarations }
  public
    { Public declarations }
    procedure OrtakMetot1;
    function OrtakMetot2:Boolean;
    function OrtakMetot3:Boolean;
{eğer IFormGenel arabirimi kullanılarak nesne türetilirse IFormGenel içinde bulunan tüm metotlar aynı IFormGenel'de tanımlı olduğu şekilde bu nesnede tanımlanmalıdır.(OrtakMetot1,OrtakMetot2,OrtakMetot3)}
  end;

implementation

procedure TDenemeNesnesi.OrtakMetot1;
begin
....
end;

function TDenemeNesnesi.OrtakMetot2: Boolean;
begin
...
end;

function TDenemeNesnesi.OrtakMetot3: Boolean;
begin
...
end;

end.
şeklinde form olmayan bir nesneyi IFormGenel arabirimiyle tanımlarsak ve MetotlariCalistir(DenemeNesnesi1) yazarsak bu sefer TDenemeNesnesi'ne ait ortak metotlar çalışacaktır.
-----------------
Bu konular aslında derin ve zaman isteyen konulardır. Ben bunları Charlie Calvert (Delphi4) ve Marco Cantu(Delphi7) kitaplarından okudum. Aslında zamanını bu konuları öğrenmek için muhakkak ayır. Özellikle nesne programlama tekniğini. Eğer zamanını alacağını düşünüyorsan gelecekte yapacağın işlerde kaybettiğinden çok daha fazlasını kazanacağını garanti ederim. Ayrıca akla ilk gelen soru nesneleri nasıl tasarlamak gerektiğidir. Bu teknik bir bilgi değildir bu tamamen tecrübedir. Bu konularla ne kadar haşır neşir olur örnekler yaparsan o kadar sağlıklı nesneler üretmeyi başarabilirsin.
????????
Bir şeyi belirtmeyi unutmuşum. Senin bunu MetotlariCalistir(TForm(ortak.tag)) yazarak kullanman gerekecek
En son sabanakman tarafından 30 Haz 2007 04:59 tarihinde düzenlendi, toplamda 3 kere düzenlendi.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Cevapla