25 Mart 2010 Perşembe

Swing ve EDT (Event Dispatch Thread)'ın Önemi

Java AWT'nin önemli bir parçası EDT dir. AWT bize hangi sistem altında çalışırsak çalışalım pencere sistemini soyutlayan bir sistemdir. Bu sistemin varlığının sebebi çeşitli işletim sistemlerinin farklı pencere sistemlerine sahip olmasından kaynaklanıyor. Java iddası gereği (Platformdan bağımsız olma) AWT ile beraber üzerinde çalıştığı sistemin pencere yöneticisine bağlantı kurmamızı sağlayan bir sistem sağlamak için adı üzerinde soyut (abstract) bir araç-kiti (toolkit) olan  AWT'yi sunuyor. EDT ise bunun bir parçası demiştik. Görsel öğeler eğer kullanıcının hareketlerine yanıt veriyor ve çoğu zaman bir işlem gerçekleştirilmesini sağlıyorsa birer kullanıcı arayüzü (GUI) haline gelirler. Örneğin yaz tatilinde çekilmiş olduğunuz bir resim sizi internete bağlamayacaktır yada üzerine fareyi getirdiğinizde bir tepki vermeyecektir. O zaman bir kullanıcı arayüzünde o kullanıcıya cevap veren durumlar ve bu durumların ürettiği bazı olaylar vardır. Mesela bir düğmeye tıklamak bir menüyü seçmek bir olay yaratır. Bu olayın işlenmesi ve gerekiyorsa görsel bir bildirimde bulunulması işi önemlidir.

Bildiğiniz gibi biz programlarımızı farklı işlemleribağımsız olarak yürütülecek şekilde tasarlıyabiliyoruz. Bu işlemleri ayrı kanallarda yaparken grafik arayüz ile ilgilenmeye başlayınca aklımıza kullanıcı arayüzünün de performans açısından çok kanallı tasarlanabilineceği aklımıza gelmiş olabilir. Ancak gerçekte çoğu çizim işlemi ve olay yönetimi tek kanalda yapılacak şekilde dizayn edilir.

Not: Swing içerisinde her zaman tek kanallık söz konusu olmaya bilir. Bazı çalışma zamanı ortamlarında çok kanallı yaklaşım sergilenebilir. Ayrıca Swing dökümanları içerisinde Thread-Safe ifadeleri yer alabilir. Thread-Safe ile işaret edilen durumlar java tarafından sekronize edilmiştir ve aşağıda bahsedeceğim çizim hatalarına neden olmaz.

Bunun asıl sebebi çok kanallı yaklaşımın hem hataları ayıklamayı zorlaştırmaları hemde bazı garip davranışlara yol açması. Bazı sistemler kanalları belirli bir süre çalıştırıp durdururken bazıları ise kanalın kendi isteği ile işlemciyi serbest bırakmasını destekler. Bu iki durumdan bir sakıncası var. Bildiğiniz gibi bir kanal bir iş yaparken yaptığı iş yarıda kesilebilir.  Bu durumda o iş yarıda kalır. Yapılan bu iş sonucu bir çizim yapılacaksa mesela bir düğmenin etiketi çizilecekse o etiket şaçma sapan çizilebiliyor. Çünkü etiketin içeriğini değiştiren kod parçası işini bitiremeden durdurulmuş ve çizim kanalı çalıştırılmıştır. İşte tüm bu ve burada açıklanmayan bazı durumlardan dolayı kullanıcı arayüzünü ilgilendiren bütün işlemler aynı kanalda yapılır. İşte bu kanalın adı EDT dir.

Arayüzü değiştirme işlerinin hepsi EDT içerisinde yapılması gereklidir. EDT için yapılan çağrılar her zaman bir kuyruğa sokulur. Arka arkaya yapılan bir çok çağrı birleştirilip tek sefer de işlenebilir yada sırayla işlenir. İşleri bu şekilde yapamnın bir yararıda kullanıcı arayüzünüzün donmasını engellemektir.

Swing EDT için bazı metotlar sağlar. Bu metotlar:
static void invokeLater(Runnable r)
static void invokeAndWait(Runnable r)
static boolean isEventDispatchThread()
invokeLater Desktop uygulamalarında invokeAndWait Applet uygulamalarında kullanılır. Aslında iki metotda java.awt.EventQueue sınıfındaki metotların tetikleyen cover metotlardır.
invokeLater asenkron olarak çalıştırılırken invokeAndWait senkron olarak çalışır. invokeAndWait illa appletler için kullanılacak diye bir şey yok ancak arayüzü ilk yapılandırırken appletlarda kullanılması önerilmektedir. invokeAndWait AWT kanalı işlem bitene kadar beklemeye alır.

invokeLater'ın önemi uzun hesaplamalar yapacağımız zaman ya da network'e bağlantı yapıp bir veritabanından veri çekeceğimiz zaman ortaya çıkar. Eğer bu işlemleri AWT-Thread (Event Dispatch Thread) içinde yaparsak ve kullanıcı pencereyi ikon durumuna getirip tekrar ekrana büyütürse pencere içerisinin boyanmadığını doğal olarak programın donduğu gibi bir imaj oluştuğunu görürsünüz.

Peki içerisinde bulunduğumuz kanalın AWT kanalı olup olmadığını nasıl anlarız. isEventDispatchThread metodu true gönderirse bu AWT kanalı içerisinde olduğumuzu gösterir. False değeri ise tersini ispatlar.

Swing kütüphanesi tüm bu zorluklardan standart ve kolay bir yöntemle kurtulmamız için SwingWorker adında JavaSE6 (JDK 1.6 / JRE1.6) ile gelen sınıfı bünyesine dahil etmiştir. Ayrıca bu yazının yazıldığı tarih itibari ile terkedilmiş bir çatı olan SAF (Swing Application Framework) Task ile daha iyi çözümler üretmiştir. SAF'ın akıbetinden sonra onun halefi olan  BSAF(Better Swing Application Framework) ortaya çıkmıştır. BSAF'ı google dan aratmanızı tavsiye ederim. Çünkü bu yazı yazılırken kenai üzerinde konumlanan BSAF java.net'e henüz geçmemişti. Swing Worker SAF ve BSAF başka bir yazının konusu. Şimdilik Swing ve EDT konusu bu kadar. Aklıma başka bir şeyler gelirse bu yazıyı güncelleyebilirim yada Swing ve EDT (2) şeklinde başka bir başlıkta yayınlayabilirim.
 
Not: Kenai Oracle kararı ile özellikleri java.net'e aktarılacak ve Oracle'ın kendi içerisinde geliştirilen yazılımlara ev sahipliği yapacak ve son olarak dışarıya kapatılacaktı. Kenai üzerinde konuşlanan yazılım depoları otomatikman java.net'e aktarılacaktı.

28 Şubat 2010 Pazar

Neden Swing

Java Swing'e neden ihtiyaç duydu ve Swing bize neler sağladı.

Javanın 1.0 sürümünde Kullanıcı Grafik Arayüzü (GUI) olarak AWT (Soyut Pencereler Araç Kiti - Abstract Windows Toolkit) vardı. AWT mantığı Javanın çalıştığı platformda desteklenen GUI'ler için javada bir eş yaratılmasından ibaretti. Yani siz bir düğme oluşturduğunuzda bu düğme hangi platformadaysanız o platformun doğal kodundan (native code) türetiliyordu.

Bu yaklaşımın bir kaç sakıncası vardı. Bunlardan bir tanesi sunulan bileşenlerin (component) çeşitliliği Javanın üzerinde çalıştığı platform ile sınırlıydı. Java bir kere yaz her yerde çalıştır ilkesiyle ters düşmemek için yanlızca bütün platformlarda desteklenen bileşenleri sunabiliyordu.

Bir başka sakınca ise davranış ve görünümün (Look And Feel) aynı olmamasıydı. Bir bileşen Windows da farklı MacOS da farklı gözüküyor ve farklı davranıyordu. Programcılar bu farklılıkları değerlendirmek zorundaydı. Bu sıkıntılardan yola çıkarak Java Swing'i yarattı.

Swing tüm platformlarda aynı şekilde davranacak ve aynı gözükecekti. Üstelik Swing yeni bileşenlerin oluşturulmasını, hali hazırdakilerin değiştirilmesini ve görünüşlerinin çalıştıkları platformu yansıtacak veya Javanın kendine ait görünümünde olmasını destekleyecek şekilde geliştirilecekti.

Geliştiriciler Swing'i oldukça kullanışlı ve gelişmiş buldular. Zamanla Swing genişledi ve dev bir kütüphane oldu. Swing çekirdek API ile yani JRE ve JDK ile geliyor ve ayrı bir kuruluma gerek kalmıyor.

Swing teknolojisi AWT paketinin Container Sınfını genişleten JComponent ile hayat bulur. JComponent üzerine Swing bileşenlerinin Java2D API'leri kullanarak çizim yaptığı çok sayıda özellik ve metot barındıran dev bir sınıftır.

Aslında Swing teknolijisi MVC (Model Görünüm Kontrolcü - Model View Controler) teknolojisine dayanır. MVC ilk olarak Smalltalk Programlama dilinde kullanılmış bir yaklaşımdır. MVC bir bileşeni  3 sorumluluğu yerine getirecek 3 parçaya ayırır. Bu parçalar:
  1. Model : Bileşenin ilgileneceği veri modelini tarif edecek sınıf
  2. View (Görünüm) : Bileşenin veriyi ifade edecek şekilde görüntülenmesini sağlayacak sınıfı ifade eder.
  3. Controller (Kontrolcü): Bileşenle etkileşime girimesi sonucu oluşan olayları ele alan sınıfı ifade eder.
Örneğin JButton sınıfı  bir buttonun davranışını ve modelini uygular. ButtonUI sınıfı ise JButton sınıfının görünüşünü uygular.

Bazı Swing bileşenleri pek çok sınıf ile desteklenmiştir ve bunlar ayrı paketlerde yer alır. Yeri gelmişken Swing paketlerine bakalım:
  1. javax.swing (Birçok bileşen ve destek sınıfları barındırır.)
  2. javax.swing.border (Bileşenlerin çevrelerine çerçeveler oluşturan sınıfları barındırır.)
  3. javax.swing.colorchooser (Renk seçim kutusunu destekleyen sınıfları barındırır.)
  4. javax.swing.event (Swing bileşenleri için özel olayları yöneten sınıfları barındırır.)
  5. javax.swing.filechooser (Dosya iletişim kutusunu destekleyen sınıfları barındırır.)
  6. javax.swing.plaf (Platforma bağlı görünümler oluşturmak için gereken destek sınıfları barındırır.)
  7. javax.swing.plaf.basic (Platforma bağlı görünümler oluşturmak için gereken destek sınıfları barındırır.)
  8. javax.swing.plaf.metal  (Metal temalı görünüm oluşturmak için gereken destek sınıfları barındırır.)
  9. javax.swing.plaf.multi (Farklı temadaki bileşenleri karıştırmak için gereken destek sınıfları barındırır.)
  10. javax.swing.plaf.synth (Sentetik tema oluşturmak için sınıflar barındırır.)
  11. javax.swing.table (Tablolar oluşturmak ve yönetmek için gereken destek sınıfları barındırır.)
  12. javax.swing.text (Text bileşenlerini için destek sınıf barındırır. Text bileşenleri HTML yada RTF tipi textleri görüntüleyebilir.)
  13. javax.swing.text.html (HTML tipi text bileşenleri için destek sınıfları barındırır.)
  14. javax.swing.text.html.parser (HTML ayrıştırıcı sınıfları barındırır.)
  15. javax.swing.text.rtf (RTF (Zengin Yazı Formatı -Rich Text Format) için destek sınıfları barındırır.)
  16. javax.swing.tree (Ağaç listeleri bileşenleri için destek sınıfları barındırır.)
  17. javax.swing.undo (Bir programda yapılan işlemleri geri almak ve/veya tekrar uygulamak için gereken sınıfları barındırır.)
javax.swing paketi oldukça büyük bir pakettir ve bileşenlerin çoğu bu pakettedir. Ayrıca sıkca kullanacağımız pek çok yararlı sınıfıda barındırır. Diğer paketler javax.swing paketindeki bileşenleri desteklemek amacı ile yada görünüm v.s. gibi diğer destekler için oluşturulmuştur.

Bu yazıma burada son vermeyi düşündüm. Ancak Swing ile ilgili birçok yazı yayınlayacağım. Şimdilik yayınlaması düşündüğüm bazı konular şöyle:
  • Swing bileşenlerini oluşturmak: Klasik bir button nasıl oluşturulur v.s.
  • Swing bileşenlerini değiştirmek: Tablo veri modeli nasıl değiştirlir. Hücre boyama v.s.
  • Yeni bileşenler yaratmak: JPanel kullanarak yeni bir bileşen oluşturmak yada JButtonu değiştirerek bileşenlerin görünümü ile oynamak
  • Bileşenler ile ilgili örnek kodlar: Tablo sütün sıralama filtreleme v.s.
  • Özel sınıflar: Swing'i desteklemek amaçlı yazılmış sınıflar (Swing worker v.s)
  • Olay yönetimi v.s
  • Tabiki arada kafama göre bir kaç konu.