Hem masaüstü hem de web tabanlı uygulamalar geliştirirken, zaman zaman eldeki verilerin görselleştirilmesi yani resim olarak ifade edilmesi ve bu resimler üzerinden de düzenlenebilir olması ihtiyacı ile karşılaşılır. Bu yazıda JAVA bileşenleri ve Graphics sınıfı kullanarak etkileşimli veri görselleştirme konusuna bir giriş yapacağız. Başlangıç olarak basit çizim nesnelerinin yerleştirilebildiği ve bu nesnelerin klavye ve fare aracılığıyla yönetilebildiği bir ekran tasarlayalım.Öncelikli olarak bu tip uygulamalarda etkileşim için daha sonra rahatça eklemeler yapabilmek için mümkün olduğunca genel bir çerçeve çizerek sınıfları genişletilebilir hazırlamamızda fayda var. Tüm çizim nesnelerini ifade edebilecek bir ata (parent) sınıf yazarak başlayalım.Ekranımızda çizim yapabileceğimiz bir alana ihtiyacımız olacağı için JPanel sınıfından türeyen (inherit) bir çizim sınıfı oluşturalım.import java.awt.Color;import java.awt.Point;public class CizimNesne {// cizilecek her nesnenin bir bulundugu nokta bilgisi olmalı, varsayılan (0, 0)protected Point Yer = new Point(0, 0);//her nesnenin çizgi/dolgu rengi olmalı, varsayılan siyahprotected Color Renk = Color.BLACK;public CizimNesne(){ }public CizimNesne(int YerX, int YerY, Color Renk){Yer.setLocation(YerX, YerY);this.Renk = Renk;}public void setYer(Point Yer){this.Yer.setLocation(Yer.x, Yer.y);}public void setColor(Color Renk){this.Renk = Renk;}//diger metotlarımız buraya gelecek}
Burada özetle her bir çizim nesnesinin ekranda bulunduğu yeri ifade eden bir Point nesnesi ve çizim rengini ifade eden bir Color değeri olacağını düşünerek, tüm çizim nesneleri için ortak özellikleri ve davranışları barındıran bir sınıf oluşturduk. Bu sınıfa değişiklikler ve eklemeler yapmadan önce diğer sınıflarımızı da yazarak ihtiyaçlarımızı görelim.İlk çizim nesnemiz dikdörtgen tipinde olsun. Bu tipte nesneleri ifade edecek bir veri tipi (sınıf) yaratalım. Bir önceki adımda yaratmış olduğumuz CizimNesne sınıfımız Dikdortgen sınıfı için temel teşkil edecek.public class Dikdortgen extends CizimNesne {private int Genislik = 0;private int Yukseklik = 0;public Dikdortgen(){ super(); }public Dikdortgen(int YerX, int YerY, int Genislik, int Yukseklik, Color Renk){super(YerX, YerY, Renk);this.Genislik = Genislik;this.Yukseklik = Yukseklik;}public void setGenislik(int Genislik){this.Genislik = Genislik;}public void setYukseklik(int Yukseklik){this.Yukseklik = Yukseklik;}//diger metotlarımız buraya eklenecek}
Şu an için sadece bir tipte çizim nesnemiz olsa da, Dikdortgen sınıfını tasarladığımız gibi yeni şekilleri ifade eden farklı sınıfları da programımıza ekleyerek çeşitlilik sağlayabiliriz. İlk denememizi şu an için Dikdortgen nesnelerimiz ile yapalım.Çizim aşamasına geçerken programımızda asla bir CizimNesne’ sinin bulunmayacağını, ekranda görüntülenecek her nesnenin mutlaka CizimNesne’ sinden türemiş bir sınıf tipinde olması gerektiğini bilmemiz gerekiyor. Bu nedenle CizimNesne sınıfımız abstract (soyut) olarak işaretlenmeli ve bu tipte bir obje yaratımına izin verilmemeli. Bu sınıfı abstract yaparken ayrıca her bir çizim nesnesinin mutlaka sahip olması gereken bazı davranışları (fonksiyon) da zorunlu kılabileceğiz.public abstract class CizimNesne {// cizilecek her nesnenin bir bulundugu nokta bilgisi olmalı, varsayılan (0, 0)protected Point Yer = new Point(0, 0);//her nesnenin çizgi/dolgu rengi olmalı, varsayılan siyahprotected Color Renk = Color.BLACK;public CizimNesne(){ }public CizimNesne(int YerX, int YerY, Color Renk){Yer.setLocation(YerX, YerY);this.Renk = Renk;}public void setYer(Point Yer){this.Yer.setLocation(Yer.x, Yer.y);}public void setColor(Color Renk){this.Renk = Renk;}//diger metotlarımız buraya gelecekpublic abstract void ciz(Graphics g);public abstract boolean kesismeKontrol(Point p);}
Bu şekilde artık Dikdortgen sınıfımızda yazmak zorunda olduğumuz iki fonksiyon elde ettik. İlk fonksiyonumuz ciz fonksiyonu. Kendisine gönderilen grafik nesnesi üzerinden Dikdortgen nesnesini ekrana çizdirecek fonksiyonu tanımlamamız gerekiyor.public void ciz(Graphics g) {g.setColor(this.Renk);g.fillRect(this.Yer.x, this.Yer.y, this.Genislik, this.Yukseklik);}
kesismeKontrol fonksiyonumuz ise bir noktanın sözkonusu dikdortgen objesinin sınırları dahilinde olup olmadığını kontrol ederek true/false bir değer döndürecek.public boolean kesismeKontrol(Point p) {if ( (this.Yer.x <= p.x && this.Yer.x + this.Genislik >= p.x)&& (this.Yer.y <= p.y && this.Yer.y + this.Yukseklik>= p.y ))return true;return false;}
Sınıflarımız hazır olduğuna göre artık ekrana çizme işlemine geçebiliriz. Öncelikle çizim nesnelerini barındıracak bir Canvas sınıfı hazırlayalım. JPanel’ den türeteceğimiz bu sınıfı üzerine çizim yapacağımız alan olarak kullanacağız.Anlık olarak çizim ekranımız üzerinde bulunacak çizim nesnelerini tutmak amacıyla bir ArrayList oluşturalım ve eklemek istediğimiz her nesneyi bu ArrayList’e ekleyelim.public class Canvas extends JPanel {public ArrayList GrafikListesi = new ArrayList();public Canvas() {}public void paintComponent(Graphics g){}}
Burada paintComponent metodu Jcomponent sınıfından miras alınan her bir bileşenin ekrandaki görüntüsünün oluşturulması esnasında çalışan fonksiyondur. Bu nedenle, bileşenin çizimi ile ilgili kodlarımızı bu fonksiyona yerleştireceğiz.Basitçe düşünürsek çizim ekranının oluşturulması için bu fonksiyonda yapmamız gereken tek şey GrafikNesneleri listemizdeki tüm nesnelerinin çizimini yapmak. Bu listedeki tüm nesneler CizimNesne sınıfından türediği için her nesnenin ciz(..) fonksiyonu olduğunu biliyoruz. Dolayısıyla her nesne için bu fonksiyonu çağırmamız yeterli olacak.public void paintComponent(Graphics g){super.paintComponent(g);for (CizimNesne n:GrafikListesi) // grafik listesindeki her bir cizimnesnesi için{n.ciz(g);}}
Şimdi ilk ekran çıktımızı alabilmek için bir ana pencere oluşturalım ve elle girdiğimiz bazı dikdortgen nesnelerini ekranda görüntüleyebildiğimizi test edelim.public class CizimTest {public static void main(String args[]){JFrame frm = new JFrame(“Cizim Test Ekranı”);frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);Canvas cizim = new Canvas();cizim.GrafikListesi.add(new Dikdortgen(50, 50, 100, 35, Color.blue));cizim.GrafikListesi.add(new Dikdortgen(85, 150, 90, 235, Color.green));frm.add(cizim); //cizim alanını pencereye eklefrm.setSize(600, 600); //pencere boyutu ayarlafrm.setVisible(true); //pencereyi goster}}
Uygulamayı test ettiğimizde aşağıdaki gibi bir ekran çıktısı alacağız.

Şimdi ekrandaki çizim nesnelerimiz için etkileşimi tasarlayabiliriz.Şu an için ekrandaki dikdörtgen nesnelerimizin fare ile taşınabilir olmasını sağlayalım. Fare ile taşıma işleminde iki farklı aşama yer alıyor. Öncelikle fare butonuna bastığımız ve çektiğimiz an, bu iki arasında da yani fare tuşuna basılı iken fareyi hareket ettirdiğimiz süre. Bu iki tip durum için kodlama yapmamız gerekiyor. JAVA’ da bu iki işlem için MouseListener ve MouseMotionListener uygulamamız gerekiyor. Fare etkileşimleri çizim alanı üzerinde gerçekleşeceği için bu arayüzleri (interface) Canvas sınıfımızda uygulayacağız.public class Canvas extends JPanel implements MouseListener, MouseMotionListener {
Bu değişiklik sınıfımıza şu fonksiyonları eklememizi gerektirir;public void mouseClicked(MouseEvent arg0) { }public void mouseEntered(MouseEvent arg0) { }public void mouseExited(MouseEvent arg0) { }public void mousePressed(MouseEvent arg0) { }public void mouseReleased(MouseEvent arg0) { }public void mouseDragged(MouseEvent arg0) { }public void mouseMoved(MouseEvent arg0) { }
Interface kullanımı gereği tüm metotları uygulamasınızda metot tanımını yapmanız gerekmektedir. Bu yazı için yalnızca mousePressed, mouseReleased ve mouseDragged metotlarını uygulayacağız.İzleyeceğimiz adımlar şu şekilde olacak;* Fare sol butona tıklandığında, tıklanan noktanın çizim ekranındaki mevcut cizim nesnelerden herhangi birine denk gelip gelmediğini bulacağız, eğer geliyorsa bu nesnesi bir yerde tutacağız.* Fare butona basılı iken hareket ettiğinde (drag) tutaln bir nesne var ise o nesnenin Yer bilgisini farenin konumuna göre güncelleyeceğiz.* Fare butonu serbest bırakıldığında tutulan nesneyi serbest bırakacağız.Bunun için Canvas sınıfımıza CizimNesne tipinde bir üye değişken ekleyelim.….ArrayList GrafikListesi = new ArrayList();CizimNesne tasinanNesne = null;public Canvas() {…..Fare metotlarımızı da aşağıdaki gibi tamamlayalım.public void mousePressed(MouseEvent arg0) {tasinanNesne = null;if (arg0.getButton() == MouseEvent.BUTTON1) {for (CizimNesne n:GrafikListesi)if (n.kesismeKontrol(arg0.getPoint())){ tasinanNesne = n;break;}}}public void mouseReleased(MouseEvent arg0) {tasinanNesne = null;}public void mouseDragged(MouseEvent arg0) {if (tasinanNesne != null && arg0.getButton() == MouseEvent.BUTTON1){tasinanNesne.setYer(arg0.getPoint());}}
Son olarak, canvas nesnemiz üzerindeki fare olayları için sınıfı yönetici/dinleyici olarak atayalım. Canvas sınıfı yapılandırıcısında bu işlemi yapabiliriz. Canvas sınıfımızın son durumu aşağıdaki gibi olacaktır.public class Canvas extends JPanel implements MouseListener, MouseMotionListener {ArrayList GrafikListesi = new ArrayList();CizimNesne tasinanNesne = null;public Canvas() {addMouseListener(this);addMouseMotionListener(this);}public void paintComponent(Graphics g){super.paintComponent(g);for (CizimNesne n:GrafikListesi) // grafik listesindeki her bir cizimnesnesi için{n.ciz(g);}}public void mouseClicked(MouseEvent arg0) {// TODO Auto-generated method stub}public void mouseEntered(MouseEvent arg0) {// TODO Auto-generated method stub}public void mouseExited(MouseEvent arg0) {}public void mousePressed(MouseEvent arg0) {tasinanNesne = null;if (arg0.getButton() == MouseEvent.BUTTON1) {for (CizimNesne n:GrafikListesi)if (n.kesismeKontrol(arg0.getPoint())){ tasinanNesne = n;break;}}}public void mouseReleased(MouseEvent arg0) {tasinanNesne = null;}public void mouseDragged(MouseEvent arg0) {if (tasinanNesne != null && arg0.getButton() == MouseEvent.BUTTON1){tasinanNesne.setYer(arg0.getPoint());}repaint();}public void mouseMoved(MouseEvent arg0) {}}
Uygulamamızı çalıştırdığınızda fare yardımıyla dikdortgenleri ekranda taşıyabildiğimizi göreceğiz.Bu uygulamaya kendiniz sadece üçgen, daire gibi farklı şekil sınıfları ekleyerek kodların bu sınıflar için de çalışabildiğini göreceksiniz. Bu uygulamada kalıtım ve polimorfizm kavramlarını kullanarak kodları oldukça kısa tuttuk. Yazının ileriki bölümlerinde bu yapı üzerine kuracağımız detaylı çizim ekranlarında da kodlar karmaşıklaşmadığını göreceğiz.