|
Bir kaç haftadır Java dilini popüler yapan Applet’ ler ile uğraşıyorum. Buna karşın günümüz dünyasının bir programlama dilinden bekledikleri arasında mutlaka windows uygulamalarının var olması gerektiğini düşünüyorum. Sonuç olarak Applet’ ler her ne kadar çok başarılı olsalarda, zaman zaman windows uygulamaları geliştirmemizde gerekiyor. Bir windows uygulamasının belkide en temel özelliği mutlaka bir Form (Nam-ı diğer pencere diyebiliriz) ekranına sahip olması. Peki java dilinde, windows uygulamları oluşturmak için nasıl bir yol izlemem gerekir. İşte bu hafta boyunca, java dili ile bağımsız olarak çalışabilen pencereleri incelemeye çalıştım.
Sun’ ın Java paltformu, Microsoft’ un ciddi rakiplerinden birisi. Belkide tek ciddi rakibi. Ancak bu rekabet zaman zaman biraz komik olaylarada neden olmuyor değil. örneğin, yaptığım araştırmalarda gördüm ki, Windows uygulamarında Form kavramı, java dilinde Frame olarak adlandırılıyor. Bu kısa politik düşüncelerden sonra, artık ilk form ekranımı, pardon düzeltiyorum; ilk frame ekranımı tasarlamam gerektiğine karar verdim. Bu amacımı gerçekleştirebilmek amacıyla aşağıdaki çok kısa uygulamayı yazdım.
import java.awt.*;
public class IlkPencere
{
public static void main(String args[])
{
Frame pencere=new Frame("ILK PENCEREM");
pencere.setLocation(0,0);
pencere.setBackground(Color.red);
pencere.setVisible(true);
}
} |
Yazdığım bu java dosyasının derledikten sonra çalıştırdım. Karşımda beni bekleyen güzel bir pencere olacağı düşüncesindeydim. Gerçektende muazzam bir pencere oluşturmayı başarmıştım :)

Doğruyu söylemek gerekirse daha büyük bir frame olacağını düşünmüştüm. Bunun üzerine yazmış olduğum kod satırlarını incelemeye başladım. İlk olarak awt.window paketinde yer alan Frame sınıfından bir nesne örneği oluşturmuştum. Bunu yaparkende, yapıcı metoda string tipte bir parametre gönderdim. Bu parametre Frame penceresinin başlığı (Title) olacaktı.
| Frame pencere=new Frame("ILK PENCEREM"); |
Daha sonra, Frame’ in ekran üzerindeki konumunu belirledim. Bunun içinde setLocation metoduna X ve Y koordinatlarını 0 olarak verdim. Böylece, Frame penceresi ekranın sol üst köşesinde konumlanacaktı.
| pencere.setLocation(0,0); |
setBackgorund metodu ile Frame penceresinin arka plan rengini kırmızı olarak belirledim.
| pencere.setBackground(Color.red); |
Frame sınıfının en önemli metodu ise setVisible idi. Bu metod, oluşturulan Frame penceresinin gösterilmesini sağlıyordu. Bunun için parametre olarak metoda true değerini vermek yeterliydi.
| pencere.setVisible(true); |
Buraya kadar herşey sorunsuz gözüküyordu. Ancak Frame’ in neden böyle göründüğünü tam olarak anlayamamıştım. Kaynaklarımı gözden geçirdiğimde, setSize isimli metodu kullanmadığımı farkettim. Bu metod ile Frame’ in başlangıç boyutlarını belirleyebiliyordum. Şimdi tek yapmam gereken uygulama koduna setSize metodunu ilave etmek olacaktı. Lakin ufak bir sorun vardı. O da, Frame penceresini X butonuna basıp kapatamıyor oluşuydu. Programdan çıkamıyordum. Bunun tek bir nedeni olabilirdi o da, X butonu ile kapatma işlemi için gerekli olan olay dinleyecisinin ilgili olay metodunu çalıştırmayışıydı.
Frame sınıfının olaylarına sonradan zaten bakacaktım. Ancak bu pencereyi bir şekilde kapatıp, kodumu düzenlemek istiyordum. Yaklaşık bir yarım saat kadar sırf bu pencerenin nasıl kapatılacağını araştırdım. Nitekim windows’ un ALT+F4 tuş kombinasyonu dahi işe yaramıyordu. Sonunda komut satırından CTLR+C tuş komimasyonuna basmam gerektiğini öğrendim. Bu tuş kombinasyonu sayesinde açık olan uygulama kapatılabiliyordu. Artık uygulama kodlarımı düzenleyebilir ve Frame penceresinin istediğim boyutlarda oluşturulmasını sağlayabilirdim. Bu amaçla kodlarıma aşağıdaki satırı ekledim. Burada ilk parametre Frame penceresinin genişliğini (width), ikinci parametres ise yüksekliğini (height) belirtmekteydi.
| pencere.setSize(300,100); |
Uygulamayı bu haliyle derleyip çalıştırdığımda 300 piksel genişliğinde ve 100 piksel yüksekliğinde bir Frame penceresi elde ettim. Artık hem Title görünüyordu, hemde Frame penceresi daha makul boyutlardaydı.

Kaynaklardan Frame ile ilgili olarak kullanabileceğim diğer teknikleride araştırmaya başladım. örneğin, X butonunun aksine, Minimize ve Maksimize butonları çalışıyor dolayısıyla Frame penceresi mimimize edilebiliyor yada maksimize olabiliyordu. Derken aklıma, bu Frame’ in Maksimize edilmek istendiğinde, belirli yükseklik ve genişliğin üstüne çıkmamasını nasıl sağlayabileceğim sorusu geldi. Bunun için setMaximizedBounds() isimli bir metod buldum. Bu Frame sınıfına ait metoda Rectangle sınıfı türünden bir nesne parametre olarak aktarılabiliyordu. Bu Rectangle nesnesi, bir dortgen şeklini boyutları ve konumları ile bildirebildiğinden, setMaximizedBounds metodu sayesinde, Frame penceresi belirtilen Rectangle nesnesinin boyutları kadar büyüyebilecekti. Hemen bu durumu analiz etmek amacıyla uygulama kodlarını aşağıdaki gibi geliştirdim.
Rectangle r=new Rectangle(500,500);
pencere.setMaximizedBounds(r); |
Burada Rectangle sınıfından nesne örneğini oluştururken, parametre olarak genişlik ve yüksekliği bildirdim. İlk parametre Rectangle nesnesinin genişliğini, ikinci parametre ise yüksekliğini belirtmekteydi. Daha sonra, setMaximizedBounds metoduna, bu Rectangle nesnesini parametre olarak verdim. Uygulamayı tekrar derleyip çalıştırdığımda ve Maksimize butonuna bastığımda, Frame’ in 500 piksel X 500 piksel boyutlarına geldiğini gördüm. Normal şartlar altında bu metodu kullanmasaydım, Frame tüm ekranı kaplayacak şekilde boyutlandırılacaktı.
Frame pencereleri ile ilgili aklıma takılan bir diğer nokta ise, X butonu ile pencereyi kapatamayışımdı. Bunu kendim programlamam gerekiyordu. Bir başka deyişle, olay metodunu yazmalıydım. Kaynaklarımı araştırdığımda, Java Frame sınıfının aşağıdaki window olay metodlarına cevap verebildiğini öğrendim.
|
Frame için Window Olayları
|
| windowOpened |
Pencere ilk kez gösterildiğinde çalışan olay. |
WindowListener Arayüzünden |
| windowClosing |
Pencere kullanıcı tarafından kapatılırken gerçekleşen olay. |
| windowClosed |
Pencere kapatıldıktan sonra çalışan olay. |
| windowIconified |
Pencere minimize edildiğinde gerçekleşen olay. |
| windowDeiconified |
Minimize olan bir Pencere normal haline döndüğünde gerçekleşen olay. |
| windowActivated |
Pencereya odaklanıldığı (Focus) yani aktifleştirildiği zaman çalışan olay. |
| windowDeactivated |
Pencereden ayrılındığında çalışan olay. |
| windowLostFocus |
Focus (odak) pencereden uzaklaştığında çalışan olay. |
WindowFocusListener Arayüzünden |
| windowGainedFocus |
Odak (Focus) pencereye geldiğinde çalışan olay. |
| windowStateChanged |
Pencerenin durumu değiştiğinde (minimize edildiğinde, maksimize edildiğinde vb.) çalışan olay. |
WindowStateListener Arayüzünden |
İlk olarak denemek istediğim, pencerenin X butonu ile kapatılabilmesiydi. öncelikle, windowClosing metodunu uygulamam gerekiyordu. Bunu gerçekleştirebilmek için, WindowListener arayüzünü sınıfa uygulamalıydım. Böylece, WindowListener arayüzünden uyguladığım windowClosing metodunda yazabilir ve X butonu ile pencerenin kapatılaması sırasında oluşacak olayı kodlayabilirdim. Bu amaçla sınıf kodlarını aşağıdaki gibi geliştirdim.
import java.awt.*;
import java.awt.event.*;
public class IlkPencere implements WindowListener
{
public static void main(String args[])
{
IlkPencere p=new IlkPencere();
Frame pencere=new Frame("ILK PENCEREM");
pencere.setLocation(0,0);
pencere.setBackground(Color.red);
pencere.setSize(300,100);
Rectangle r=new Rectangle(500,500);
pencere.setMaximizedBounds(r);
pencere.addWindowListener(p);
pencere.setVisible(true);
}
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
} |
Programı bu haliyle derlediğimde aşağıdaki hata mesajını aldım.

Anladığım kadarı ile WindowListener arayüzündeki tüm window olay metodlarını sınıf içerisinde kullanmasamda bildirmeliydim. Bu amaçla sınıfa aşağıdaki metodlarıda ekledim.
public void windowOpened(WindowEvent e)
{
}
public void windowClosed(WindowEvent e)
{
}
public void windowIconified(WindowEvent e)
{
}
public void windowDeiconified(WindowEvent e)
{
}
public void windowActivated(WindowEvent e)
{
}
public void windowDeactivated(WindowEvent e)
{
} |
Uygulama başarılı bir şekilde derlendikten sonra, hemen X butonu ile kapatılıp kapatılamadığını denemedim. Sonuç başarılıydı. Elbetteki bir pencere bu haliyle çok yavan durmaktaydı. Bu pencereye kontroller eklemek gerekiyordu. Normal bir Applet’ e kontroller nasıl ekleniyorsa buradada aynı kurallar geçerliydi. Bu kez bir Applet’ e kontrol eklemek yerine bir Frame nesnesine kontrol ekleyecektim. Bu amaçla uygulamayı biraz daha düzenlemeye ve ilginç hale getirmeye karar verdim. Amacım Frame içindeki bir button yardımıyla başka bir frame penceresinin açılabilmesini sağlamaktı. Bu amaçla aşağıdaki örneği oluşturdum.
import java.awt.*;
import java.awt.event.*;
public class IlkPencere implements WindowListener,ActionListener
{
public Frame p1;
public Button btnIkinciPencere;
public Button btnKapat;
public int X;
public int Y;
public void PencereAyarla(String baslik,int genislik,int yukseklik,int konumX, int konumY,Color
arkaPlanrengi)
{
X=konumX;
Y=konumY;
p1=new Frame(baslik);
p1.setLocation(konumX,konumY);
p1.setBackground(arkaPlanrengi);
p1.setSize(genislik,yukseklik);
p1.setLayout(new FlowLayout());
p1.addWindowListener(this);
btnIkinciPencere= new Button("Ikinci Pencere");
btnKapat=new Button("Kapat");
p1.add(btnIkinciPencere);
p1.add(btnKapat);
btnKapat.addActionListener(this);
btnIkinciPencere.addActionListener(this);
p1.setVisible(true);
}
public static void main(String args[])
{
IlkPencere p=new IlkPencere();
p.PencereAyarla("ANA PENCERE",250,100,0,0,Color.white);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==btnKapat)
{
p1.setVisible(false);
}
else if(e.getSource()==btnIkinciPencere)
{
IlkPencere p=new IlkPencere();
X=X+50;
Y=Y+50;
p.PencereAyarla("ANA PENCERE",100,100,X,Y,Color.red);
}
}
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
public void windowOpened(WindowEvent e)
{
}
public void windowClosed(WindowEvent e)
{
}
public void windowIconified(WindowEvent e)
{
}
public void windowDeiconified(WindowEvent e)
{
}
public void windowActivated(WindowEvent e)
{
}
public void windowDeactivated(WindowEvent e)
{
}
}
|
Bu uzayıp giden kodlar çok işe yaramıyor. Ancak şu ana kadar GUI ’ler ile ilgili bilgilerimi tekrar etmemede yardımcı oldu. Bu uygulama çalıştığında ilk olarak belirtilen boyutlarda, konumda, başlıkta ve art alan renginde bir ana pencere oluşturuyor. Bu pencere üzerine, FlowLayout sınıfının öngördüğü Layout düzenine göre yerleşen iki Button bileşenim var. Ikınci Pencere başlıklı button bileşenine tıklandığında yeni bir pencere oluşturuluyor. Kapat button bileşeni ise, bu pencereyi kapatıyor. Bu kapatma işleminde setVisible(false) metodunu kullandım. Böylece sonradan açılan pencereler aslında gizleniyordu.
Uygulamayı bu haliyle derleyip çalıştırdığımda aşağıdaki gibi bir görüntü oluştu. Her yeni pencere bir öncekinin konumunun 50 birim sağına ve altına konumlandırılıyor. Elbette X butonuna basıldığında System.exit(0) metodu o an çalışan prosesi sonlandırdığı için tüm pencereler kapanmaktaydı. Mesela ilk pencerede Kapat başlıklı butona basınca komut satırı açık kalacak şekilde pencere ortadan kayboluyor. Yani görünmez oluyor. Ancak proses çalışmaya devam ediyor. Sanırım neden işe yaramaz bir program olduğu ortada. Olsun en azından el cimnastipi yapmış oldum.

Şu anada kadar yaptıklarım ile geliştirdiğim bu pencere uygulamalarında önemli bir sorun var aslında. Bu uygulamaları çalıştırabilmek için komut satırında ilgili sınıfı java yorumlayıcısı ile açmam gerekiyor. Diğer taraftan uygulama çalışırken, komut satırı açık kalıyor. Oysaki normal bir exe dosyası gibi bu uygulamanın tek başına çalışabilmesi çok daha yerinde olur. İşte bunu gerçekleştirmek için kaynaklarda 3 yoldan bahsedildiğini öğrendim. En basit olanı üçüncü parti yazılımlar ile bu işi gerçekleştirmek. örneğin halen daha özlemini çektiğim değerli arkadaşımın bilgisayarında yer alan JBuilder gibi.
Diğer iki yol ise bizim manuel olarak kullanabileceğimiz teknikler içeriyor. Bunlardan birisi Dos ortamından kalma bat(batch) uzantılı dosyalar içerisine uygulamayı çalıştıracak kod satırını yazmak. Diğeri ise, GUI uygulamasına ati tüm sınıfları ve gerekli dosyaları içeren bir JAR paketi oluşturmak. Açıkçası JAR paketini oluşturmak bana daha mantıklı göründü. Ancak bir JAR paketini oluşturmadan önce, bu JAR paketi için verisyon numarası, ana sınıf gibi bilgileri içeren bir manifesto dosyası hazırmamam gerektiğini öğrendim. Bu manifesto dosyası, mf uzantılı olmakla birlikte, aslında .net assembly’ larındaki manifesto bilgilerinin tutulduğu yapıya benzer bir içeriğe sahip. çok basit olarak geliştridiğim java uygulaması için aşağıdaki bilgileri içeren bir manifesto dökümanı hazırladım.
Manifest-Verison: 1.0
Main-Class: IlkPencere
Created-By: 1.4.1 (Sun Microsystems Inc.) |
Bu dosyayı Manifesto.mf ile kaydettikten sonra aşağıdaki komut ile, Jar dosyasını oluşturdum.


Artık Pencereler.Jar dosyasına çift tıkladığımda GUI uygulamasının, normal bir windows uygulaması gibi çalıştığını gördüm. Bu sorunu çözmem son derece önemli idi. Artık windows tabanlı GUI’ lerin nasıl oluşturulduğunu, window olaylarına nasıl cevap verdiğini biliyordum. Dahası bu pencereler üzerine awt bileşenlerinin nasıl ekleneceğini ve herşeyden önemlisi bu GUI uygulamasının çift tıklamalı versiyonunun Jar dosyası olarak nasıl hazırlanabileceğini biliyordum. Artık tüm bu bildiklerimi birleştirerek daha işe yarar bir uygulama yapabileceğim kanısındaydım. Bunun için aklıma basit bir hesap makinesi uygulması yazmak geldi. Ama çok basit. Sadece 2 operand değeri için 4 işlem yapacaktı. Lakin burada önemli olan, Frame’ in tasarlanması ve Frame üzerindeki bileşenlerin olaylara tepki vermesinin sağlanmasıydı. Hemen kolları sıvadım ve uygulamayı geliştirmeye başladım. Sonuçta hem pratik yapmış oldum hemde GUI bilgilerimi tekrar etmiş. Sonuçta aşağıdaki küçük programcık ortaya çıktı.
import java.awt.*;
import java.awt.event.*;
/* HesapMakinesi sınıfında window olaylarına ve Button olaylarına izin verebilmek için, WindowListener ve ActionListener arayüzlerinin uygulanması gerekir. */
public class HesapMakinesi implements WindowListener,ActionListener
{
/* Frame sınıfına ait nesne tanımlanıyor ve bu Frame üzerindeki awt bileşenleri tanımlanıyor.*/
public Frame f;
public Button btnHesapla;
public Label lbSayi1;
public Label lbSayi2;
public Label lbIslem;
public TextField tfSayi1;
public TextField tfSayi2;
public Choice lstIslem;
/* iki sayı değerini ve işlem sonucunu tutacak double tipinden değişkenler tanımlanıyor.*/
public double sayi1,sayi2,sonuc;
/* Olustur metodunda, penceremiz ve üzerindeki bileşenler oluşturuluyor.*/
public void Olustur()
{
f=new Frame("Hesap Makinesi"); // Başlığı (Title) Hesap Makinesi olan bir Frame nesnesi oluşturuluyor.
f.setLayout(new FlowLayout()); // Frame üzerindeki bileşenler FlowLayout tekniğine göre dizilecekler.
Color c=new Color(248,221,139); /* Color tipinden bir nesne R (Red), G (Green), B(Blue) formatında oluşturuluyor.*/
f.setBackground(c); // Pencerenin arka plan rengi c isimli Color nesnesine göre belirleniyor.
/* TextField bileşenleri 10 karakter uzunluğunda oluşturuluyor.*/
tfSayi1=new TextField(10);
tfSayi2=new TextField(10);
/* Label bileşenleri başlıkları ile oluşturuluyor.*/
lbSayi1=new Label("Sayi 1");
lbSayi2=new Label("Sayi 2");
lbIslem=new Label("ISLEMIN SONUCU...");
/* Button bileşeni oluşturuluyor ve bu bileşen için olay dinleyicisi ekleniyor.*/
btnHesapla=new Button("Hesapla");
btnHesapla.addActionListener(this);
/* Choice (başka bir deyişle ComboBox) bileşeni oluşturuluyor. Listedeki elemanlar addItem metodu ile ekleniyor.*/
lstIslem=new Choice();
lstIslem.addItem("TOPLA");
lstIslem.addItem("CIKART");
lstIslem.addItem("BOL");
lstIslem.addItem("CARP");
/* Bileşenler sırasıyla Frame bileşenine yani pencereye add metodu ile ekleniyor. */
f.add(lbSayi1);
f.add(tfSayi1);
f.add(lstIslem);
f.add(lbSayi2);
f.add(tfSayi2);
f.add(btnHesapla);
f.add(lbIslem);
f.pack(); /* pack metodu ile pencerenin yüksekliği ve genişliği, içerdiği bileşenlerin kapladığı alana göre otomatik olarak ayarlanıyor.*/
f.addWindowListener(this); // Frame bileşeni için window olay dinleyicisi ekleniyor.
f.setVisible(true); // Frame bileşeni (pencere) gösteriliyor.
}
/* IslemYap metodunda 4 işlem gerçekleştiriliyor. */
public void IslemYap()
{
sayi1=Double.parseDouble(tfSayi1.getText()); /* TextField bileşenlerinin string içeriği Double sınıfının parseDouble metodu ile double tipine dönüştürülerek değişkene atanıyor.*/
sayi2=Double.parseDouble(tfSayi2.getText());
/* if koşullarında Choice bileşeninde seçili olan item getSelectedItem() metodu ile alınıyor ve uygun olan işlemler yapılıyor.*/
if(lstIslem.getSelectedItem()=="TOPLA")
{
sonuc=sayi1+sayi2;
bIslem.setText(sayi1+"+"+sayi2+"="+sonuc);
}
else if(lstIslem.getSelectedItem()=="CARP")
{
sonuc=sayi1*sayi2;
lbIslem.setText(sayi1+"x"+sayi2+"="+sonuc);
}
else if(lstIslem.getSelectedItem()=="CIKART")
{
sonuc=sayi1-sayi2;
lbIslem.setText(sayi1+"-"+sayi2+"="+sonuc);
}
else if(lstIslem.getSelectedItem()=="BOL")
{
sonuc=sayi1/sayi2;
lbIslem.setText(sayi1+"/"+sayi2+"="+sonuc);
}
}
public static void main(String args[])
{
HesapMakinesi m=new HesapMakinesi();
m.Olustur();
}
/* actionPerformed olayı meydana geldiğinde bu metod çalışıyor.*/
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==btnHesapla) // Eğer olayın kaynağı Button bileşeni ise, yani Button’ a tıklandıysa.
{
IslemYap();
}
}
/* Kullanıcı X buton ile pencereyi kapatmak istediğinde bu olay metodu çalışıyor. */
public void windowClosing(WindowEvent e)
{
System.exit(0); /* Güncel olan proses sonlandırılıyor. Dolayısıyla uygulama sona eriyor. */
}
public void windowOpened(WindowEvent e)
{
}
public void windowClosed(WindowEvent e)
{
}
public void windowIconified(WindowEvent e)
{
}
public void windowDeiconified(WindowEvent e)
{
}
public void windowActivated(WindowEvent e)
{
}
public void windowDeactivated(WindowEvent e)
{
}
} |
Programı derledikten sonra Manifesto dosyasını (ManifestoHesapMakinesi.mf) aşağıdaki gibi düzenledikten sonra, JAR Paketinide hazırladım.
Manifest-Verison: 1.0
Main-Class: HesapMakinesi
Created-By: 1.4.1 (Sun Microsystems Inc.) |

Paketi çift tıkladığımda, basit hesap makinesi uygulamam kullanılmaya hazırdı.

Artık GUI’ lerde iyice ilerlemeye başladığımı hissediyordum. Bununla birlikte, 2 boyutlu grafik çizimleri, animasyon hazırlamak, resim işlemek, ses işlemek, Swing bileşenleri, Menu’ ler vs... gibi henüz bilmediğim daha pek çok konu vardı. Ancak hem kahvem hemde pilim bitmişti. Sanırım önümüzdeki günlerde, bu konulara eğileceğim.
Kaynak : csharpnedir.com
|
 |