You are on page 1of 10

Java ile Görsel Programlamaya Giriş

Ersin Çine 13.12.2014

Java ile görsel programlama için mevcut en yaygın yol: Swing (Diğer alternatifler: JavaFX, SWT, AWT).

SWT ve AWT öğrenmek, bu vakitten son önemli değil. Topluluk, artık JavaFX’e yönleniyor. Yine de Swing’e
derinlemesine girmeksizin bizim anlatacağımız kadar kısmını öğrenmek size çok şey katacaktır. Swing kütüphanesinin
çok küçük ama yeterli bir kısmını göreceğiz. Bu sayede nesneye dayalı programlamanın en önemli kavramlarını
öğreneceksiniz.

Swing Component’leri (Bileşen) iki çeşittir:

1. Container (JPanel gibi, içine başka bileşen eklenebilen bileşen),


2. Control (JLabel gibi, içine bileşen eklenemeyen bileşen).

Bazı çok temel bileşenler:

JFrame: Pencere. Tek bir pencere kullanacağız.


JPanel: Tepsi. Pencerenin içerik alanını dolduracak ve bütün bileşenler üzerine eklenecek.
JLabel: Yazı (Kullanıcı sadece okur).
JButton: Düğme (Tıklama olayı var).
JTextField: Yazı kutusu (Kullanıcı okur ve yazar).

JFrame için:

JFrame pencere = new JFrame(); // JFrame örneği oluşturulur.


pencere.setTitle("Pencerenin başlığı"); // Pencerenin başlığı ayarlanır.
pencere.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Pencere kapatıldığında program da kapansın.
pencere.setContentPane(tepsi); // Pencerenin içerik kısmına tepsi serilecek. tepsi bir taşıyıcıdır (Örneğin JPanel).
pencere.setSize(300, 200); // Pencere 300 piksel genişliğinde ve 200 piksel yüksekliğinde olsun.
pencere.pack(); // Üsttekine alternatif. Boyutları biz girmiyoruz, penceredeki bileşenlere göre otomatik ayarlanıyor.
pencere.setLocationRelativeTo(null); // Pencere ekranı ortalasın (İsteğe bağlı). Önce pencere boyutunu ayarlayın!
pencere.setResizable(false); // Pencere boyutlarını kullanıcı değiştiremez (Örneğin tam ekran yapamaz).
pencere.setVisible(true); // Görünürlük varsayılan olarak false olur. Gözükmesi için true yapılmalı. En son yapın!

JPanel için:

JPanel tepsi = new JPanel(duzen); // duzen yerine örneğin şu gelir: new GridLayout(3,4,5,5)
// 3 satır, 4 sütun; bileşenler arasında 5 piksel yatay boşluk, 5 piksel dikey boşluk.
// Dolayısıyla bu örnekte tepsiye 12 bileşen eklenir.
tepsi.setBackground(renk); // Tepsinin arka plan rengi değiştirilebilir. renk yerine:
Color.RED gibi renk sabitlerinden biri
Ya da new Color(50,100,200) gibi kendi istediğiniz bir renk gelecek.
[0,255] aralığında sırasıyla kırmızı, yeşil, mavi (RGB) renk ağırlıkları girilir.
tepsi.add(bilesen); // Tepsiye bir bileşen eklenir.
Başka bir JPanel ya da JButton, JLabel, JTextField gibi bir bileşen gelecek.
Bileşenler, satır dolana kadar soldan sağa doğru eklenir. Satır dolunca otomatik olarak bir alt satıra inilir.

JLabel için:

JLabel yazi1 = new JLabel();


yazi1.setText("Yazının içeriği"); // Yazısı değiştirilir.
String s = yazi1.getText(); // Yazısı okunur.
yazi1.setForeground(renk); // Yazının rengi değiştirilir.
yazi1.setBackground(renk); // Yazının arka plan rengi değiştirilir.
JTextField için:

Oluşturulması, içeriğinin değiştirilmesi, içeriğinin okunması, yazı renginin değiştirilmesi ve arka plan renginin
değiştirilmesi tıpkı JLabel için olduğu gibi.

JLabel’da daha çok setText kullanılır (yazıyı biz belirlediğimiz için getText daha az kullanılır), JTextField’da daha çok
getText kullanılır (yazıyı kullanıcı belirlediği setText daha az kullanılır).

JButton için:

Oluşturulması, içeriğinin değiştirilmesi, içeriğinin okunması, yazı renginin değiştirilmesi ve arka plan renginin
değiştirilmesi tıpkı JLabel ve JTextField için olduğu gibi.

Ek olarak şu metot çok kullanılır:

dugme1.addActionListener( new ActionListener() {


@Override
public void actionPerformed(ActionEvent ae) {
// Butona tıklanınca yapılacak şeyler buraya gelecek.

// Burada yapılan şey: ActionListener interfaceini implement eden isimsiz


// bir sınıf oluşturup interfacein actionPerformed metodunu eziyoruz.
// Çünkü addActionListener metodu parametre olarak ActionListener interfaceini
// implement eden bir sınıfın nesnesini istiyor. Ama böyle bir sınıfımız yok. Biz de
// hemen ayaküstü bir sınıf tanımlayıp nesne oluşturuyoruz: new InterfaceAdi() { metot }
// Java 8 ile daha güzel ve daha kolay bir yolu var. Bkz. “Lambda expressions”.
}
} );

Şart değil ama işini çok kolaylaştıracak kurallar (Biz bu kuralları takip edeceğiz):
1. Kullanılacak JFrame, JPanel, JLabel, JButton, JTextField örneklerini yerel değişken olarak değil de, sınıf değişkeni
olarak tanımla.
2. main metodunda yapılacak işleri, kendi tanımlayacağın parametresiz void metotlara paylaştır (Bütün değişkenler
sınıf değişkeni olduğu için parametreye ve değer döndürmeye gerek yok).
ÖRNEK BİR PROGRAM (1. YAKLAŞIM)
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GorselProgram {


private static JFrame pencere;
private static JPanel tepsi;
private static JLabel yazi1, yazi2, yazi3;
private static JTextField yaziKutusu1, yaziKutusu2;
private static JButton dugme;

public static void main(String[] args) {


pencereyiOlusturupTepsiEkle();
tepsiyeBilesenleriEkle();
dinleyicileriEkle();
pencereAyarlariniYap();
}

private static void pencereyiOlusturupTepsiEkle() {


pencere = new JFrame();
tepsi = new JPanel( new GridLayout(3,2,10,10) );
tepsi.setBackground( Color.YELLOW );
pencere.setContentPane( tepsi );
}

private static void tepsiyeBilesenleriEkle() {


yazi1 = new JLabel();
yazi1.setText("İsim: ");
tepsi.add(yazi1);

yaziKutusu1 = new JTextField();


tepsi.add(yaziKutusu1);

yazi2 = new JLabel();


yazi2.setText("Yaş: ");
tepsi.add(yazi2);

yaziKutusu2 = new JTextField();


tepsi.add(yaziKutusu2);

dugme = new JButton();


dugme.setText("Tıkla!");
dugme.setBackground(Color.RED);
tepsi.add(dugme);
yazi3 = new JLabel();
yazi3.setForeground(Color.BLUE);
tepsi.add(yazi3);
}

private static void dinleyicileriEkle() {


dugme.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
String isim = yaziKutusu1.getText();
String yas = yaziKutusu2.getText();
String mesaj = isim + ", " + yas + " yaşındadır.";
yazi3.setText(mesaj);
}
} );
}

private static void pencereAyarlariniYap() {


pencere.setTitle("Program");
pencere.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pencere.setSize(400, 600);
pencere.setLocationRelativeTo(null);
pencere.setResizable(false);
pencere.setVisible(true);
}
}

Çalışırıp deneyin!
İkinci yaklaşım (Bunun da mantığını bilmek çok önemli. Yoksa nesneye dayalı programlama anlaşılmaz!):

Birinci yaklaşımı iyi anlamadan buraya gelme!

 Sınıfı extends JFrame şeklinde tanımlayın. Yani sınıfın kendisi, bir çeşit JFrame olacak.
 main metodunda yazdıklarımızı kurucu metoda yazın.
 main metoduna SinifAdi pencere = new SinifAdi(); ya da kısaca new SinifAdi(); yazın.
 Yeni main metodu dışında kodda pencere kelimesini kullanmayacaksınız artık. Örneğin
pencere.setContentPane(), pencere.setVisible() yerine setContentPane(), setVisible() kullanacaksınız. Çünkü
zaten pencere’nin içindesiniz!
 Artık static çalışmıyoruz! [main hep statictir, o hariç] İşte nesneye dayalı programlama!

ÖRNEK BİR PROGRAM (2. YAKLAŞIM: NESNEYE DAYALI)


(Önceki örneğe göre; silinen yerler kırmızı, eklenen yerler yeşil gösterilmiştir.)

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GorselProgram extends JFrame { // Bu sınıfın kendisi bir penceredir. Başka bir pencereye gerek yok!
private static JFrame pencere;
private static JPanel tepsi;
private static JLabel yazi1, yazi2, yazi3;
private static JTextField yaziKutusu1, yaziKutusu2;
private static JButton dugme;

public static void main(String[] args) { // Program çalıştığında sınıfımızdan bir nesne üretelim
new GorselProgram(); // Yeni bir nesne oluşturmamız yeterli. İsim bile vermemize gerek yok.
pencereyiOlusturupTepsiEkle();
tepsiyeBilesenleriEkle();
dinleyicileriEkle();
pencereAyarlariniYap();
}

public GorselProgram() { // new GorselProgram() dendiği an yapılması gereken her şey burada.
pencereyiOlusturupTepsiEkle();
tepsiyeBilesenleriEkle();
dinleyicileriEkle();
pencereAyarlariniYap();
}

private static void pencereyiOlusturupTepsiEkle() {


pencere = new JFrame(); // Zaten pencerenin içindeyiz.
tepsi = new JPanel( new GridLayout(3,2,10,10) );
tepsi.setBackground( Color.YELLOW );
pencere. setContentPane( tepsi ); // Başına isteğe bağlı “this.” eklenebilir.
}

private static void tepsiyeBilesenleriEkle() {


yazi1 = new JLabel();
yazi1.setText("İsim: ");
tepsi.add(yazi1);

yaziKutusu1 = new JTextField();


tepsi.add(yaziKutusu1);

yazi2 = new JLabel();


yazi2.setText("Yaş: ");
tepsi.add(yazi2);

yaziKutusu2 = new JTextField();


tepsi.add(yaziKutusu2);

dugme = new JButton();


dugme.setText("Tıkla!");
dugme.setBackground(Color.RED);
tepsi.add(dugme);

yazi3 = new JLabel();


yazi3.setForeground(Color.BLUE);
tepsi.add(yazi3);
}

private static void dinleyicileriEkle() {


dugme.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
String isim = yaziKutusu1.getText();
String yas = yaziKutusu2.getText();
String mesaj = isim + ", " + yas + " yaşındadır.";
yazi3.setText(mesaj);
}
} );
}

private static void pencereAyarlariniYap() {


pencere. setTitle("Program"); // Başına isteğe bağlı “this.” eklenebilir: this.setTitle("Program");
pencere. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Hepsi için geçerli…
pencere. setSize(400, 600);
pencere. setLocationRelativeTo(null);
pencere. setResizable(false);
pencere. setVisible(true);
}
}
ÖNEMLİ BİR NOKTA İÇİN AÇIKLAMA VE DİĞER YAKLAŞIMLAR
(Renklere dikkat!)

Aşağıdaki kod biraz garip…


dugme.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
String isim = yaziKutusu1.getText();
String yas = yaziKutusu2.getText();
String mesaj = isim + ", " + yas + " yaşındadır.";
yazi3.setText(mesaj);
}
} );

Aslında yapılmak istenen şey şu:


dugme.addActionListener( x );

Fakat sorun şu:


x biraz karmaşık.

x yerine ne gelmeli?
“implements ActionListener” olan (ActionListener interfaceini implement eden) bir sınıftan üretilmiş bir nesne.

Interface nedir? Implements nedir? Ne oluyor burada?


Interfaceler birer sözleşme gibidir. İçlerinde metot(lar) vardır ama metotların sadece başlığı vardır, gövdesi yoktur
(Interfacelerdeki metotlar default olarak abstracttır). Bir sınıfın bir (veya daha çok) interfacei implements etmesi,
“ben bu interface(ler)deki metotları override edeceğim” sözünü vermesi anlamına gelir. Override etmek, metodun
başlığını aynen alıp gövdeyi kendin yazmak anlamına gelir.

Bir örnek versen?


public interface KonsolaYazilabilir {
public void konsolaYaz();
}

Böyle bir interfaceimiz olsun. KonsolaYazilabilir ky = new KonsolaYazilabilir(); şeklinde bir kod yazılamaz. Çünkü
interfacelerden nesne üretilmez, sınıflardan nesne üretilir! Zaten böyle nesne mi olur? Orada bir metot var ama metot
kendisinin nasıl çalışacağını bilmiyor!

public class Sayi implements KonsolaYazilabilir {


private double sayi;

public Sayi(double s) {
sayi = s;
}

@Override // Verdiğimiz sözü yerine getiriyoruz.


public void konsolaYaz() { // Burayı (metot başlığını) aynen yazdık.
System.out.println(sayi); // Metot gövdesi bize kalmış!
}

// … Canımızın tanımlamak istediği başka metotlar varsa onları da ekleyebiliriz.

}
Şimdi şunu yazabiliriz:

KonsolaYazilabilir ky = new Sayi(3.5);


ky.konsolaYaz();

veya

Sayi s = new Sayi(3.5);


s.konsolaYaz();

Ama asla new KonsolaYazilabilir(); yazamayız!

E o zaman bu interface ne işe yarıyor? O hiç olmasa, sınıfta yine konsolaYaz metodunu tanımlasak olmaz mı?
Burada olur tabii ama asıl problemimizde olmaz. Adam sizden, public void actionPerformed(ActionEvent ae) metodu
barındıran bir nesne istiyor. Bunu söylemenin yolu şu: Gidip mesela ActionListener adında bir interface tanımlar. İçine
bu metodu yazar.

public interface ActionListener {


public void actionPerformed(ActionEvent ae);
}

Sonra da bu tipte bir parametre ister:

public class JButton {



public void addActionListener(ActionListener al) {

}
}

Senin yapman gereken şuna benzer bir şey:

public class SeninSinifin {



public static void main(String[] args) {
JButton dugme = new JButton();
dugme.addActionListener( BURAYA NE KOYACAĞIMI HALA BİLMİYORUM -_- );
}
}

Tamam dur oraya ne koyacağını söylüyorum şimdi.


Parametre olarak tanımlanan “şey” sınıf değil interface, bunu biliyorsun.
O halde şunlardan birini yapman lazım:

1. SEÇENEK: O interfacei implement eden bir sınıf ayrıca tanımla ve o sınıftan oluşturduğun nesneyi parametre olarak
ver.
public class AmanYaBirSinifDahaCikti implements ActionListener {
@Override
public void actionPerformed(ActionEvent ae) {
String isim = yaziKutusu1.getText();
String yas = yaziKutusu2.getText();
String mesaj = isim + ", " + yas + " yaşındadır.";
yazi3.setText(mesaj);
}
}

Ama şimdi burada HATA var. Adam, yaziKutusu1, yaziKutusu2, yazi3 nedir bilmiyor ki!?

public class AmanYaBirSinifDahaCikti implements ActionListener {

private JTextField yaziKutusu1, yaziKutusu2;


private JLabel yazi3;

public class AmanYaBirSinifDahaCikti(JTextField yk1, yk2, y3) {


yaziKutusu1 = yk1;
yaziKutusu2 = yk2;
yazi3 = y3;
}

@Override
public void actionPerformed(ActionEvent ae) {
String isim = yaziKutusu1.getText();
String yas = yaziKutusu2.getText();
String mesaj = isim + ", " + yas + " yaşındadır.";
yazi3.setText(mesaj);
}
}

Zor oldu ama oldu. Başka sınıfa gittiğimiz için gerekli nesneleri de taşımamız gerekti.
Peki bu sınıfı nasıl kullanacağız?
public class SeninProgramin {

private static void dinleyicileriEkle() {
AmanYaBirSinifDahaCikti x = new AmanYaBirSinifDahaCikti(yaziKutusu1, yaziKutusu2, yazi3);
dugme.addActionListener(x);
}

}

Bu kadar. Ya da:
public class SeninProgramin {

private static void dinleyicileriEkle() {
dugme.addActionListener( new AmanYaBirSinifDahaCikti(yaziKutusu1, yaziKutusu2, yazi3) );
}

}

Ama şöyle parlak bir fikrimiz gelmiş olabilir. Biz zaten bir sınıftayız. Madem o interfacei implement eden bir sınıfa
ihtiyacımız var, bu sınıf implement etsin olsun bitsin. Hem nesneleri (yazı kutuları ve yazılar) taşımamıza da gerek
kalmaz! [Bu durumda programın 2. yaklaşımını yani JFrame extends edip static’ten kurtulmalı, this’e kavuşmalıyız]

public class SeninProgramin extends JFrame implements ActionListener {



private void dinleyicileriEkle() {
dugme.addActionListener(this); // “Bu” (this) zaten bir ActionListener implements eden sınıf nesnesi!
}

@Override
public void actionPerformed(ActionEvent ae) {
String isim = yaziKutusu1.getText();
String yas = yaziKutusu2.getText();
String mesaj = isim + ", " + yas + " yaşındadır.";
yazi3.setText(mesaj);
}

Bu son yaptığımız çok hoş, ama birden fazla düğmemiz olsaydı işe yaramazdı. Çünkü aynı sınıfa bir actionPerformed
metodu daha tanımlayamayız, çakışırlar (Ama yine de mantığını anlamak çok önemli!).

2. SEÇENEK: O interfacei implement eden bir sınıfı satır içinde (isimsiz olarak) tanımla ve bir nesne oluştur.
Yani programda yaptığımız gibi:

dugme.addActionListener( new ActionListener() {


@Override
public void actionPerformed(ActionEvent ae) {
String isim = yaziKutusu1.getText();
String yas = yaziKutusu2.getText();
String mesaj = isim + ", " + yas + " yaşındadır.";
yazi3.setText(mesaj);
}
} );

Artık bunu sevmeye başlamışsındır sanırım :D


Aslında zor değil. Bir interfacei implement eden isimsiz bir sınıftan nesne üretmenin genel hali:

new InterfaceAdi() {
@Override
metot1(Parametreler) {

}

@Override
varsaMetot2FalanDiyeGider(Parametreler) {

}
}

3. SEÇENEK: En güzel ama öğrenmek için şimdilik erken olan yol (Şimdi diğer yöntemleri anlamak çok önemli):
Java 8 ile gelen lambda expressions!

You might also like