Bölüm 8: Grafikler

Java ile Nesne Yönelimli Programlama
Grafik programlamaJFrame ve JPanelGraphics ile çizimPoint, Color, Font Yerleşim yöneticileriFare olaylarıDüğme ve metin bileşenleriÖrnek uygulamalar
Sercan KÜLCÜ · Giresun Üniversitesi · Elektrik-Elektronik Mühendisliği

Giriş

Öğrenme Çıktıları

Pencere kurmak

JFrame ve JPanel ile pencere ve panel oluşturmak, bileşen eklemek, pencereyi göstermek ve kapatmak.

Çizmek

paintComponent metodunu geçersiz kılıp Graphics ile şekil ve metin çizmek; ekran koordinatlarını kullanmak.

Yerleştirmek

BorderLayout, FlowLayout ve GridLayout ile bileşenleri düzenlemek.

Olaylara yanıt vermek

Dinleyici arayüzleri, adaptör sınıfları ve lambda ile fare ve düğme olaylarını işlemek.

Güvenli başlatmak

Arayüzü SwingUtilities.invokeLater ile olay iş parçacığında kurmanın nedenini açıklamak.

Uygulama yazmak

Çizim programı, metin dönüştürücü ve para üstü hesaplayıcıyı okuyup değiştirebilmek.

Grafik Programlama

Grafik Programlama

  • Java, grafik kullanıcı arayüzü (GUI, Graphical User Interface) geliştirmek için güçlü ve kapsamlı bir araç seti sunar: pencereler, düğmeler, metin alanları, çizimler.
  • Böylece etkileşimli ve görsel uygulamalar yazılabilir. Bunun için üç kavramı anlamak gerekir:
Bileşenler (components)

Pencere, düğme, etiket, metin alanı gibi arayüzün yapı taşları. Her biri bir sınıfın nesnesidir.

Olay işleme (event handling)

Fare tıklaması, tuşa basma gibi kullanıcı eylemlerini yakalar ve bunlara yanıt veren metotları çağırır.

Görsel oluşturma (painting)

Şekilleri çizer, ekranı günceller ve bileşenlerin görüntülenmesini sağlar.

Benzetme: bir GUI programı, müşteriyi bekleyen bir dükkân gibidir. Vitrin (bileşenler) hazırlanır, sonra program bekler; müşteri ne zaman neye dokunursa (olay) ilgili görevli (dinleyici metot) çalışır.

Grafik Programlama

Konsol ve GUI Programı

Konsol programıGUI programı
AkışSıralı: main baştan sona çalışır, soruyu program sorarOlay güdümlü (event-driven): program kullanıcının hamlesini bekler
GirdiScanner ile klavyeden satır okunurDüğme, metin alanı, fare; dinleyici metotlar çağrılır
ÇıktıSystem.out.printlnBileşenlerin metni değişir veya panel yeniden çizilir
Bitişmain bitince program bitermain bitse de pencere kapanana kadar çalışır
Kütüphanejava.util, java.iojava.awt, javax.swing, java.awt.event

Kural: GUI programında “sonra ne olacak?” sorusunun cevabı koddaki sıra değil, kullanıcının sıradaki eylemidir. Kodun büyük kısmı “şu olursa şunu yap” biçimindeki dinleyicilerden oluşur.

Grafik Programlama

AWT ve Swing

AWT (Abstract Window Toolkit), java.awt

Java'nın ilk grafik kütüphanesi. Bugün en çok ortak sınıfları için kullanılır: Graphics, Color, Font, Point, yerleşim yöneticileri ve olay sınıfları (java.awt.event).

Swing, javax.swing

AWT'nin üzerine kurulmuş, bileşenleri Java'nın kendisi çizen kütüphane. Sınıf adları J ile başlar: JFrame, JPanel, JButton, JLabel…

ComponentContainerWindowJComponentFrameJFrameJPanelJButtonJLabelJScrollPaneJTextComponentJTextFieldJTextAreajava.awtjavax.swing

İçi boş üçgen: “türetilmiştir” (kalıtım). JFrame bir AWT penceresidir; diğer Swing bileşenleri JComponent'ten türer (JButton arada AbstractButton üzerinden).

Grafik Programlama

Uygulama Adımları

  1. Java'nın grafik sınıfları kullanılarak arayüze bileşenler eklenir.
  2. Kullanıcının eylemlerine yanıt veren olay işleme metotları tanımlanır.
  3. paint() veya paintComponent() gibi metotlarla görsel oluşturulur.
x = 0x = getWidth()y = 0y = getHeight()(0, 0) sol üst köşex sağa, y AŞAĞI doğru artar

Ekran bir piksel ızgarasıdır. Koordinatlar tam sayıdır ve bileşenin sol üst köşesinden ölçülür. Matematikteki eksenin tersine, y aşağı doğru büyür: (0, 0) sol üst, (getWidth() − 1, getHeight() − 1) sağ alt pikseldir.

Grafik Programlama

Temel Grafik Kavramları

Tuval (canvas)

Üzerine resim çizilebilen yüzeydir. Swing'de genellikle JPanel (AWT'de Canvas) kullanılır: sınıfı JPanel'den türetir, çizimi onun içine yaparız.

Graphics sınıfı

Çizim işlemlerini yapan “kalem”dir. Metotları: drawLine(), drawRect(), fillOval(), drawString(), drawImage()…

Color ve Font

Kalemin rengini Color, yazı tipini Font belirler: g.setColor(Color.RED), g.setFont(new Font("Serif", Font.BOLD, 24)).

Kalem benzetmesi: Graphics nesnesi elinizdeki kalemdir. setColor kalemi değiştirir; değiştirene kadar bütün çizimler aynı renkle yapılır.

Grafik Programlama

paintComponent ile Çizim

import java.awt.*;
import javax.swing.*;

class CizimPaneli extends JPanel {
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);     // zemini temizle
        g.setColor(Color.BLUE);
        g.drawRect(20, 30, 50, 70);  // x, y, en, boy
        g.drawString("Merhaba, Java Grafik!", 100, 100);
    }
}
  • paintComponent'i biz çağırmayız: pencere ilk açıldığında, boyutu değiştiğinde veya repaint() istendiğinde Swing çağırır ve hazır bir Graphics g verir.
  • panel.getGraphics() ile de bir grafik nesnesi alınabilir, ama bununla yapılan çizim pencere bir sonraki kez yeniden çizildiğinde silinir. Kalıcı çizim için yol paintComponent'tir.
CizimPaneli
Merhaba, Java Grafik!

Panel 300 × 160 iken sonuç. drawString'in y değeri yazının taban çizgisidir (harflerin altı).

Grafik Programlama

Graphics Çizim Metotları

MetotNe yapar?
drawLine(x1, y1, x2, y2)İki nokta arasında çizgi
drawRect(x, y, en, boy)Dikdörtgen çerçevesi; (x, y) sol üst köşe
fillRect(x, y, en, boy)İçi dolu dikdörtgen
drawOval(x, y, en, boy)Bu dikdörtgene sığan elips (en = boy ise çember)
fillOval(x, y, en, boy)İçi dolu elips / daire
drawString(s, x, y)Metin; y taban çizgisi
setColor(c) / setFont(f)Sonraki çizimlerin rengi / yazı tipi
drawImage(resim, x, y, null)Bir resmi (x, y) noktasına çizer
(40, 40)genişlik 16090

Elips ve daireler sınırlayıcı dikdörtgenleri ile verilir: merkez değil, sol üst köşe. Merkezi (cx, cy), yarıçapı r olan daire: fillOval(cx − r, cy − r, 2r, 2r).

Grafik Programlama

Şekiller: Kod ve Sonuç

class SekillerPaneli extends JPanel {
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawLine(10, 10, 110, 60);
        g.drawRect(130, 10, 80, 50);
        g.fillRect(230, 10, 80, 50);
        g.drawOval(10, 80, 100, 60);
        g.fillOval(130, 80, 60, 60);
        g.drawString("Merhaba", 230, 115);
    }
}
SekillerPaneli
Merhaba

Renk verilmediğinde kalem, panelin ön plan rengi (Swing'de koyu gri) ile çizer. draw… çerçeve, fill… içi dolu şekil çizer.

Sırayla düşünün: çizimler üst üste boyanır; sonradan çizilen öncekini örter. Bu, birazdan göreceğimiz trafik işaretinin temel fikridir.

Pencere ve Panel

JFrame Sınıfı

Ekranda başlık çubuğu, simge durumuna küçültme ve kapatma düğmeleri olan üst düzey pencere (top-level window) oluşturur. Diğer bütün bileşenler bir pencerenin içinde yaşar.

KodGörevi
JFrame pencere = new JFrame("Başlık");Başlığı verilen pencereyi oluşturur (henüz görünmez)
pencere.add(bilesen);Pencereye (içerik bölmesine) bileşen ekler
pencere.setSize(400, 300);Genişlik ve yükseklik (piksel, kenarlıklar dahil)
pencere.pack();Boyutu içerikteki bileşenlerin tercih ettiği boyuta göre ayarlar
pencere.setLocation(x, y);Pencerenin ekrandaki konumu; setLocationRelativeTo(null) ortalar
pencere.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);Kapatılınca programı sonlandırır
pencere.setVisible(true);Pencereyi görünür yapar (genellikle en son çağrılır)

Pencere ve Panel

İlk Pencere

import javax.swing.JFrame;

public class JFrameOrnegi {
    public static void main(String[] args) {
        JFrame pencere = new JFrame("Java JFrame Örneği");
        pencere.setSize(400, 300);
        pencere.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pencere.setVisible(true);
    }
}
  • setVisible(true) unutulursa pencere oluşur ama görünmez.
  • EXIT_ON_CLOSE verilmezse varsayılan davranış HIDE_ON_CLOSE'dur: pencere gizlenir ama program arka planda çalışmaya devam eder.
  • Boyut verilmezse pencere 0 × 0'a yakın, yalnız başlık çubuğu kadar açılır.
Java JFrame Örneği

İçi boş, 400 × 300 boyutlu pencere (ölçekli).

Pencere ve Panel

JPanel Sınıfı

  • javax.swing paketinde bulunan bir konteynerdir (container): içinde başka GUI öğeleri barındırır.
  • Bir pencerenin içindeki bileşenleri gruplamak ve düzenlemek için kullanılır; birden fazla panel iç içe konarak karmaşık düzenler kurulur.
  • setBackground(), setBorder(), setPreferredSize() ile renk, kenarlık ve boyut özelleştirilir.
  • Kendi çizimimizi, animasyon ve grafikleri yaptığımız tuvaldir: JPanel'den türetip paintComponent'i geçersiz kılarız.
  • Kodu parçalara ayırmaya yarar: her panel ayrı bir sınıf olabilir.
JFramepencereiçerik bölmesigetContentPane()JPanelpanelJButtondüğmeJLabeletiketJPaneliç panel

Pencere ve Panel

JPanel Örneği

import java.awt.Color;
import javax.swing.*;

public class PanelOrnegi {
    public static void main(String[] args) {
        JPanel panel = new JPanel();
        panel.setBackground(Color.LIGHT_GRAY);
        panel.add(new JButton("Tıkla"));
        JFrame pencere = new JFrame("JPanel Örneği");
        pencere.add(panel);
        pencere.setSize(300, 150);
        pencere.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pencere.setVisible(true);
    }
}
JPanel Örneği
Tıkla

Color.LIGHT_GRAY = (192, 192, 192). Düğme panelin üst ortasında durur.

Neden üst ortada? JPanel'in varsayılan yerleşim yöneticisi FlowLayout'tur: bileşenleri tercih ettikleri boyutta, satır satır ve ortalı dizer. JFrame'in içerik bölmesi ise BorderLayout kullanır; bu yüzden panel bütün pencereyi kaplar.

Çizim Araçları · Kodu adım adım çalıştır

Point Sınıfı: (x, y) Noktası

(0, 0)(30, 40)

Point nesnesi oluşur; x ve y alanları public int'tir.

(0, 0)(30, 40)

getX() double döndürür: 30.0.

(0, 0)(30, 40)

getY(): 40.0.

(0, 0)(30, 40)

double değerler ondalıklı yazılır.

(0, 0)(30, 40)

Alanlara doğrudan erişim int verir.

(0, 0)(30, 40)

Orijine uzaklık: √(30² + 40²) = 50.0.

(0, 0)(60, 80)

setLocation noktayı yeni konuma taşır. Değişkenler eski değerleri saklar.

(0, 0)(60, 80)

toString() sınıf adını ve alanları yazar.

(0, 0)(65, 70)

translate(dx, dy) göreli kaydırır. y azaldı: nokta yukarı çıktı.

(0, 0)(65, 70)

Yeni konum yazılır.

(0, 0)(65, 70)

static distance(x1, y1, x2, y2): (0, 0) ile (3, 4) arası 5.0.

Point nokta = new Point(30, 40);
double xKoordinati = nokta.getX();
double yKoordinati = nokta.getY();
System.out.println(xKoordinati + " " + yKoordinati);
System.out.println(nokta.x + " " + nokta.y);
System.out.println(nokta.distance(0, 0));
nokta.setLocation(60, 80);
System.out.println(nokta);
nokta.translate(5, -10);   // 5 sağa, 10 yukarı
System.out.println(nokta);
System.out.println(Point.distance(0, 0, 3, 4));

Çizim Araçları

Color Sınıfı

  • Arayüzün ve çizimlerin renklendirilmesini sağlar (java.awt.Color).
  • Hazır sabitler: Color.RED, Color.GREEN, Color.WHITE, Color.LIGHT_GRAY…
  • RGB: kırmızı, yeşil, mavi bileşenleri 0–255 arası: new Color(int red, int green, int blue).
  • darker() bileşenleri 0,7 ile çarpar, brighter() 0,7'ye böler (en çok 255): yeni bir renk nesnesi döner.
Color turuncu = new Color(255, 128, 0);
System.out.println(turuncu);
System.out.println(turuncu.getGreen());
System.out.println(Color.RED.darker());
java.awt.Color[r=255,g=128,b=0]
128
java.awt.Color[r=178,g=0,b=0]
Color.RED (255, 0, 0)Color.BLUE (0, 0, 255)Color.LIGHT_GRAY (192, 192, 192)new Color(255, 128, 0) turuncuturuncu.darker() (178, 89, 0)Color.RED.darker() (178, 0, 0)Color.GREEN.darker() (0, 178, 0)new Color(100, 50, 0).brighter() (142, 71, 0)

Çizim Araçları

Font Sınıfı

Metnin yazı tipini, stilini ve boyutunu belirler: new Font(ad, stil, punto).

ParametreDeğerler
ad"Serif", "SansSerif", "Monospaced", "Dialog" (her sistemde bulunan mantıksal adlar) veya "Arial" gibi gerçek bir yazı tipi
stilFont.PLAIN (0), Font.BOLD (1), Font.ITALIC (2), ikisi birden: Font.BOLD | Font.ITALIC
puntoTam sayı boyut, ör. 24
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(new Color(0, 102, 204));
    g.setFont(new Font("Serif", Font.BOLD, 24));
    g.drawString("Java", 20, 40);
    g.setFont(new Font("Monospaced", Font.PLAIN, 14));
    g.drawString("Grafik", 20, 70);
}
YaziPaneli
JavaGrafik

JLabel gibi bileşenlerde de aynı nesne kullanılır: etiket.setFont(f). Mevcut bir yazı tipinden türetmek için: f.deriveFont(Font.ITALIC, 18f).

Yerleşim Yöneticileri

Yerleşim Yöneticisi

Yerleşim yöneticisi (layout manager), bir konteynerin içindeki bileşenlerin boyutunu ve konumunu kurallara göre hesaplayan nesnedir: panel.setLayout(new GridLayout(2, 3));. Koordinatları elle vermek yerine kullanılır, çünkü pencere büyüyünce, yazı tipi veya ekran çözünürlüğü değişince düzen kendiliğinden yeniden hesaplanır.

FlowLayout1234

Soldan sağa, satır dolunca alta. JPanel varsayılanı.

BorderLayoutNSWECENTER

Beş bölge. JFrame içerik bölmesi varsayılanı.

GridLayout123456

Eşit boyutlu hücrelerden ızgara: new GridLayout(2, 3).

BoxLayout123

Tek satır veya tek sütun: BoxLayout.Y_AXIS.

Daha esnek ama karmaşık olan GridBagLayout, farklı boyutlarda hücrelerden oluşan bir ızgara kurar. Panelleri iç içe koyup her birine basit bir yönetici vermek çoğu zaman yeterlidir.

Yerleşim Yöneticileri

BorderLayout Sınıfı

  • Bileşenleri beş bölgeye yerleştirir: NORTH, SOUTH, WEST, EAST, CENTER.
  • Önceliği farklı bileşenleri düzenli göstermeye yarar: araç çubuğu üstte, durum satırı altta, asıl içerik ortada.
  • Bölge belirtilmeden eklenen bileşen merkeze yerleşir: add(b) = add(b, BorderLayout.CENTER).
  • Her bölgede tek bileşen olur; aynı bölgeye ikinci ekleme öncekinin yerini alır.
  • Kuzey ve güney tüm genişliği, batı ve doğu kalan yüksekliği alır; merkez geriye kalan her şeyi doldurur.
  • setHgap() ve setVgap() bölgeler arasındaki yatay ve dikey boşluğu (piksel) ayarlar.
NORTH (kuzey)SOUTH (güney)WEST(batı)EAST(doğu)CENTER(merkez, kalan alan)

Yerleşim Yöneticileri · Kodu adım adım çalıştır

BorderLayout: Bölgeleri Doldurma

BorderLayout
CENTER boş

Panel BorderLayout kullanacak; bölgeler arasında 5 piksel boşluk var. Henüz bileşen yok.

BorderLayout
KuzeyCENTER boş

Kuzey düğmesi tüm genişliği alır, yüksekliği düğmenin tercih ettiği kadardır.

BorderLayout
KuzeyGüneyCENTER boş

Güney de tüm genişlikte, en alta yerleşir.

BorderLayout
KuzeyGüneyBatıCENTER boş

Batı, kuzey ile güney arasında kalan yüksekliği alır; genişliği metne göre.

BorderLayout
KuzeyGüneyBatıDoğuCENTER boş

Doğu sağ kenara yerleşir.

BorderLayout
KuzeyGüneyBatıDoğuMerkez

Merkez geriye kalan bütün alanı doldurur. Pencere büyütülürse en çok merkez büyür.

JPanel panel = new JPanel();
BorderLayout yerlesim = new BorderLayout();
yerlesim.setHgap(5);
yerlesim.setVgap(5);
panel.setLayout(yerlesim);
panel.add(new JButton("Kuzey"), BorderLayout.NORTH);
panel.add(new JButton("Güney"), BorderLayout.SOUTH);
panel.add(new JButton("Batı"), BorderLayout.WEST);
panel.add(new JButton("Doğu"), BorderLayout.EAST);
panel.add(new JButton("Merkez"), BorderLayout.CENTER);

Giriş Yasak İşareti

Giriş Yasak İşareti

Hedef: trafikteki “girişi olmayan yol” işaretini çizen bir panel. Şekil üst üste boyanan dört katmandan oluşur:

  1. Yeşil arka plan (setBackground)
  2. Beyaz büyük daire (dış halka)
  3. Kırmızı, biraz küçük daire
  4. Ortada beyaz yatay bar

Bütün ölçüler getWidth() ve getHeight()'tan hesaplanır: pencere büyütülünce işaret de büyür ve hep ortada kalır.

Basit bir grafik programı

Giriş Yasak İşareti

paintComponent Kodu

public class GirisYasaktirIsareti extends JPanel {
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        var c = new Point(getWidth() / 2, getHeight() / 2); // merkez
        var r = Math.min(getWidth() / 2, getHeight() / 2) - 5; // yarıçap
        var r2 = (int) (r * 0.9);   // iç yarıçap
        var bw = (int) (r2 * 1.4);  // bar genişliği
        var bh = (int) (r2 * 0.35); // bar yüksekliği
        g.setColor(Color.WHITE);
        g.fillOval(c.x - r, c.y - r, 2 * r, 2 * r);
        g.setColor(Color.RED);
        g.fillOval(c.x - r2, c.y - r2, r2 * 2, r2 * 2);
        g.setColor(Color.WHITE);
        g.fillRect(c.x - bw / 2, c.y - bh / 2, bw, bh);
    }
}

var (Java 10+): türü derleyici sağdaki ifadeden çıkarır; burada c bir Point, diğerleri int. Klasik yazım: Point c = new Point(…); int r = …;. (int) dönüşümü ondalık kısmı atar. Gerekli içe aktarmalar: java.awt.* ve javax.swing.*.

Giriş Yasak İşareti · Kodu adım adım çalıştır

İşareti Çizme: paintComponent İzleme

Panel 384 × 261 piksel. super.paintComponent zemini arka plan rengiyle (yeşil) boyar.

Merkez: (384 / 2, 261 / 2) = (192, 130). Tam sayı bölmesi: 130,5 → 130.

Yarıçap: min(192, 130) − 5 = 125. Kısa kenara göre seçilir, 5 piksel pay kalır.

İç yarıçap: (int) 112,5 = 112.

Bar genişliği: (int) (112 × 1,4) = (int) 156,8 = 156.

Bar yüksekliği: (int) 39,2 = 39.

fillOval(67, 5, 250, 250): beyaz daire, sınırlayıcı kare kesikli çizgide.

fillOval(80, 18, 224, 224): kırmızı daire beyazın üstüne boyanır; 13 piksellik beyaz halka kalır.

fillRect(114, 111, 156, 39): beyaz bar en üste. İşaret tamam.

super.paintComponent(g);
var c = new Point(getWidth() / 2, getHeight() / 2);
var r = Math.min(getWidth() / 2, getHeight() / 2) - 5;
var r2 = (int) (r * 0.9);
var bw = (int) (r2 * 1.4);
var bh = (int) (r2 * 0.35);
g.setColor(Color.WHITE);
g.fillOval(c.x - r, c.y - r, 2 * r, 2 * r);
g.setColor(Color.RED);
g.fillOval(c.x - r2, c.y - r2, r2 * 2, r2 * 2);
g.setColor(Color.WHITE);
g.fillRect(c.x - bw / 2, c.y - bh / 2, bw, bh);

Giriş Yasak İşareti

main ve Pencere

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
        var panel = new GirisYasaktirIsareti();
        panel.setBackground(Color.GREEN.darker());
        var frame = new JFrame("Basit bir grafik programı");
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(panel, BorderLayout.CENTER);
        frame.setVisible(true);
    });
}
  • SwingUtilities.invokeLater(() -> { … }): arayüzü olay iş parçacığında kurar (birazdan).
  • () -> { … } bir lambda ifadesidir (Java 8+): “sonra çalıştırılacak kod parçası”.
  • Color.GREEN.darker() = (0, 178, 0): saf yeşilden biraz koyu.
  • Panel, pencerenin içerik bölmesinin merkezine eklenir; tek bileşen olduğu için tüm alanı kaplar.
  • 400 × 300 pencerede kenarlık ve başlık çubuğu düşülünce panel yaklaşık 384 × 261 olur (işletim sistemine göre değişir).

Fare Olayları

Etkileşimli Bilgisayar Grafikleri

  • Bilgisayar grafikleri, görsel içerik oluşturma ve işleme sürecidir. Etkileşimli (interactive) grafiklerde kullanıcı fare, klavye gibi giriş aygıtlarıyla görüntüyü değiştirir: çizim programları, oyunlar, haritalar.
  • Grafik kütüphaneleri şekil çizmeyi, renklendirmeyi ve grafik nesnelerini değiştirmeyi sağlar; etkileşim ise aşağıdaki olay döngüsü ile gerçekleşir.
Kullanıcıfare, klavyeİşletim sistemigiriş aygıtı sinyaliOlay kuyruğuMouseEvent, KeyEvent…Olay iş parçacığı(EDT) sıradaki olayı alırDinleyici metotmousePressed(e)…repaint()yeniden çizim isteğipaintComponent(g)Swing çağırırEkrangüncel görüntüsıradaki olay

Dinleyici metot ekranı doğrudan boyamaz: veriyi günceller ve repaint() ile yeniden çizim ister. Swing uygun anda paintComponent'i çağırır.

Fare Olayları

Dinleyici Arayüzü ve Adaptör

Arayüz: beş metodun hepsi yazılmalı

class Dinleyici implements MouseListener {
    public void mouseClicked(MouseEvent e) {
        System.out.println("tık");
    }
    public void mousePressed(MouseEvent e) { }
    public void mouseReleased(MouseEvent e) { }
    public void mouseEntered(MouseEvent e) { }
    public void mouseExited(MouseEvent e) { }
}

MouseAdapter: yalnız gerekeni geçersiz kıl

class Dinleyici extends MouseAdapter {
    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("tık");
    }
}
// panel.addMouseListener(new Dinleyici());
  • MouseAdapter, MouseListener (ve MouseMotionListener, MouseWheelListener) arayüzünü boş gövdelerle uygulayan hazır bir sınıftır. Ondan türeyen sınıf yalnızca ilgilendiği metodu yazar.
  • Hareket olayları ayrı bir arayüzdedir: MouseMotionListener (mouseDragged, mouseMoved); adaptörü MouseMotionAdapter. Kayıt: addMouseListener(…), addMouseMotionListener(…).
  • new MouseAdapter() { … } biçimi bir anonim iç sınıftır (anonymous inner class): adı olmayan, tek kullanımlık bir alt sınıf.

Fare Olayları

Fare Olay Metotları

MetotArayüzNe zaman çağrılır?
mousePressed(e)MouseListenerFare düğmesine basıldığı an
mouseReleased(e)MouseListenerDüğme bırakıldığında
mouseClicked(e)MouseListenerBasıp aynı yerde bırakınca (pressed → released → clicked)
mouseEntered(e) / mouseExited(e)MouseListenerİşaretçi bileşenin içine girince / dışına çıkınca
mouseMoved(e)MouseMotionListenerDüğmeye basmadan hareket edince
mouseDragged(e)MouseMotionListenerDüğme basılıyken hareket edince (sürükleme)
mouseWheelMoved(e)MouseWheelListenerTekerlek döndürülünce

Her metot bir MouseEvent e parametresi alır: olayın nerede, hangi düğmeyle, hangi tuşlar basılıyken olduğu bu nesnededir.

Fare Olayları

MouseEvent Sınıfı

MetotDöndürdüğü
getX(), getY()İşaretçinin bileşene göre konumu
getPoint()Aynı konum, Point olarak
getButton()BUTTON1 sol, BUTTON2 orta, BUTTON3 sağ
getClickCount()Art arda tıklama sayısı (2: çift tık)
isShiftDown(), isCtrlDown(), isAltDown()O anda tuş basılı mı?
panel.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        String dugme = "sol";
        if (e.getButton() == MouseEvent.BUTTON3) {
            dugme = "sağ";
        }
        System.out.println(dugme + " (" + e.getX()
                + ", " + e.getY() + ")"
                + (e.isShiftDown() ? " + Shift" : ""));
    }
});

Fare olayı sonrasında oluşan durumu temsil eder. Koordinatlar ekrana değil bileşene göredir: panelin sol üst köşesi (0, 0).

Fare Olayları

Deneyin: Fare Olayları

Fare Olayları
Panelin içinde tıklayın, sürükleyin; Shift veya Ctrl basılı deneyin.

Java çağrısı ve MouseEvent değerleri

(henüz olay yok)

Tarayıcı olayları Java'daki karşılıklarıyla gösterilir. Tıklamanın pressed → released → clicked sırasıyla üç olay ürettiğine, sürüklerken çok sayıda mouseDragged geldiğine dikkat edin. Sağ tık BUTTON3'tür.

Fare Olayları

SwingUtilities ve Olay İş Parçacığı

  • javax.swing.SwingUtilities yardımcı metotlar içerir.
  • Swing bileşenleri iş parçacığı güvenli değildir (not thread-safe): aynı anda birden çok iş parçacığı dokunursa tutarsızlık olabilir.
  • Kural: bileşenler yalnızca olay iş parçacığından (Event Dispatch Thread, EDT) kurulur ve değiştirilir. Dinleyici metotlar zaten EDT'de çalışır.
  • Benzetme: mutfakta tek bir aşçı (EDT) vardır; diğerleri yemeği kendileri yapmaz, sipariş fişi (Runnable) bırakır.
main iş parçacığımain biterinvokeLater(iş)olay kuyruğuişfaretuşboyaolay iş parçacığı (EDT)sırayla tek tek çalıştırırpencere kapanana kadar sürer
MetotDavranış
invokeLater(iş)İşi kuyruğa koyar ve hemen döner (asenkron). GUI başlatmanın standart yolu.
invokeAndWait(iş)İş EDT'de bitene kadar bekler (senkron). EDT'nin içinden çağrılırsa Error fırlatır (EDT kendini bekleyemez).

Çizim Programı

Basit Çizim Programı

Basit Çizim Programı
egriler.size() = 0, toplam nokta = 0

Fareyle basılı tutup sürükleyerek çizim yapılan program. Panelin içinde deneyin.

  • Basınca (mousePressed) yeni bir eğri başlar.
  • Sürükledikçe (mouseDragged) eğrinin sonuna nokta eklenir ve repaint istenir.
  • Çizerken (paintComponent) her eğrinin ardışık noktaları çizgilerle birleştirilir.

Program çizimi bir resim olarak değil, noktaların listesi olarak saklar; ekran her seferinde bu veriden yeniden çizilir.

Çizim Programı

Eğrileri Saklamak

public class BasitCizimPaneli extends JPanel {
    private List<List<Point>> egriler = new ArrayList<>();

    public BasitCizimPaneli() {
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                var yeniEgri = new ArrayList<Point>();
                yeniEgri.add(new Point(e.getX(), e.getY()));
                egriler.add(yeniEgri);
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                egriler.get(egriler.size() - 1)
                       .add(new Point(e.getX(), e.getY()));
                repaint(0, 0, getWidth(), getHeight());
            }
        });
    }
}
eğri 0:(40,120)(60,60)(80,120)eğri 1:(50,95)(70,95)
  • List<List<Point>>: listelerin listesi. Dış liste eğrileri, her iç liste bir eğrinin noktalarını tutar.
  • Son eğri: egriler.get(egriler.size() - 1). Son eleman indeksi size() - 1'dir; get(size()) IndexOutOfBoundsException fırlatır.

Çizim Programı · Kodu adım adım çalıştır

Fare Olaylarını İzleme

eğri 0:(40,120)

mousePressed: Basıldı (40, 120): yeni bir iç liste oluşur, ilk noktası eklenir, dış listeye konur.

eğri 0:(40,120)(60,60)

mouseDragged: Sürüklendi (60, 60): son eğriye nokta eklenir; repaint yeniden çizimi ister, çizgi görünür.

eğri 0:(40,120)(60,60)(80,120)

mouseDragged: Sürüklendi (80, 120): aynı eğri uzar. Gerçekte saniyede onlarca mouseDragged gelir.

eğri 0:(40,120)(60,60)(80,120)

mouseReleased: Bırakıldı: mouseReleased'ı yazmadık; MouseAdapter'ın boş gövdesi çalışır, hiçbir şey olmaz.

eğri 0:(40,120)(60,60)(80,120)eğri 1:(50,95)

mousePressed: Yeniden basıldı (50, 95): ikinci eğri başlar. Eski eğri olduğu gibi kalır.

eğri 0:(40,120)(60,60)(80,120)eğri 1:(50,95)(70,95)

mouseDragged: Sürüklendi (70, 95): ekleme yine son eğriye, yani eğri 1'e yapılır.

addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        var yeniEgri = new ArrayList<Point>();
        yeniEgri.add(new Point(e.getX(), e.getY()));
        egriler.add(yeniEgri);
    }
});
addMouseMotionListener(new MouseMotionAdapter() {
    @Override
    public void mouseDragged(MouseEvent e) {
        egriler.get(egriler.size() - 1)
               .add(new Point(e.getX(), e.getY()));
        repaint(0, 0, getWidth(), getHeight());
    }
});

Çizim Programı · Kodu adım adım çalıştır

Eğrileri Çizmek: paintComponent

Zemin temizlenir; önceki çizimden iz kalmaz.

İlk eğri; onceki onun ilk noktası.

İç döngü ilk noktadan başlar: kendisiyle birleşir, tek piksel çizilir. Ardından onceki = nokta.

(40,120) → (60,60) çizgisi.

(60,60) → (80,120). Eğri 0 bitti.

Dış döngü ikinci eğriye geçer; onceki yeniden onun ilk noktası olur. Böylece iki eğri birleşmez.

Yine tek piksel.

(50,95) → (70,95). Beş drawLine çağrısıyla çizim tamam.

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    for (var egri : egriler) {
        var onceki = egri.get(0);
        for (var nokta : egri) {
            g.drawLine(onceki.x, onceki.y, nokta.x, nokta.y);
            onceki = nokta;
        }
    }
}

Çizim Programı

main ve repaint

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
        var frame = new JFrame("Basit Çizim Programı");
        frame.getContentPane().add(new BasitCizimPaneli(),
                BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setVisible(true);
    });
}
  • repaint() çizimi hemen yapmaz: kuyruğa bir “yeniden boya” isteği koyar. Art arda gelen istekler birleştirilebilir.
  • repaint(x, y, en, boy) yalnızca o dikdörtgenin yeniden çizilmesini ister. Swing bunun dışını kırpar (clipping): g o bölgenin dışına boyamaz, iş azalır. repaint(0, 0, getWidth(), getHeight()) = repaint().
  • super.paintComponent(g) unutulursa zemin temizlenmez; eski görüntü artıkları kalabilir.
  • paintComponent'i kendimiz çağırmayız; veriyi değiştirip repaint() isteriz.

Metin Bileşenleri

JButton Sınıfı

  • Tıklanabilir düğmeler oluşturur; metin, ikon ve olay işleyicilerle özelleştirilir.
  • setText() metni, setIcon() ikonu belirler; setEnabled(false) pasif yapar.
  • addActionListener() tıklanınca çalışacak dinleyiciyi ekler (ActionListener, tek metodu actionPerformed).
class SayacPaneli extends JPanel {
    private int sayac = 0;
    private JLabel etiket = new JLabel("Henüz tıklanmadı");

    SayacPaneli() {
        JButton dugme = new JButton("Tıkla");
        dugme.addActionListener(e -> {
            sayac++;
            etiket.setText(sayac + " kez tıklandı");
        });
        add(dugme);
        add(etiket);
    }
}
Sayaç
Henüz tıklanmadı
Düğmeye tıklayın.

Metin Bileşenleri

ActionListener: Anonim Sınıf ve Lambda

Anonim iç sınıf (klasik)

dugme.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        sayac++;
        etiket.setText("Sayı: " + sayac);
    }
});

Lambda ifadesi (Java 8+)

dugme.addActionListener(e -> {
    sayac++;
    etiket.setText("Sayı: " + sayac);
});

// tek ifade ise süslü parantez gerekmez:
dugme.addActionListener(e -> System.exit(0));
  • ActionListener yalnızca tek soyut metodu olan bir arayüzdür (fonksiyonel arayüz). Bu yüzden derleyici e -> … lambdasını actionPerformed'ın gövdesi olarak kabul eder.
  • MouseListener'ın beş metodu olduğu için lambda ile yazılamaz; orada adaptör sınıfı kullanılır.
  • Lambda içinden yerel değişken değiştirilemez: int sayac = 0; … e -> sayac++ derlenmez. Sayaç gibi değişen değerler alan (field) olmalıdır.

Metin Bileşenleri

JLabel ve JTextField

JLabel: etiket

Metin veya resim gösterir; kullanıcı değiştiremez.

setText() metni, setIcon() resmi, setFont() yazı tipini, setForeground() metin rengini belirler.

JTextField: tek satırlık metin alanı

Kullanıcının metin girmesi için; formlardan veri toplanır.

getText() / setText() okur ve yazar, setColumns() görünen sütun sayısını belirler, addActionListener() Enter'a basılınca çalışır.

JLabel etiket = new JLabel("Adınız:");
etiket.setFont(new Font("SansSerif", Font.BOLD, 14));
etiket.setForeground(Color.BLUE);
JTextField adAlani = new JTextField(12);
JLabel selam = new JLabel(" ");
adAlani.addActionListener(e -> selam.setText(
        "Merhaba, " + adAlani.getText() + "!"));
Selam
Adınız: 
Adınızı yazıp Enter'a basın.

Metin Bileşenleri

JTextArea ve JScrollPane

JTextArea: çok satırlı metin

İçerik okunabilir, atanabilir, güncellenebilir. new JTextArea(satır, sütun) ile görünür boyut önceden verilir. getText(), setText(), append() (sona ekle), setEditable(false) (salt okunur), setLineWrap(true) (satır kaydır).

JScrollPane: kaydırma bölmesi

İçine konan bileşen (metin alanı, tablo, resim) ekrana sığmadığında otomatik kaydırma çubukları ekler; içerik boyutu değişince kendini uyarlar. setPreferredSize() ile boyutu, setViewportView() ile içeriği değiştirilir.

JTextArea alan = new JTextArea(5, 20);
alan.setText("Birinci satır\n");
alan.append("İkinci satır\n");
JScrollPane kaydirma = new JScrollPane(alan);
System.out.print(alan.getText());
System.out.println(alan.getLineCount());
Birinci satır
İkinci satır
3
JScrollPane
Birinci satır İkinci satır Üçüncü satır Dördüncü satır Beşinci satır Altıncı satır

Harf Çevirici

Metin Dönüştürücü: Pencere

BuyukHarfeCevirici
Metni değiştirip düğmeleri deneyin.
  • Ortada (CENTER) bir JScrollPane içinde 8 satır × 50 sütunluk JTextArea.
  • Altta (SOUTH) iki düğmeyi taşıyan bir JPanel (FlowLayout: ortalı).
  • pack() pencere boyutunu bu bileşenlerin tercih ettiği boyuttan hesaplar.
  • Düğmeler metni toLowerCase() / toUpperCase() ile dönüştürüp alana geri yazar.

Not: toUpperCase() bilgisayarın yerel ayarını (locale) kullanır. İngilizce ayarlı bir makinede "istanbul" → "ISTANBUL", Türkçe ayarlıda "İSTANBUL" olur. Sonucu sabitlemek için: toUpperCase(Locale.forLanguageTag("tr")). Bu demo Türkçe kuralları kullanır.

Harf Çevirici

Metin Dönüştürücü: Kod

import java.awt.BorderLayout;
import javax.swing.*;

public class BuyukHarfeCevirici {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            var alan = new JTextArea("Java Programlama", 8, 50);
            var kucukHarfButton = new JButton("Küçük Harfe Çevir");
            var buyukHarfButton = new JButton("Büyük Harfe Çevir");
            kucukHarfButton.addActionListener(e ->
                    alan.setText(alan.getText().toLowerCase()));
            buyukHarfButton.addActionListener(e ->
                    alan.setText(alan.getText().toUpperCase()));
            var panel = new JPanel();
            panel.add(kucukHarfButton);
            panel.add(buyukHarfButton);
            var frame = new JFrame("BuyukHarfeCevirici");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(new JScrollPane(alan),
                    BorderLayout.CENTER);
            frame.getContentPane().add(panel, BorderLayout.SOUTH);
            frame.pack();
            frame.setVisible(true);
        });
    }
}
  • Tüm arayüz tek bir lambda içinde, EDT'de kurulur.
  • alan yerel bir değişkendir ama lambda içinde yalnızca okunduğu (değiştirilmediği) için kullanılabilir (effectively final).
  • toUpperCase() yeni bir String döndürür; String değişmez olduğu için sonucu setText ile geri yazmak gerekir.
  • BorderLayout.CENTER tam adıyla yazılır; yalnız CENTER derlenmez.

Harf Çevirici

Bir Tıklamada Neler Olur?

Kullanıcı tıklarBüyük Harfe ÇevirOlay kuyruğuActionEvent beklerEDTJButton olayı alırLambda: getText()"Java Programlama"toUpperCase()yeni StringsetText + repaintekran güncelleniralan: Java Programlama

Kullanıcı “Büyük Harfe Çevir” düğmesine tıklar; işletim sistemi bunu Java'ya iletir.

Kullanıcı tıklarBüyük Harfe ÇevirOlay kuyruğuActionEvent beklerEDTJButton olayı alırLambda: getText()"Java Programlama"toUpperCase()yeni StringsetText + repaintekran güncelleniralan: Java Programlama

Java bir olay nesnesi oluşturup olay kuyruğuna koyar.

Kullanıcı tıklarBüyük Harfe ÇevirOlay kuyruğuActionEvent beklerEDTJButton olayı alırLambda: getText()"Java Programlama"toUpperCase()yeni StringsetText + repaintekran güncelleniralan: Java Programlama

EDT sıradaki olayı alır; düğme, kayıtlı tüm ActionListener'ların actionPerformed'ını çağırır: bizim lambdamız çalışır.

Kullanıcı tıklarBüyük Harfe ÇevirOlay kuyruğuActionEvent beklerEDTJButton olayı alırLambda: getText()"Java Programlama"toUpperCase()yeni StringsetText + repaintekran güncelleniralan: Java Programlama

alan.getText() mevcut metni okur.

Kullanıcı tıklarBüyük Harfe ÇevirOlay kuyruğuActionEvent beklerEDTJButton olayı alırLambda: getText()"Java Programlama"toUpperCase()yeni StringsetText + repaintekran güncelleniralan: Java Programlama

toUpperCase() yeni bir dizgi üretir; eski dizgi değişmez.

Kullanıcı tıklarBüyük Harfe ÇevirOlay kuyruğuActionEvent beklerEDTJButton olayı alırLambda: getText()"Java Programlama"toUpperCase()yeni StringsetText + repaintekran güncelleniralan: JAVA PROGRAMLAMA

setText alanın modelini günceller; alan kendini repaint ile yeniden çizdirir. EDT sıradaki olaya geçer.

Para Üstü Uygulaması

Para Üstü Hesaplama

Para Üstü Hesaplama
Miktar:
Olay sayısı: 0

Girilen kuruş miktarının en az sayıda madeni parayla (50, 25, 10, 5, 1) nasıl ödeneceğini gösterir.

  • Düğme yoktur: rapor her tuş vuruşunda kendiliğinden güncellenir.
  • Bunu metin alanının belgesine (Document) eklenen bir DocumentListener sağlar.
  • Deneyin: 93, 287, boş alan, abc, -7.

Para Üstü Uygulaması

Alanlar ve Yapıcı

public class ParaUstuHesaplama extends JFrame {
    private JTextField miktarAlani = new JTextField(12);
    private Document metin = miktarAlani.getDocument();
    private JTextArea rapor = new JTextArea(8, 40);

    public ParaUstuHesaplama() {
        var ustPanel = new JPanel();
        ustPanel.add(new JLabel("Miktar:"));
        ustPanel.add(miktarAlani);
        getContentPane().add(ustPanel, BorderLayout.NORTH);
        getContentPane().add(new JScrollPane(rapor),
                BorderLayout.CENTER);
        setBackground(Color.LIGHT_GRAY);
        rapor.setEditable(false);
        metin.addDocumentListener(new DocumentListener() {
            public void insertUpdate(DocumentEvent e) { raporuGuncelle(); }
            public void removeUpdate(DocumentEvent e) { raporuGuncelle(); }
            public void changedUpdate(DocumentEvent e) { raporuGuncelle(); }
        });
    }
  • Sınıf JFrame'den türer. Swing'de veri ile görünüm ayrıdır (MVC): JTextField görünüm, getDocument() ile alınan Document metni tutan model.
  • DocumentListener: insertUpdate (eklendi), removeUpdate (silindi), changedUpdate (stil değişti; düz metinde çağrılmaz). Arayüz olduğu için üçü de yazılır.

Para Üstü Uygulaması · Kodu adım adım çalıştır

raporuGuncelle: 93 kuruş

50kuruş–25kuruş–10kuruş–5kuruş–1kuruş–kalan miktar: 93

Alandaki metin "93" okunur ve tam sayıya çevrilir.

50kuruş–25kuruş–10kuruş–5kuruş–1kuruş–kalan miktar: 93

Para değerleri büyükten küçüğe bir dizide.

50kuruş–25kuruş–10kuruş–5kuruş–1kuruş–kalan miktar: 93

setText raporu sıfırdan başlatır: eski içerik silinir.

50kuruş× 125kuruş–10kuruş–5kuruş–1kuruş–kalan miktar: 93

x = 50: 93 / 50 = 1 adet (tam sayı bölmesi), satır sona eklenir.

50kuruş× 125kuruş–10kuruş–5kuruş–1kuruş–kalan miktar: 43

Kalan: 93 % 50 = 43.

50kuruş× 125kuruş× 110kuruş–5kuruş–1kuruş–kalan miktar: 43

x = 25: 43 / 25 = 1 adet (tam sayı bölmesi), satır sona eklenir.

50kuruş× 125kuruş× 110kuruş–5kuruş–1kuruş–kalan miktar: 18

Kalan: 43 % 25 = 18.

50kuruş× 125kuruş× 110kuruş× 15kuruş–1kuruş–kalan miktar: 18

x = 10: 18 / 10 = 1 adet (tam sayı bölmesi), satır sona eklenir.

50kuruş× 125kuruş× 110kuruş× 15kuruş–1kuruş–kalan miktar: 8

Kalan: 18 % 10 = 8.

50kuruş× 125kuruş× 110kuruş× 15kuruş× 11kuruş–kalan miktar: 8

x = 5: 8 / 5 = 1 adet (tam sayı bölmesi), satır sona eklenir.

50kuruş× 125kuruş× 110kuruş× 15kuruş× 11kuruş–kalan miktar: 3

Kalan: 8 % 5 = 3.

50kuruş× 125kuruş× 110kuruş× 15kuruş× 11kuruş× 3kalan miktar: 3

x = 1: 3 / 1 = 3 adet (tam sayı bölmesi), satır sona eklenir.

50kuruş× 125kuruş× 110kuruş× 15kuruş× 11kuruş× 3kalan miktar: 0

Kalan: 3 % 1 = 0.

void raporuGuncelle() {
    try {
        var miktar = Integer.parseInt(
                metin.getText(0, metin.getLength()));
        int[] dizi = {50, 25, 10, 5, 1};
        rapor.setText(miktar
                + " kuruş yapmak için kullanılacaklar:\n");
        for (int x : dizi) {
            rapor.append(miktar / x + " " + x + " kuruş\n");
            miktar %= x;
        }
    } catch (NumberFormatException e) {
        rapor.setText("Tam sayı değil veya aralık dışında");
    } catch (Exception e) {
        rapor.setText(e.toString());
    }
}

Para Üstü Uygulaması

main ve Olayların Sırası

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
        var frame = new ParaUstuHesaplama();
        frame.setTitle("Para Üstü Hesaplama");
        frame.pack();
        frame.setDefaultCloseOperation(
                JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    });
}
Kullanıcı / kodOlay → rapor
9 yazarinsertUpdate → 9 kuruş: 1 × 5, 4 × 1
3 yazarinsertUpdate → 93 kuruş raporu
Hepsini silerremoveUpdate → parseInt(""): “Tam sayı değil…”
abc veya 99999999999NumberFormatException → aynı mesaj
setText("287")iki olay: önce removeUpdate, sonra insertUpdate → 5, 1, 1, 0, 2
-7Geçerli sayı! 0, 0, 0, −1, −2: kontrol eksik

İlk catch beklenen hatayı (sayı olmayan metin, int sınırını aşan değer) yakalar. İkinci catch diğer her şey için genel güvencedir; getText(0, n) işaretli (checked) BadLocationException fırlatabildiği için gereklidir.

Özet

İyi Uygulamalar

Yerleşim yöneticisi kullanın

Koordinatları elle vermeyin; farklı ekran boyutu ve çözünürlükte düzen bozulmaz.

Anlamlı adlar verin

b1, t2 yerine buyukHarfButton, miktarAlani: onlarca bileşenli kod okunur kalır.

Olay güdümlü düşünün

“Kullanıcı şunu yapınca ne olmalı?” sorusuyla tasarlayın; her eylem için bir dinleyici.

Arayüz ile iş mantığını ayırın

Para üstü hesabı gibi kuralları ayrı bir metotta veya sınıfta tutun; arayüzsüz test edilebilir, başka arayüzde de kullanılır.

Arayüzü EDT'de kurun

main'in içi: SwingUtilities.invokeLater(() -> { … }).

EDT'yi meşgul etmeyin

Dinleyicide uzun bir iş (dosya indirme, büyük hesap) yapılırsa pencere donar; bu işler ayrı iş parçacığına taşınır (Bölüm 9).

Özet

Özet

KavramÖzü
Paketlerjava.awt: Graphics, Color, Font, Point, yerleşim, olaylar · javax.swing: J… bileşenleri
JFramePencere: setSize/pack, setDefaultCloseOperation(EXIT_ON_CLOSE), en son setVisible(true)
JPanelKonteyner ve tuval; varsayılan FlowLayout
ÇizimpaintComponent(Graphics g) geçersiz kılınır, önce super.paintComponent(g); değişince repaint()
Koordinat(0, 0) sol üst; x sağa, y aşağı; ovaller sınırlayıcı dikdörtgenle verilir
YerleşimBorderLayout (5 bölge, içerik bölmesi varsayılanı), FlowLayout, GridLayout, BoxLayout
OlaylarDinleyici arayüzü + add…Listener; çok metotlu arayüzler için adaptör; tek metotlu için lambda
FareMouseListener, MouseMotionListener; MouseEvent: getX, getY, getButton
EDTSwing tek iş parçacıklıdır; invokeLater asenkron, invokeAndWait senkron
MetinJLabel gösterir, JTextField tek satır, JTextArea çok satır, JScrollPane kaydırır

Özet

Sık Yapılan Hatalar

İçe aktarmayı unutmak

JFrame için import javax.swing.*; yoksa: cannot find symbol … class JFrame.

setVisible(true) ya da EXIT_ON_CLOSE yok

Pencere hiç görünmez veya kapatılınca program arka planda çalışmaya devam eder.

Metot adını yanlış yazmak

paintcomponent yeni bir metottur, hiç çağrılmaz. @Override ile: method does not override or implement a method from a supertype.

super.paintComponent(g) unutmak

Zemin temizlenmez; eski çizim artıkları ekranda kalır.

Arayüzün tüm metotlarını yazmamak

Dinleyici is not abstract and does not override abstract method mouseExited(MouseEvent) in MouseListener. Çözüm: MouseAdapter.

Son eleman için get(size())

IndexOutOfBoundsException: Index 1 out of bounds for length 1. Son eleman size() - 1.

Lambda içinde yerel değişken değiştirmek

e -> sayac++: local variables referenced from a lambda expression must be final or effectively final. Alan kullanın.

Sabiti sınıf adı olmadan yazmak

add(bilesen, CENTER): cannot find symbol … variable CENTER. BorderLayout.CENTER yazın.

Özet

Örnek Problemler

  1. Giriş yasak işareti paneli 200 × 100 piksel olsaydı r, r2, bw, bh kaç olurdu?
  2. Para üstü programına 68 yazılınca rapor ne olur?
  3. g.drawOval(50, 50, 100, 60) ile çizilen elipsin merkezi neresidir?
  4. BorderLayout kullanan bir panele önce A, sonra B düğmesi aynı NORTH bölgesine eklenirse kuzeyde hangisi görünür?
  5. Kullanıcı panele bir kez tıklayıp bırakırsa MouseListener'ın hangi metotları hangi sırayla çağrılır?
  6. Color.RED.brighter() hangi rengi verir?
Cevapları göster
  1. r = min(100, 50) − 5 = 45, r2 = (int) 40,5 = 40, bw = 56, bh = 14.
  2. “68 kuruş yapmak için kullanılacaklar:” ardından 1 50, 0 25, 1 10, 1 5, 3 1 kuruş.
  3. (50 + 100/2, 50 + 60/2) = (100, 80).
  4. B: her bölgede tek bileşen olur, son eklenen kazanır (A panelde kalır ama yerleşimde yer almaz).
  5. mousePressed → mouseReleased → mouseClicked (işaretçi panele girerken ayrıca mouseEntered).
  6. Yine (255, 0, 0): kırmızı zaten en parlak; 0 olan yeşil ve mavi bileşenler 0 kalır.

Özet

Alıştırmalar

  1. Hedef tahtası: panel boyutuna göre ölçeklenen, kırmızı-beyaz 5 iç içe halka çizin.
  2. Sayaç penceresi: “−1”, “+1”, “Sıfırla” düğmeleri ve değeri gösteren bir JLabel.
  3. Çizim programına bir “Temizle” düğmesi ekleyin.
  4. Çizim programında sağ tık son eğriyi silsin.
  5. Para üstü programı negatif miktarlar için “Miktar pozitif olmalı” yazsın.
  6. Sıcaklık dönüştürücü: JTextField'a °C girilip düğmeye basılınca °F gösterilsin.
Cevaplar / ipuçları
  1. Döngü: int ri = r - i * r / 5; g.setColor(i % 2 == 0 ? Color.RED : Color.WHITE); g.fillOval(cx - ri, cy - ri, 2 * ri, 2 * ri); Büyükten küçüğe çizin.
  2. private static int sayac; alanı; arti.addActionListener(e -> etiket.setText("" + (++sayac)));, panel FlowLayout.
  3. Düğme dinleyicisi: egriler.clear(); repaint(); (panel ile düğme BorderLayout'ta CENTER ve SOUTH).
  4. mousePressed başında: if (e.getButton() == MouseEvent.BUTTON3) { if (!egriler.isEmpty()) egriler.remove(egriler.size() - 1); repaint(); return; }; mouseDragged başına if (!SwingUtilities.isLeftMouseButton(e)) return;
  5. parseInt'ten sonra: if (miktar < 0) { rapor.setText("Miktar pozitif olmalı"); return; }
  6. double c = Double.parseDouble(alan.getText()); sonuc.setText(c * 9 / 5 + 32 + " °F"); 100 → 212.0 °F; hatalı girdi için NumberFormatException yakalayın.

Özet

Kaynaklar

  • Oracle, The Java Tutorials: Creating a GUI With Swing; Performing Custom Painting; Laying Out Components Within a Container; Writing Event Listeners; Concurrency in Swing.
  • Oracle, Java SE 21 API Documentation: java.awt.Graphics, java.awt.Color, javax.swing.JFrame, javax.swing.SwingUtilities.
  • P. Deitel ve H. Deitel, Java: How to Program, 11. baskı, Pearson (Bölüm 12: GUI Components; Bölüm 13: Graphics and Java 2D).
  • K. Sierra ve B. Bates, Head First Java, 3. baskı, O'Reilly (Bölüm 14–15: GUI, Swing ve olaylar).
  • C. S. Horstmann, Core Java, Volume I: Fundamentals, 12. baskı, Pearson (Bölüm 10–11: grafik programlama, olay işleme, Swing).
  • A. B. Downey ve C. Mayfield, Think Java, 2. baskı, O'Reilly (Ek: Java 2D Graphics).

Son

Bölüm 8: Grafikler
Sonraki bölüm: Bölüm 9: İş Parçacıkları
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.