Java'da basit bir GUI programı geliştirme süreci. Java için GUI çerçevelerine ve ilk basit Swing GUI uygulamama kısa bir genel bakış Java kullanarak bir GUI nasıl uygulanır

Tarihsel olarak öyle oldu ki, UI ile çok az çalışmak zorunda kaldım. Görünüşe göre, bu yüzden her türlü Qt ve wxWidget ile bu kadar ilgileniyorum - her şey yeni, ilginç, olağandışı görünüyor. Ancak, Java çalışmasına başlar başlamaz bugün Qt ve wxWidget'lar hakkında değil, Swing hakkında konuşacağız. Bugün birlikte Java'da düğmeler, listeler ve hatta dış görünümleri değiştirme yeteneği olan basit bir GUI uygulaması yazacağız!

Java dünyasında GUI çerçeveleriyle ilgili durum biraz kafa karıştırıcıdır. Anladığım kadarıyla olaylar şu şekilde.

  • A.W.T.(Özet Pencere Araç Takımı) ilk GUI çerçevesiydi. Fikir doğruydu - AWT yerel denetimleri kullanır, yani uygulamanızı nerede çalıştırırsanız çalıştırın, bunlar fiziksel olarak yerel görünür ve yereldir. Ne yazık ki, (1) farklı ortamlar için ortak olan birkaç kontrol olduğu ve (2) hiçbir şeyin sürünüp dağılmaması için platformlar arası yerel arayüzler yazmanın çok zor olduğu ortaya çıktı;
  • Bu nedenle, AWT ile değiştirildi Sallanmak. Swing, AWT'nin oluşturduğu kalıpları kullanır ve üzerine kontrolleri kendisi çizer. Bu ekonomi elbette daha yavaş çalışır, ancak kullanıcı arayüzü çok daha taşınabilir hale gelir. Swing, programcıya aralarından seçim yapabileceğiniz çeşitli Görünüm ve Hisler sunar; bu sayede, uygulamayı istediğiniz gibi görünmesini sağlayabilirsiniz. ve davrandı hem Windows hem de Linux için aynıdır veya uygulamanın nerede çalıştırıldığına bakılmaksızın yerel olana çok benzer olması. İlk durumda, uygulamada hata ayıklamak daha kolaydır, ikincisinde kullanıcılar daha mutlu olur. Bu arada, Swing aslında Netscape'teki adamlar tarafından yapıldı;
  • GBT(Standart Widget Toolkit), IBM tarafından yazılmış ve Eclipse'de kullanılan bir çerçevedir. AWT'de olduğu gibi, yerel kontroller kullanılır. SWT, JDK'nın bir parçası değildir ve JNI kullanır, bu nedenle Java'nın "bir kez yaz, her yerde çalıştır" ideolojisine gerçekten uymuyor. Görünüşe göre çok güçlü bir istekle, tüm platformlar için SWT uygulamasını bir pakette paketleyebilirsiniz ve ardından uygulama taşınabilir hale bile gelebilir, ancak yalnızca bazı yeni işletim sistemi veya işlemci mimarisi görünene kadar;
  • JavaFX Oracle'da aktif olarak biçilmiş ve Swing için bir ambulans yedeği olarak konumlandırılmıştır. İdeolojik olarak JavaFX, Swing'e benzer, yani kontroller yerel değildir. JavaFX'in ilginç özellikleri arasında donanım hızlandırma, CSS ve XML (FXML) ile GUI oluşturma, Swing'de JavaFX kontrollerini kullanma yeteneği ve ayrıca çizim diyagramları ve 3D için olanlar da dahil olmak üzere bir dizi yeni güzel kontrol yer alır. Şu andan itibaren videolar ayrıntılı genel bakış JavaFX mümkündür. Java 7'den beri JavaFX, JRE/JDK'nın bir parçasıdır;
  • NetBeans Platformu(NetBeans IDE ile karıştırılmamalıdır!) - bu öyle bir şey ki, anladığım kadarıyla Swing ve JavaFX'in üzerinde çalışıyor, onlarla çalışmak için daha uygun bir arayüz ve her türlü ek kontrol sağlıyor. NetBeans Platformunu kullanan bir uygulamada, penceredeki panelleri döşemeli pencere yöneticilerinin yaptığına benzer şekilde yerleştirip, ilaç ve bırak ile sekmeleri sürükleyip bırakma yeteneğini gördüm. Görünüşe göre, Swing'in kendisi bunu yapamaz. NetBeans Platformu hakkında daha fazlasını okuyun;

Başka çerçeveler olması mümkündür. Bugün en kanonik olanı Swing'dir, bu yüzden onunla ilgileneceğiz.

Yukarıda, oradaki bazı Bak & Hisset hakkında bir şeyler söylendi. ne olduğunu daha iyi anlamak için söz konusu, aynı Look & Feel listesini görüntüleyen ve programı çalıştırma sürecinde bunlar arasında geçiş yapmanızı sağlayan bir program yazalım.

Uygulamamız Ubuntu altında şöyle görünecek:

Ve Windows altında çalışırken şöyle görünecek:

Gördüğünüz gibi, Windows ve Linux için JRE'ler farklı bir L&F seti içerir. Ek olarak, üçüncü taraf bir Look&Feel bağlayabilir veya hatta kendinizinkini yazabilirsiniz. Varsayılan olarak, tüm işletim sistemlerinde ve pencere yöneticilerinde aşağı yukarı aynı görünen L&F Metal kullanılır. Yuvarlak düğmeleri tercih ederseniz Metal yerine Look&Feel Nimbus kullanabilirsiniz. Uygulamanın yerel bir uygulama gibi görünmesini istiyorsanız, Linux altında L&F GTK + (Kullanıcının KDE çalıştırıp çalıştırmadığını merak ediyorum?), Ve Windows altında - L&F Windows'u seçmelisiniz. Programınızın farklı L&F'ler arasında geçiş yapmasını sağlamak iyi bir fikir olabilir. Öte yandan, tüm bu L&F'ler ile uygulamayı test etmeniz gerekecektir.

Uygulamanın kaynak koduna bakalım. UI uzmanlarının meslektaşları, herhangi bir WYSIWYG düzenleyicisi kullanmadıklarına dair bana güvence verdiler ve eğer kullanırlarsa, sadece hızlı prototipleme içindir. İyi WYSIWYG editörlerinden isim JFormDesigner idi. Hatta oluşturduğu kodun insan tarafından yazılmış koda benzediğini ve cehennemi().sequence().calls().methods() olmadığını söylüyorlar. Genel olarak, tüm kodlar IntelliJ IDEA'da pençelerle yazılmıştır.

public static void main(String args) (

@Geçersiz kıl
public void run() (
GUI oluştur() ;
}
} ) ;
}

Swing ve AWT'de, kullanıcı arayüzünde bir şeyi değiştirmek istiyorsak, bunu olay gönderme iş parçacığından yapmalıyız. invokeLater statik yöntemi, Runnable arabirimini uygulayan ve olay gönderme iş parçacığı içinde run() yöntemini çağıran bir sınıf alır. Yukarıdaki sözdizimine aşina değilseniz, bu, Java'nın bir sınıfa isim vermeden bildirme şeklidir. İsimsiz sınıflara isimsiz denir. Java'daki anonim sınıflar genellikle lambda işlevlerinin işlevsel programlama dillerinde oynadığı rolün aynısını gerçekleştirir. Diğer şeylerin yanı sıra, kapatmalar da desteklenir. İlginç bir şekilde, lambdalardan farklı olarak, Java'daki anonim sınıflar, aynı anda bir çok yöntemi geçmenize izin verir. Ayrıca, kalıtım ve soyut sınıfların yardımıyla, yöntemlerin tamamı veya bir kısmı için varsayılan uygulamalarını alabilirsiniz.

@Override ek açıklaması, run() yönteminin gerçekten Runnable arabiriminin yöntemini geçersiz kılacağını kontrol eder. Onsuz, bir yöntemi geçersiz kılarken, yanlışlıkla bir yazım hatası yapabilir ve mevcut olanı geçersiz kılmak yerine yeni bir yöntem tanımlayabiliriz. Bununla birlikte, bu özel durumda, açıklama görünüşe göre çok kullanışlı değil ve muhtemelen gereksiz bile.

Sonuç olarak, olay gönderme iş parçacığı, createGUI () yöntemini çağırır, tam kod aşağıdakilerden hangisidir:

özel statik boşluk createGUI() (
liste< String>liste = yeni JList<> () ;
list.setSelectionMode (ListSelectionModel .SINGLE_SELECTION);

JScrollPane listScrollPane = yeni JScrollPane (liste) ;

JPanel topPanel = yeni JPanel();
topPanel.setLayout(yeni BorderLayout()) ;
topPanel.add (listScrollPane, BorderLayout .CENTER ) ;

ActionListener updateButtonListener = yeni UpdateListAction(list) ;
updateButtonListener.actionPerformed(
yeni ActionEvent (liste, ActionEvent .ACTION_PERFORMED , null )
) ;

JButton updateListButton = new JButton ("Listeyi güncelle") ;
JButton updateLookAndFeelButton = new JButton ("Bak ve Hisset'i Güncelle") ;

JPanel btnPanel = yeni JPanel();
btnPannel.setLayout (yeni BoxLayout (btnPannel, BoxLayout .LINE_AXIS ) ) ;
btnPannel.add(updateListButton) ;
btnPannel.add (Kutu .createHorizontalStrut (5) ) ;
btnPannel.add(updateLookAndFeelButton) ;

JPanel altPanel = yeni JPanel();
altPanel.add (btnPanel) ;

JPanel paneli = yeni JPanel();
panel.setBorder (BorderFactory .createEmptyBorder (5,5,5,5));
panel.setLayout(yeni BorderLayout());
panel.add (topPanel, BorderLayout .CENTER ) ;
panel.add (bottomPanel, BorderLayout .GÜNEY ) ;

JFrame çerçevesi = yeni JFrame ("Look&Feel Değiştirici" );
frame.setMinimumSize (yeni Boyut (300, 200));
frame.setDefaultCloseOperation (WindowConstants .EXIT_ON_CLOSE);
frame.add (panel);
çerçeve.paket();
frame.setVisible(true) ;

UpdateListButton.addActionListener(updateButtonListener) ;
updateLookAndFeelButton.addActionListener(
yeni UpdateLookAndFeelAction(çerçeve, liste)
) ;
}

Burada, genel olarak, süper karmaşık bir şey yoktur. Düğmeler, bir liste oluşturulur, liste bir JScrollPane'e sarılır, böylece liste kaydırılır. Kontroller, paneller kullanılarak bir çerçeve içinde düzenlenmiştir. Paneller farklı düzenlere sahip olabilir, burada BorderLayout ve BoxLayout kullandık. Prensip, wxWidgets'ta kullanılana benzer.

Düğme basışları gibi çeşitli olaylara yanıt vermek için ActionListener arabirimini uygulayan sınıflar kullanılır. Yukarıdaki kod böyle iki sınıf kullanır, UpdateListAction ve UpdateLookAndFeelAction. Adından da tahmin edebileceğiniz gibi, birinci sınıf, soldaki "Listeyi güncelle" düğmesine tıklamaları işlemekten sorumludur, ikincisi - açık sağ düğme Bak ve Hisset'i güncelleyin. ActionListener, addActionListener yöntemi kullanılarak düğmelere eklenir. Uygulama başladıktan hemen sonra mevcut Look&Feels listesini görmek istediğimiz için “Listeyi güncelle” butonuna tıklayarak öykünme yapıyoruz. Bunu yapmak için ActionEvent sınıfının bir örneğini oluştururuz ve bunu UpdateListAction sınıfının actionPerformed yöntemine bir argüman olarak iletiriz.

UpdateListAction sınıfının uygulaması aşağıdaki gibidir:

statik sınıf UpdateListAction, ActionListener(
özel JList< String>liste;

public UpdateListAction(JList< String>liste) (
this.list = liste;
}

@Geçersiz kıl
public void actionPerformed(ActionEvent olayı) (
Dizi Listesi< String>lookAndFeelList = yeni ArrayList<> () ;
UIManager.LookAndFeelInfo infoArray =

int lookAndFeelIndex = 0 ;
int currentLookAndFeelIndex = 0 ;
string currentLookAndFeelClassName =
UIManager .getLookAndFeel() .getClass() .getName() ;

için ( UIManager.LookAndFeelInfo bilgi: infoArray) (
if (info.getClassName() .equals(currentLookAndFeelClassName) ) (
currentLookAndFeelIndex = lookAndFeelIndex;
}
lookAndFeelList.add(info.getName()) ;
lookAndFeelIndex++;
}

String listDataArray = new String [lookAndFeelList.size()];
son Dize newListData =
lookAndFeelList.toArray (listDataArray);
final int newSelectedIndex = currentLookAndFeelIndex;

SwingUtilities .invokeLater(yeni Runnable()(
@Geçersiz kıl
public void run() (
list.setListData(newListData);
list.setSelectedIndex(newSelectedIndex) ;
}
} ) ;
}
}

Yapıcıda, mevcut Görünüm ve Hissi göstereceğimiz bir listeye işaretçi iletilir. Aslında UpdateListAction, ana LookAndFeelSwitcher sınıfımızın iç içe geçmiş bir sınıfı olduğundan, onu oluşturan LookAndFeelSwitcher örneğinin alanlarına doğrudan erişme yeteneğine sahiptir. Ama içimdeki işlevselci bu yaklaşıma direniyor, bu yüzden listeye açıkça bir referansı yapıcı aracılığıyla iletmeye karar verdim.

Düğme tıklandığında actionPerformed yöntemi çağrılır. Bu yöntemin kodu oldukça önemsizdir - UIManager sınıfının statik yöntemlerini mevcut Look&Feels listesini almak ve mevcut Look&Feel'ı belirlemek için kullanırız. Ardından listenin içeriği ve içinde seçilen öğe güncellenir. Burada iki noktaya dikkat etmeniz gerekiyor. İlk olarak, her Bak&Hisset isim Ve sınıf adı farklı şeylerdir. Kullanıcı adlarını göstermeliyiz ve Look & Feel'i değiştirirken sınıf adını kullanmalıyız. İkinci olarak, newListData ve newSelectedIndex son değişkenlerinin nasıl oluşturulduğuna ve ardından anonim sınıfta nasıl kullanıldığına dikkat edin. Bu, daha önce tartışılan aynı kapanış analogudur. Açıktır ki, kapanışlarda nihai olmayan değişkenlerin kullanılması üzücü sonuçlara yol açacaktır.

Son olarak, UpdateLookAndFeelAction sınıfını düşünün:

statik sınıf UpdateLookAndFeelAction, ActionListener(
özel JList< String>liste;
özel JFrame rootFrame;

public UpdateLookAndFeelAction(JFrame çerçevesi, JList< String>liste) (
bu .rootFrame = çerçeve;
this.list = liste;
}

@Geçersiz kıl
public void actionPerformed(ActionEvent e) (
String lookAndFeelName = list.getSelectedValue();
UIManager.LookAndFeelInfo infoArray =
UIManager .getInstalledLookAndFeels();

için ( UIManager.LookAndFeelInfo bilgi: infoArray) (
if (info.getName() .equals(lookAndFeelName) ) (
String mesajı = "Bak&hisset" olarak değiştirildi + lookAndFeelName;
denemek(
UIManager .setLookAndFeel (info.getClassName() );
SwingUtilities .updateComponentTreeUI(rootFrame);
) yakalama (ClassNotFoundException e1) (
mesaj = "Hata: " + info.getClassName () + " bulunamadı" ;
) yakalama (InstantiationException e1) (
mesaj = "Hata: örnekleme istisnası";
) yakalama (IllegalAccessException e1) (
mesaj = "Hata: yasadışı erişim";
) yakalamak ( DesteklenmeyenLookAndFeelException e1) (
mesaj = "Hata: desteklenmeyen görünüm ve his";
}
JOptionPane .showMessageDialog (boş , mesaj) ;
kırmak ;
}
}
}
}

Burada basitçe (1) listede seçilen adla aynı ada sahip bir L&F buluruz, (2) L&F'yi UIManager sınıfının statik setLookAndFeel yöntemini kullanarak değiştiririz ve (3) UI'mizin ana çerçevesini tekrar tekrar çizeriz , üzerinde bulunan öğeler, SwingUtilities sınıfının statik updateComponentTreeUI yöntemini kullanarak. Son olarak, her şeyin başarılı olup olmadığını kullanıcıya bir mesajla bildiririz.

Sadece GUI'de değil, Java'da GUI uygulamalarında hata ayıklama hakkında da birkaç söz söylemek istiyorum. İlk olarak, Swing'in Ctr + Shift + F1 adlı sihirli klavye kısayolu vardır ve bu kısayol, kontrollerin nasıl yerleştirildiğiyle ilgili bilgileri stdout'a yazdırır. Rakiplerinizin kullanıcı arayüzünü çalmak istiyorsanız çok kullanışlıdır. İkincisi, böyle ilginç bir kısayol tuşu var Ctr + \. Çalışan bir Java uygulamasının konsolunda tıklatırsanız, tüm iş parçacıkları ve bunların yığın izleri görüntülenecektir. Bir kilitlenme yakaladıysanız uygun. Son olarak, üçüncü olarak, GUI'nin geliştirilmesi sırasında panellerin farklı renklerde dekore edilmesi faydalı olabilir. Bunu şu şekilde yapabilirsiniz:

buttonPanel.setBackground (Renk .BLUE ) ;

ön uyarı

Çoğunlukla "yaptığım gibi yap" ilkesiyle hareket ettiğimiz ve "parmaklarda" denilen kavram ve teknik detayları konuştuğumuz önceki oturumlardan farklı olarak, bu dersten itibaren sunum tarzı biraz değişecek ve daha teknik olun.

Bu, ne yazık ki, önlenemez, çünkü. er ya da geç bir noktaya gelmek zorunda kalacağız, bundan sonra "parmaklarda" yaklaşımı savunulamaz hale gelecek. Şimdi o an geliyor. O halde cesaretimizi toplayalım, kollarımızı sıvayalım ve başlayalım.

Önceki derste () monitör ekranında bir grafik pencere oluşturup görüntüledik ve bu süreçte görünümü ve konumu ile ilgili bazı sorunları çözdük. Şimdi perde arkasında kalanları tartışacağız.

Muhtemelen kaynak kodun başında aşağıdaki iki satırın olduğunu fark etmişsinizdir:

java.awt.* dosyasını içe aktarın;

javax.swing'i içe aktarın.*;

Burada biraz oyalanmamız gerekiyor. Java programlama ortamının ağ oluşturma, grafikler, veritabanları, mesajlaşma vb. için birçok kitaplık içerdiğinden daha önce bahsettiğimizi hatırlayın. Java'ya tüm gücü ve çok yönlülüğü veren şey kütüphanelerdir.

Java'da "kütüphane" terimi yerine "paket" kavramı kullanılır. Yukarıdaki satırlar, grafiksel bir arayüz oluşturmak için gerekli paketleri birbirine bağlar. Daha sonra diğer paketleri kullanacağımızı göreceksiniz ama şimdilik bu ikisi bize yetiyor.

Paketler, gelecekteki uygulamanın bir veya daha fazla işlevselliğini sağlayan gerekli sınıfları ve arayüzleri (zamanında arayüzler hakkında konuşacağız) içerir. Yıldız işaretinin ("*") varlığı, programcının paketin içerdiği sınıfları veya arabirimleri açıkça belirtmeden paketin tüm içeriğini içe aktardığını gösterir. Büyük paketler söz konusu olduğunda, ortaya çıkan nesne kodu çok büyük olabilir, ancak endişelenmeyin: Java derleyicisi, yalnızca programınızın gerçekten ihtiyaç duyduğu şeyi kullanacak kadar akıllıdır; Programın ihtiyaç duymadığı her şey, derleyici nesne koduna dahil etmeyecektir. İsterseniz, biraz farklı bir paket dahil etme biçimi kullanabilirsiniz, örneğin,

java.awt.window'u içe aktarın;

javax.swing.JFrame'i içe aktarın;

ancak bu, programcının bu paketlerin yapısı ve yetenekleri hakkında zaten iyi bir bilgiye sahip olduğunu varsayar. Daha önce belirtilen bağlantı paketlerinin daha basit biçimini kullanacağız.

Bir paketin geliştirilmekte olan programa aktarılması (bağlanması), paket adının ardından import anahtar sözcüğü ile yapılır. Her paket ayrı ayrı içe aktarılmalıdır (yani import java.awt.*, javax.swing.*; yazamazsınız). Tabii ki, kaynak kodun hacmi biraz arttı, ancak çok az. Programınızı oluşturan tüm sınıflar ve arabirimler, içe aktarma yapılarından sonra yerleştirilmelidir, aksi takdirde derleyici bir derleme hata mesajı oluşturur.

İlk paket (java.awt ile başlayan) öncelikle Java programlarının grafik alt sistemi ile etkileşimini sağlar. işletim sistemi. Java'nın platformlar arası bir programlama dili olduğunu ve bu kodun yürütüleceği işletim sisteminden bağımsız olarak tek bir nesne kodu oluşturduğunu hatırlayın. Bu nedenle Java, kullanıcının bilgisayarında yüklü olan işletim sistemi tarafından sağlanan kaynaklara erişmeye "zorlanır". Böyle bir kaynak grafiklerdir (grafiklerin yanı sıra Java, erişmek için işletim sistemi "hizmetlerini" çağırır. dosya sistemi ve diğer kaynaklar). Böylece, java.awt.* paketi, Java ile yazılmış GUI'lerin grafik yetenekleri işletim sistemi ve ekran grafik nesneleri monitör ekranında Java programlarında oluşturulur. Burada biraz duracağız.

Java'daki tüm grafik bileşenleri iki kategoriye ayrılır: hafif (hafif) ve ağır (ağır). Ezici çoğunluk grafik bileşenleri(düğmeler, listeler, ağaçlar, etiketler, tablolar vb.) hafiftir. Bu, işletim sisteminin onlar hakkında kesinlikle hiçbir şey bilmediği ve varlıklarından "şüphelenmediği" anlamına gelir. Hafif bileşenler pencerelere aittir (önceki derste gösterdiğimiz gibi) ve bu pencerelerde görüntülenir.

Bir pencerede bir buton görüntülemek istiyorsak, onu aşağıdaki gibi bir kodla tanımlamamız yeterli.

JButton buttonPressMe = new JButton("Bana basın");

ve pencerede belirtilen konuma yerleştirin (ilgili ayrıntılar daha sonra açıklanacaktır). Düğme hafif bir nesnedir ve işletim sisteminin düğme hakkında bilgisi yoktur (işletim sistemi için düğme yoktur). Yalnızca bulunduğu pencere düğmeyi "bilir". Pencere düğmeyi çizer, düğmeyle meydana gelen olayları yakalar, bir şey tarafından gizlenmişse düğmeyi yeniden çizer, vb. Ancak pencerenin kendisi - işletim sistemi bunun farkındadır ve tam olarak pencere ağır bir bileşen olduğu için. Yalnızca pencerenin işletim sistemi kaynaklarına (özellikle grafik kaynaklarına) erişimi vardır.

Kaynak koduna bakın. Ekranda göstermeden önce pencerenin sol üst köşesinin koordinatlarını hesapladığımızda ekran çözünürlüğünü bilmemiz gerekiyordu.

Boyut sSize = Toolkit.getDefaultToolkit().getScreenSize()

Bu tür bilgileri ne sağlayabilir? İşletim sistemi ve sadece o! Sonra, kodu kullandık

dene(UIManager.setLookAndFeel

(UIManager.getSystemLookAndFeelClassName());

yakalamak(İstisnai)()

böylece pencerenin görünümü belirli bir işletim sisteminde benimsenen standarda uygundur. Bu tür bilgileri ne sağlayabilir? Yine - işletim sistemi! Bu nedenle, grafik arayüzler oluşturmak için java.awt.* paketi olmadan yapamayız.

Ekranda bir pencere görüntülendiğinde, işletim sistemi pencereyi tahsis eder. gerekli kaynaklar(öncelikle bellek) ve pencere görünür hale gelir. Ayrıca, hafif bileşenler devreye girer ve diğer tüm çalışmalar pratik olarak sadece bunlarla gerçekleştirilir.

İkinci içe aktarma paketi (javax.swing ile başlayan) hafif GUI'ler oluşturmaktan sorumludur (başka paketler de vardır, ancak bu en önemli olanıdır ve neredeyse her zaman kullanılır). Bu paketi kademeli olarak inceleyeceğiz ve ustalaşacağız, çünkü. oldukça büyük ve oldukça karmaşık. Bunu bir sonraki derste yapmaya başlayacağız, ama şimdilik dönelim Sonraki satır kaynak kodu:

public class MoneyForNothing JFrame'i genişletir(

Burada yeni olan iki öğe var: Extends anahtar sözcüğü ve JFrame sözcüğü.

anahtar kelime genişletir ("genişletme" olarak çevrilir, ancak anlamı "miras alır" veya "ödünç alma özellikleri ve davranış" ifadesine yakındır) nesne yönelimli programlamanın (veya daha basit olarak sınıf tabanlı programlama) temel kavramını ifade eder ). Bu kavrama "miras" denir. Bunun iyi bir şekilde ele alınması gerekiyor.

Unutmayın, ilk derslerden birinde () sınıf kavramını tartıştık ve örnek olarak bir araba motoru kullandık. Tüm motor çeşitleri ve tasarımları ile (tabii ki içten yanmalı motorlardan bahsediyoruz), bu motorların neredeyse tamamı birbirine benzer: her birinin silindirleri, pistonları, krank milleri, valfleri vb.

Tabii ki, bir tanker için devasa bir dizel motor, bir uçak modeli için küçük bir alkollü motorla karşılaştırılamaz, ancak bunlar (eğer söyleyebilirsem) - uzak da olsalar, akrabalar. Ortak bir ataları var - bir tür soyut motor ve motorların kendileri onun soyundan geliyor (çok, çok uzak olsalar bile).

Programlamada, böyle bir ata genellikle "ebeveyn" veya "üst sınıf" olarak adlandırılır, yani. diğer sınıfların türediği sınıf. Üst sınıfın adı, uzantılardan hemen sonra gelir. Bu nedenle, sıradan dile çevrildiğinde, yukarıdaki kod parçası şu şekilde okunabilir: "sınıf... JFrame sınıfını genişletir", "sınıf... JFrame sınıfını miras alır" veya "sınıf... JFrame sınıfının özelliklerini ve davranışını ödünç alır" . JFrame sınıfı, "standart" grafik pencerelerinin temel özelliklerini ve davranışını tanımlar. JFrame sınıfının kendisi javax.swing.* paketindedir ve programın başında içe aktardığımız şey budur.

JFrame, grafik pencerelerinin ebeveynidir (Java terminolojisinde bir üst sınıftır) (diyaloglar gibi başka pencereler de vardır, ama zamanı gelince bunlardan bahsedeceğiz). Java belgelerine bakarsanız, JFrame sınıfının birkaç kurucuya, alana ve bazı "standart" pencerelerin davranışını tanımlayan yaklaşık iki düzine yönteme sahip olduğunu göreceksiniz. Bu nedenle MoneyForNothing adlı sınıfımız JFrame sınıfının mirasçısıdır (genellikle mirasçılardan değil, alt sınıflardan veya alt sınıflardan bahsederler).

Lütfen JFrame sınıfının kendisinin birkaç sınıfın (çoğu zaten bilinen Java.awt.* paketine aittir) soyundan geldiğini unutmayın:

Bu soruya geri dönmemek için Java kalıtım hiyerarşisinin en üstünde Java.lang.* paketinden sınıfların olduğuna dikkatinizi çekiyoruz. Bu, JDK'dan açıkça alınması gerekmeyen tek pakettir - her zaman otomatik olarak içe aktarılır. Bu "merdivene" bakılırsa, JFrame sınıfı java.lang.Object öğesinin büyük-büyük-büyük-torunudur (yukarıdaki resme bilimsel olarak sınıf hiyerarşisi denir).

Grafiksel kullanıcı arayüzünün (Grafik Kullanıcı Arayüzü'nden GUI olarak kısaltılır) tüm bileşenleri, hatırlayın, hafif öğelerdir, ana pencerenin içine yerleştirilmelidir - JFrame'in halefi. Şu anda elimizde herhangi bir bileşen yok, ancak yakında görünecekler - söz veriyoruz.

Ve şimdi sonuncumuzun üzerinden geçelim kaynak kodu, şuna benzer:

// Yapıcı

genel MoneyForNothing()(

setTitle("Paraya Karşılıksız Hoş Geldiniz");

setSize(yeni Boyut(600, 400));

Boyut sSize = Toolkit.getDefaultToolkit().getScreenSize(),

fSize = getSize();

if (fSize.height > sSize.height) (fSize.height = sSize.height;)

if (fSize.width > sSize.width) (fSize.width = sSize.width;)

setLocation((sSize.width - fSize.width)/2,

(sSize.height - fSize.height)/2);

setDefaultCloseOperation(EXIT_ON_CLOSE);

setVisible(doğru);

Öncelikle pencerenin başlığını belirliyoruz ( setTitle(...) methodu). Ardından pencerenin yatay ve dikey boyutları ayarlanır (setSize(...) yöntemi). Monitörün ekran çözünürlüğü belirlendikten sonra penceremizin sol üst köşesinin koordinatları hesaplanır ve pencere (method setLocation (...)) ekranda belirtilen konumda görüntülenir.

Bundan sonra sistem menüsünde pencereyi kapatırken ne yapacağımızı belirliyoruz; içinde bu durum uygulamanın çalışmasını sonlandırması gerektiği görülebilir (EXIT_ON_CLOSE). Bu kısa ve basit çizginin arkasında aslında olay işlemenin şaşırtıcı derecede ilginç ve merak uyandıran dünyası var. Hemen söyleyelim: Java'daki olay işleme mekanizmasını anlamak, grafik uygulamaların geliştirilmesinde önemli bir andır ve bir sonraki dersten başlayarak, tam olarak bunu yapacağız.

Son olarak, son satır (metod setVisible(true)) pencereyi görünür kılar.

Tabii ki, bazı detayları atlamadık, ancak amacımız her şeyi ve her şeyi tam olarak anlatmak değil - bunun için belgeler, referans kitaplar ve öğreticiler var. Amacımız, (isterseniz ve yeterli azim ile) programlarınızı doğru yönde geliştirebileceğiniz ve gerekli işlevsellik ile doldurabileceğiniz genel bir yön, bir başlangıç ​​noktası vermektir.

Bu dersimizi sonlandırıyor. Ondan almanız gereken en önemli şey miras (ödünç alma) kavramıdır. Bu aslında temel bir kavramdır. Onsuz, Java'da karmaşık ve kullanışlı bir program oluşturamazsınız, bu yüzden devam etmek için zaman ayırın, ancak şimdiye kadar öğrendiğimiz her şeyi dikkatlice gözden geçirin ve üzerinde düşünün.

İyi şanslar ve yakında görüşürüz!

Bu kısa makalede, GUI'yi dilde destekleyen küçük bir program oluşturma sürecini anlatmak istiyorum. Java. Okuyucunun dilin temellerine aşina olduğu varsayılmaktadır. Java.

Ve böylece, hangi araçlara ihtiyacımız var:

  • Java Sanal Makinesi (OpenJDK veya Oracle JDK)
  • Intellij IDEA (veya Java için başka bir IDE)

Gerekli yazılımı kurduktan sonra açın. IntelliJ FİKİR ve yeni bir proje oluşturun: Dosya -> Yeni Proje…

projeye isim verdim guiBase. Ekran görüntüsünde görebileceğiniz gibi, klasör kaynak hiçbir şey içermez, bu yüzden içinde işlevi içeren ana sınıfımızı yaratırız. ana.

Genel sınıf Main ( public static void main(String args) ( System.out.println("Merhaba, Govzalla!"); ) )

Yukarıdaki ana sınıfın içeriğine bakın. Artık bir proje oluşturabiliriz ( proje inşa etmek ) ve çalıştırın ( Koşmak ). Aşağı senin terminalinde IDE bir mesaj göreceksin Merhaba Govzalla!. Ancak sizin anladığınız gibi - GUI'yi desteklemiyor.

Bu aşamada zaten çalışan bir programımız var ama GUI desteği yok. Ve şimdi aynı klasörde kaynak oluşturmak GUI Formu: Yeni -> GUI Formu

Oluşturulan GUI formunu açın, üzerine tıklayın. jPanel ve tanımlayıcısını alana ayarlayın alan adı, Diye sordum panel.

Ardından sağ taraftaki formun üzerine sürükleyip bırakın JTextField, JPasswordField Ve jDüğme:

Geriye kodu eklemek ve formumuzu ona bağlamak kalıyor. Formu eklediğimizde ana pencere, sınıf otomatik olarak oluşturuldu ana pencere, bu sınıf, oluşturulan formun sınıfıdır, yani. bu sınıf, verilen formdaki tüm olaylara hizmet edecektir.

Pencere sınıfımız gerekli öğeleri içermesine rağmen, şimdi bile GUI ile ilgisi yok, bu yüzden onu genişletelim. jÇerçeve ve GUI'nin tüm temel ve gerekli işlevlerini devralır .

İÇİNDE şu an forma sahibiz ana pencere ve sınıf ana pencere ile genişletilmiş jÇerçeve. Şimdi, eklenen tüm GUI öğelerini sınıf içeriği olarak tanımlamamız gerekiyor ana pencere this.getContentPane().add(panel); Bundan sonra MainWindow.java dosyasının içeriği aşağıdaki gibi değiştirilecektir:

javax.swing'i içe aktarın.*; genel sınıf MainWindow, JFrame'i genişletir ( private JTextField textField1; özel JPasswordField passwordField1; özel JButton button1; özel JPanel paneli; genel MainWindow() ( this.getContentPane().add(panel); ) )

Kodu çalıştırmayı denerseniz yine aynı “Merhaba, Govzalla!” mesajını göreceksiniz. Mesele şu ki, bir sınıf ve onun formunu yarattık, ancak bu sınıfın bir örneğini yaratmadık.

Main.java dosyasını değiştirmenin ve GUI'mizi orada oluşturmak için kodu eklemenin zamanı geldi:

java.awt.* dosyasını içe aktarın; public class Main ( public static void main(String args) ( // MainWindow sınıfının bir örneğini oluşturun MainWindow mainWindow = new MainWindow(); // mainWindow.pack() formumuzdaki tüm öğeleri paketleyin; // Pencereyi yeniden boyutlandırın mainWindow.setSize( new Dimension(200, 200)); // Oluşturulan pencereyi görüntüle mainWindow. setVisible(true); ) )

Kodu çalıştırma

Butona tıklayarak programın hiçbir şekilde tepki vermediğini fark edeceksiniz. Mesele şu ki, dinleyiciyi henüz eklemedik ( dinleyici) etkinlikler için ( Olaylar) düğmesi.

olay dinleyicisi ( olay dinleyicisi) jDüğme bir adaptör uygulaması olmalıdır Eylem Dinleyici, bu nedenle aşağıdaki kodu sınıfın gövdesine ekleyin ana pencere:

Özel sınıf MyButtonListener, ActionListener'ı uygular ( @Override public void actionPerformed(ActionEvent actionEvent) ( ) )

Yöntem eylem Gerçekleştirildi() tüm button1 button olaylarını işleyecektir, ancak yine de button1'e hangi sınıfı işleyeceğini söylemeniz gerekir, bu nedenle MainWindow sınıf kurucusuna aşağıdaki kodu ekleyin: this.button1.addActionListener(new MyButtonListener()); İşleyicimizin anlamsız olmaması için metoda aşağıdaki kodu ekleyin. eylem Gerçekleştirildi():

@Override public void actionPerformed(ActionEvent actionEvent) ( if (textField1.getText().equals(passwordField1.getText())) ( JOptionPane.showMessageDialog(null, "Success"); ) else ( JOptionPane.showMessageDialog(null, "Failure) "); ))

Artık program elbette tüm olaylara değil, olaylara doğru yanıt verecektir. Örneğin, çarpı işaretine tıklayarak programı devre dışı bırakmaya çalışırsanız, pencere kaybolacaktır, ancak program çalışmaya devam edecektir, çünkü. ana pencere olay işleyicisi eklenmedi.

Davydov Anton Valerievich
TSU Öğrencisi, Rusya, Tolyatti
Bilim danışmanı: Erofeeva E.A.

Java'daki kullanıcı arayüzü, çok zorlu bir oluşum ve gelişme yolundan geçti. Uzun zamandır sistem kaynakları, yavaş performans ve sınırlı işlevsellik konusunda açgözlü olmakla suçlanıyor. .NET'in daha hızlı grafik bileşenleriyle ortaya çıkışı, Java'nın konumunu daha da sarstı. Ancak bu tür rekabet yalnızca Java geliştiricilerini geliştirmeye ve iyileştirmeye teşvik etti. grafik kitaplıkları. Ve bu yazıda bunun ne olduğunu göreceğiz.

Soyut Pencere Araç Takımı

Soyut Pencere Araç Takımı (kısaca AWT) ilk olarak 1995 yılında Sun Microsystems tarafından piyasaya sürüldü. Java için bir GUI oluşturmaya yönelik ilk girişimdi. AWT, C ile yazılmış kitaplıklardan yöntemleri çağıran bir katman görevi gördü. Bu yöntemler de işletim sisteminin grafik bileşenlerini kullandı. Bir yandan, bu şekilde oluşturulmuş bir program, kullanılan işletim sistemindeki diğer tüm programlara görünüşte benzer görünüyordu, ancak diğer yandan aynı program, farklı işletim sistemlerinde tamamen farklı görünebilir ve bu da geliştirmeyi zorlaştırır. Ek olarak, çoklu platform uğruna, bileşenlerin çağrı arayüzlerini birleştirmek gerekliydi, bu da bir şekilde kesilmiş işlevselliğe yol açtı. Bileşen seti de oldukça mütevazı. Örneğin, tablo yoktur ve simgeler düğmelere yerleştirilemez. AWT, kullanılan kaynakları otomatik olarak serbest bırakmaya çalışır. Bu, performansı etkiler ve mimariyi karmaşıklaştırır. AWT'yi öğrenmesi kolaydır, ancak karmaşık bir şeyler yazmak zordur. Şimdi AWT esas olarak uygulamalar için kullanılıyor. Oracle şu anda geliştiricileri daha güvenli olduğu için Swing'e geçmeye teşvik ediyor.

Şekil.1 - Windows ortamında AWT kullanılarak yazılmış örnek bir program

AWT'den sonra, 1998'de Sun, Swing'i piyasaya sürdü. Tamamen Java ile yazılmıştır ve render için 2D kullanır. Swing, AWT'den çok daha geniş bir bileşen çeşitliliğine sahiptir. Bileşenlerin kendileri, var olandan devralarak oluşturmak çok daha kolay hale geldi. Farklı stiller ve görünümler kullanma yeteneği de tanıtıldı. Ancak, Swing'in ilk sürümlerinin hızı oldukça yavaştı ve bir program yazarken yapılan hatalar işletim sisteminin donmasına bile yol açabilirdi.

Bununla birlikte, öğrenme kolaylığı ve büyük miktarda belgenin mevcudiyeti nedeniyle Swing, Java'daki en popüler GUI haline geldi. Buna dayanarak, görsel olarak karmaşık uygulamalar oluşturmayı daha da kolaylaştıran SwingX ve JGoodies gibi birçok uzantı ortaya çıktı. Tüm modern Java programlama ortamları şunları içerir: grafik düzenleyici Sallanmak. Artık daha modern çerçeveler mevcut olsa da, Swing en popüler olanı olmaya devam ediyor.


Şekil 2 - Swing kullanılarak yazılmış örnek program

Standart Widget Araç Seti

SWT, IBM tarafından Swing'in hala yavaş olduğu bir zamanda ve esas olarak Eclipse programlama ortamını desteklemek için piyasaya sürüldü. AWT gibi, SWT de işletim sistemi bileşenlerini kullanır, ancak farklı platformlar için farklı birlikte çalışabilirlik arayüzleri kullanılır. Bu nedenle, her işletim sistemi için ayrı bir JAR kitaplığı gönderilmelidir. Bu, farklı işletim sistemlerine karşılık gelen işlevleri daha tam olarak kullanmanıza olanak tanır. Ve eksik bileşenler 2D kullanılarak uygulandı. Ancak, SWT'de ustalaşmanın Swing'den daha zor olduğu ortaya çıktı. Ek olarak, programcı, uygulama tarafından kaynakların serbest bırakılmasını kendisi gerçekleştirmelidir.

Şekil.3 - Swing kullanılarak yazılmış örnek program

JavaFX, 2008 yılında Oracle tarafından piyasaya sürüldü. Zengin bir İnternet uygulaması oluşturmak için bir platform olarak konumlandırılmıştır. Oluşturma için, uygulamayı önemli ölçüde hızlandıran bir grafik boru hattı kullanılır. Çok sayıda yerleşik bileşen vardır. Grafikleri çizmek için ayrı bileşenler de vardır. Multimedya içeriği, animasyon ve hatta çoklu dokunma desteği uygulandı. Bileşenlerin görünümü, CSS stilleri kullanılarak yapılandırılır. Ek olarak, JavaFX yardımcı programları seti, en popüler platformlar için yerel bir yükleyici yapma yeteneğini içerir: Windows için exe veya msi, Linux için deb veya rpm, Mac için dmg. Oracle web sitesinde ayrıntılı belgeler ve Büyük sayı hazır örnekler.

Böylece, yukarıdaki grafiksel kullanıcı arayüzlerinin ana özelliklerini ve dezavantajlarını tanımlayarak, hangi görevler için en uygun olduklarına karar verebiliriz. Soyut Pencere Araç Takımı, uygulamalar oluşturmak için daha uygundur. Yeni başlayanlar, Rusça da dahil olmak üzere İnternette bunun için çok sayıda belge bulabileceğiniz gerçeğini göz önünde bulundurarak Swing'i önerebilir. JavaFX, zengin internet uygulamaları oluşturmak için mükemmeldir.

Kullanılan kaynakların listesi

    Ryzhenko A.V. Nesneye yönelik programlama: 010501 - "Uygulamalı Matematik ve Bilişim" uzmanlık alanı disiplini için eğitim ve metodolojik kompleks. – 2007.

    Khabibullin I. Sh. Java 7 (4. baskı). - BHV-Petersburg, 2012.

    Clarke J., Connors J., Bruno E. J. JavaFX: Zengin İnternet Uygulamaları Geliştirme. – Pearson Eğitim, 2009.

    Northover S., Wilson M. Swt: standart widget araç seti, cilt 1. - Addison Wesley Professional, 2004.

Java'daki kullanıcı arayüzü, çok zorlu bir oluşum ve gelişme yolundan geçti. Uzun süre yavaş çalışma, sistem kaynakları için açgözlülük, sınırlı işlevsellik ile suçlandı. .NET'in daha hızlı grafik bileşenleriyle ortaya çıkışı, Java'nın konumunu daha da sarstı. Ancak her bulutun gümüş bir astarı vardır - tüm bu hareketler yalnızca Java geliştiricilerini grafik kitaplıkları geliştirmeye ve iyileştirmeye teşvik etti. Bakalım bundan ne çıktı.

Soyut Pencere Araç Takımı

AWT, Sun'ın Java için bir GUI'deki ilk girişimiydi. Kolay yolu seçtiler ve C ile yazılmış kitaplıklardan metotları çağıran bir Java katmanı yaptılar. Kitaplık metotları, işletim ortamının grafiksel bileşenlerini yaratır ve kullanır. Bir yandan, bir Java programı bu işletim sistemindeki diğer programlara benzer olduğu için bu iyidir. Ancak öte yandan, bileşen boyutlarındaki ve yazı tiplerindeki farklılıkların, farklı bir platformda çalıştırıldığında programın görünümünü bozmayacağının garantisi yoktur. Ek olarak, çoklu platformu sağlamak için bileşenlerin çağrı arayüzlerini birleştirmek gerekiyordu, bu yüzden işlevselliklerinin biraz kısaltıldığı ortaya çıktı. Ve bileşen setinin oldukça küçük olduğu ortaya çıktı. Örneğin, AWT'de tablolar yoktur ve düğmeler simgelerin görüntülenmesini desteklemez.

Kullanılan kaynaklar AWT otomatik olarak serbest bırakmaya çalışır. Bu, mimariyi biraz karmaşıklaştırır ve performansı etkiler. AWT'yi öğrenmek oldukça kolaydır, ancak karmaşık bir şeyler yazmak biraz zor olabilir. Şimdi sadece uygulamalar için kullanılıyor.

Avantajlar:

  • JDK'nın bir parçası;
  • çalışma hızı;
  • grafiksel bileşenler standart bileşenlere benzer.

Dezavantajları:

  • yerel bileşenlerin kullanımı, özelliklerinin kullanımına kısıtlamalar getirir. Bazı bileşenler "yerel olmayan" platformlarda hiç çalışmayabilir;
  • simgeler ve araç ipuçları gibi bazı özellikler AWT'de hiç yoktur;
  • Çok az standart AWT bileşeni vardır, programcının birçok özel bileşeni uygulaması gerekir;
  • program farklı platformlarda farklı görünüyor (çarpık olabilir).

çözüm:

Şu anda, AWT son derece nadiren kullanılmaktadır - özellikle eski projelerde ve uygulamalarda. Oracle öğreticileri gizledi ve Swing'e geçişi şiddetle teşvik ediyor. Bu anlaşılabilir bir durumdur, eksen bileşenlerine doğrudan erişim ciddi bir güvenlik açığı olabilir.

Sallanmak


AWT'nin ardından Sun, Swing adlı bir dizi grafik bileşen geliştirdi. Swing bileşenleri tamamen Java ile yazılmıştır. 2D, aynı anda birçok avantajı beraberinde getiren render için kullanılır. Standart bileşenler seti, çeşitlilik ve işlevsellik açısından AWT'yi çok aşıyor. Mevcut olanlardan miras alarak ve canınız ne istiyorsa onu çizerek yeni bileşenler yaratmak kolaylaştı. Çeşitli stiller ve görünümler için destek mümkün hale geldi. Ancak, Swing'in ilk sürümlerinin hızı arzulanan çok şey bıraktı. Yanlış yazılmış bir program, Windows'u sıkıca kapatabilir.

Bununla birlikte, kullanım kolaylığı, zengin dokümantasyonu ve esnek bileşenleri nedeniyle Swing, Java'daki belki de en popüler grafik çerçevesi haline geldi. Karmaşık kullanıcı arayüzlerinin oluşturulmasını büyük ölçüde basitleştiren SwingX, JGoodies gibi birçok uzantı ortaya çıktı. Hemen hemen tüm popüler Java programlama ortamları, Swing formları için grafik düzenleyiciler içerir. Bu nedenle Swing'i anlamak ve kullanmaya başlamak zor olmayacaktır.

Avantajlar:

  • JDK'nın bir parçası, ek kitaplıklar kurmaya gerek yok;
  • Swing'de daha birçok kitap ve forum yanıtı var. Özellikle yeni başlayanlar için tüm sorunlar Google tarafından iyi bilinmektedir;
  • neredeyse tüm geliştirme ortamlarında yerleşik form düzenleyici;
  • SwingX gibi salıncak tabanlı birçok eklenti var;
  • çeşitli stiller için destek (Bak ve hisset).

Dezavantajları:

  • birçok bileşene sahip bir pencere yavaşlamaya başlar;
  • düzen yöneticileriyle çalışmak karmaşık arayüzlerde gerçek bir kabus olabilir.

Çözüm:

Swing yaşadı, Swing yaşıyor, Swing yaşayacak. Oracle, JavaFX'i tanıtmaya çalışsa da, Swing bugün en popüler Java UI çerçevesi olmaya devam ediyor.

Standart Widget Araç Seti


Nasıl
görünüyor
GBT

SWT, Swing'in hala yavaş olduğu günlerde IBM'de geliştirildi ve esas olarak Eclipse programlama ortamını desteklemek için yapıldı. AWT gibi SWT de işletim sistemi bileşenlerini kullanır, ancak her platform için kendi etkileşim arayüzlerine sahiptir. yani her biri için yeni sistem uygun SWT sürümüyle ayrı bir JAR kitaplığı göndermeniz gerekecek. Bu, her eksendeki bileşenlerin mevcut özelliklerinin daha eksiksiz kullanımına izin verdi. Eksik özellikler ve bileşenler, Swing'de olduğu gibi 2D kullanılarak uygulandı. SWT'nin birçok taraftarı var, ancak dürüst olmak gerekirse, her şeyin istediğimiz kadar basit olmadığı konusunda hemfikir olunamaz. Yeni başlayan biri, aynı Swing'i tanımaktan çok SWT öğrenmek için zaman harcamak zorunda kalacak. Ek olarak, SWT programcıya kaynakları serbest bırakma görevini verir ve bu nedenle, yanlışlıkla bir istisnanın bellek sızıntılarına yol açmaması için kod yazarken özellikle dikkatli olması gerekir.

Avantajlar:

  • işletim sistemi bileşenlerini kullanır - hız daha yüksektir;
  • Eclipse sağlar görsel düzenleyici formlar;
  • kapsamlı belgeler ve birçok örnek;
  • AWT ve Swing bileşenlerini kullanmak mümkündür.

Dezavantajları:

  • her platform için ayrı bir kütüphane sağlanması gereklidir;
  • kaynakların kullanımını sürekli olarak izlemeniz ve bunları zamanında serbest bırakmanız gerekir;
  • Karmaşık mimari, özel bir arayüz uygulamak için yapılan beyhude girişimlerden sonra intihar düşüncelerini uyandırıyor.

Çözüm:

IBM'in denediği görülüyor. Ama çok amatörce çıktı ...

JavaFX


JavaFX, abartısız bir atılım olarak adlandırılabilir. Oluşturma için, uygulamayı önemli ölçüde hızlandıran bir grafik boru hattı kullanılır. Yerleşik bileşenler seti kapsamlıdır, hatta grafik çizmek için ayrı bileşenler bile vardır. Multimedya içeriği, birçok görüntü efekti, animasyon ve hatta çoklu dokunma desteği uygulandı. Tüm bileşenlerin görünümü, CSS stilleri kullanılarak kolayca değiştirilebilir. Ve en iyi yanı, JavaFX'in en popüler platformlar için yerel bir yükleyici yapmanıza izin veren bir dizi yardımcı program içermesidir: Windows için exe veya msi, Linux için deb veya rpm, Mac için dmg. Oracle web sitesinde ayrıntılı belgeler ve çok sayıda hazır örnek bulabilirsiniz. Bu, JavaFX ile programlamayı kolay ve eğlenceli hale getirir.

Avantajlar:

  • grafik boru hattı nedeniyle hızlı çalışma;
  • birçok farklı bileşen;
  • stil desteği;
  • bir program yükleyici oluşturmak için yardımcı programlar;
  • uygulama masaüstü olarak ve tarayıcıda sayfanın bir parçası olarak başlatılabilir.

Dezavantajları:

  • çerçeve hala geliştirilmektedir, bu nedenle çökmeler ve bazı aksaklıklar meydana gelir;
  • JavaFX henüz yaygın olarak kullanılmamaktadır.

Çözüm:

İyi iş, Oracle. Çerçeve sadece olumlu izlenimler bırakıyor. Anlaşılması kolay, yöntemler ve arayüzler mantıklı görünüyor. Tekrar tekrar kullanmak istiyorum!

Pratikte görsel kütüphaneler

SWT: hava durumu widget'ı

En popüler grafik kitaplıklarının yeteneklerini ve onlarla çalışmanın temel ilkelerini göstermek için çeşitli bilgileri görüntüleyen birkaç küçük pencere öğesi yapacağız.

Ve belki de en popüler widget ile başlayalım - uygulanması için SWT'yi seçeceğimiz mevcut hava durumunu gösteren.

Herhangi bir SWT programı, bir Görüntüleme nesnesinin oluşturulmasıyla başlar. Sistem kaynaklarına erişmek için gerekli yöntemleri içeren ve bir olay döngüsü sağlayan bir tür uygulama bağlamı görevi görür. Sonraki adım, eşit derecede önemli Shell nesnesini oluşturmaktır. Kabuk, normal bir işletim sistemi penceresidir. Üst düzey bir pencere oluşturmak için ekran kabuk yapıcısına iletilir.

Ekran görüntüsü = yeni Ekran(); kabuk = yeni Kabuk(görüntüleme, SWT.NO_TRIM);

Widget oluşturduğumuz için standart pencere çerçevesi ve kontrol butonlarını göstermemize gerek yok, bunun için NO_TRIM bayrağını belirledik. Arka plan için bir resim kullanacağız - köşeleri yuvarlatılmış bir dikdörtgen. Prensipte, bir SWT penceresi herhangi bir şekle girebilir. Bu etkiyi elde etmek için Region sınıfını kullanıyoruz. Yapılması gereken tek şey, şeffaf olanları atlayarak arka plan görüntüsündeki tüm görünür noktaları bu sınıfa eklemektir.

Resim yükleme:

Resim resmi = yeni Resim(ekran, "images/bg.png#26759185");

Farklı biçimlerdeki görüntülerde saydamlık farklı şekillerde ayarlanır, dolayısıyla saydam alanlarla ilgili bilgiler de aynı şekilde alınmaz. Bir arka plan alanı oluşturun ve görünen tüm noktaları buraya ekleyin:

Bölge bölgesi = yeni Bölge(); ImageData imageData = image.getImageData(); if (imageData.alphaData != null) ( Rectangle pixel = new Rectangle(0, 0, 1, 1); for (int y = 0; y< imageData.height; y++) { for (int x = 0; x < imageData.width; x++) { if (imageData.getAlpha(x, y) == 255) { pixel.x = imageData.x + x; pixel.y = imageData.y + y; region.add(pixel); } } } } else { ImageData mask = imageData.getTransparencyMask(); Rectangle pixel = new Rectangle(0, 0, 1, 1); for (int y = 0; y < mask.height; y++) { for (int x = 0; x < mask.width; x++) { if (mask.getPixel(x, y) != 0) { pixel.x = imageData.x + x; pixel.y = imageData.y + y; region.add(pixel); } } } }

Pencere şeklini ayarla:

Shell.setRegion(bölge);

Şimdi pencere için bir olay dinleyicisi oluşturmamız gerekiyor. Pencere çizim olayları, fare olayları ve pencerenin ekranda hareket ettirilebilmesi için tuşlara basılmasıyla ilgileneceğiz.

Listener listener = new Listener() ( int startX, startY; public void handleEvent(Event e) ( if (e.type == SWT.KeyDown && e.character == SWT.ESC) ( shell.dispose(); ) if (e.type == SWT.MouseDown && e.button == 1) ( startX = ex; startY = ey; ) if (e.type == SWT.MouseMove && (e.stateMask & SWT.BUTTON1) != 0 ) ( Nokta p = shell.toDisplay(ex, ey); px -= startX; py -= startY; shell.setLocation(p); ) if (e.type == SWT.Paint) ( e.gc.drawImage( image, imageData.x, imageData.y); ) ) );

Yani Esc tuşuna basıldığında pencere kapanacaktır. Pencere alanı üzerinde farenin sol tuşuna bastığınızda, tıklamanın koordinatlarını hatırlayın. Fareyi sol tuşa basılı tutarak hareket ettirirken ekrandaki pencereyi harekete göre hareket ettiriyoruz. Redraw olayında - GC grafik bağlamını kullanarak arka plan resmi çizin.

İlgili pencere olaylarına bir dinleyici atayın:

Shell.addListener(SWT.KeyDown, dinleyici); shell.addListener(SWT.MouseDown, dinleyici); shell.addListener(SWT.MouseMove, dinleyici); shell.addListener(SWT.Paint, dinleyici);

Pencere boyutunu görüntünün boyutuna ayarlayın:

Shell.setSize(imageData.x + imageData.width, imageData.y + imageData.height);

Pencereyi açın ve olay döngüsünü çalıştırın:

Shell.open(); while (!shell.isDisposed ()) ( if (!display.readAndDispatch ()) display.sleep (); )

Sonunda kullanılan kaynakları serbest bırakmayı unutmayın:

bölge.dispose(); image.dispose(); display.dispose();

Bu aşamada programı çalıştırarak mouse ile hareket ettirilebilen ve Esc ile kapatılabilen bir dikdörtgen elde edeceğiz.

İçerik ekleme zamanı. Mevcut hava durumunu bir durum simgesi (güneşli, yağmur, kar ...), sıcaklık okumaları ve son güncellemenin zamanı şeklinde göstereceğiz.

Mizanpaj yöneticileri, penceredeki grafik bileşenleri istenilen biçimde düzenlemek için kullanılır. Düzen yöneticisi yalnızca bileşenlerin düzenlenmesiyle değil, aynı zamanda pencere yeniden boyutlandırıldığında yeniden boyutlandırılmasıyla da ilgilenir. Widget'ımız için GridLayout kullanacağız. Bu yönetici, bileşenleri hayali bir tablonun hücrelerinde düzenler. Farklı sütun genişliklerine sahip iki sütun için bir GridBagLayout oluşturun (kurucuda yanlış bayrak), bunu pencere düzeni yöneticisi olarak ayarlayın:

GridLayout düzeni = new GridLayout(2, false); shell.setLayout(düzen);

Durum görüntüsü için Label bileşenini kullanıyoruz. Pencere nesnesini ebeveyn olarak geçiriyoruz. İkinci parametre, bileşenin stilini ayarlamaktır. Her bileşen için, olası stil bayrakları kümesi farklıdır, bunlar belgede veya doğrudan bileşenin kaynak kodunda bulunabilir.

//durum resmi çizin Label imageLabel = new Label(shell, SWT.NONE); imageLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1));

GridData sınıfındaki bayraklar, etiketin sol üstte konumlandırılacağı, boş alan olduğunda yatay ve dikey olarak uzayacağı (bayraklar true olarak ayarlanır) ve yerleşim tablosunun bir satır ve bir sütununu işgal edeceği anlamına gelir.

SWT'de değil şeffaf arka plan bileşenler ve durum görüntüsünün arkasında beyaz bir arka plan belirecektir, bu da elbette istenmez. Pencerenin arka plan rengiyle bir Color nesnesi oluşturalım:

Renk bgColor = yeni Renk(ekran, 0x2b, 0x2b, 0x2b);

Programın sonunda bu nesne de Dispose yöntemi çağrılarak temizlenmelidir. Bir dosyadan yüklenebilen arka plan rengini ve durum görüntüsünü, başlangıçta arka plan görüntüsünü yüklediğimiz gibi ayarlayın:

ImageLabel.setBackground(bgColor); Resim durumuImage = new Image(ekran, "images/1.png#26759185"); imageLabel.setImage(statusImage);

Şimdi mevcut sıcaklığı içeren bir Etiket ekleyelim ve pencerenin sağ üst kısmına yerleştirelim:

Etiket sıcaklığı Etiket = new Etiket(kabuk, SWT.NONE); sıcaklıkLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false, 1, 1));

Biraz sıcaklık ayarlayalım:

SıcaklıkLabel.setText("+1 \u2103");

Sıcaklığı Celsius cinsinden kaydetmek için, ilgili karakterin Unicode numarası \u hizmet karakterleriyle birlikte kullanılır.

Metin etiketleri için varsayılan yazı tipi çok küçük. Öyleyse yeni, daha büyük bir tane oluşturalım:

FontData fD = sıcaklıkLabel.getFont().getFontData(); fD.setHeight(30); fD.setStyle(SWT.BOLD); Font newFont = new Font(ekran, fD); sıcaklıkLabel.setFont(newFont); Yazı tipi, diğer kaynak nesneleri gibi serbest bırakılmalıdır. Bunu yapmak için etiket imha olay dinleyicisini kullanıyoruz:

SıcaklıkLabel.addDisposeListener(new DisposeListener() ( public void widgetDisposed(DisposeEvent e) ( newFont.dispose(); ) ));

Son olarak hava durumunu anlatan bir etiket ekleyelim:

Etiket açıklamasıLabel = new Label(kabuk, SWT.WRAP); descriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 1)); descriptionLabel.setText("Açıklıklı, hafif yağmurlu"); açıklamaLabel.setBackground(bgColor); açıklamaLabel.setForeground(display.getSystemColor(SWT.COLOR_WHITE));

Metin oldukça uzun olabilir, bu nedenle etiketi oluştururken, yeterli alan olmadığında metnin otomatik olarak birkaç satıra bölünmesi için WRAP bayrağını belirtiriz. Bileşeni ortalayalım ve tüm yatay alanı doldurmasına izin verelim. Ayrıca, bileşenin yerleşim tablosunun iki sütununu kapladığını belirtiyoruz. "Weather Widget" resminden bir pencere başlatıp alıyoruz.

Artık bir tür hava durumu hizmetini bağlayabilir, bunun için bir zamanlayıcı oluşturabilirsiniz. otomatik güncelleme- ve widget hazır.

Salıncak: her zaman taze haberler

Swing'de RSS beslemelerini görüntülemek için bir widget yazacağız. Geçen seferki gibi bir pencere oluşturarak başlıyoruz. Swing'de standart pencere işlevini uygulayan sınıfa JFrame adı verilir. Varsayılan olarak, Swing'de bir uygulama penceresinin kapatılması programın durmasına neden olmaz, bu nedenle pencerenin kapatıldığında nasıl davranacağını belirtmek daha iyidir:

JFrame çerçevesi = yeni JFrame(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

Bir tablo, haberleri sunmak için en iyisidir. Swing, Model-View-Controller (MVC) modeli üzerine inşa edilmiştir. MVC mimarisinde Model verileri sağlar, Görünüm verileri (örneğin metin, giriş alanları) görüntülemekten sorumludur ve Kontrolör Model ile Görünüm arasındaki etkileşimi sağlar. Tablo bu yaklaşımı iyi bir şekilde göstermektedir. Verileri temsil etmek için TableModel arabirimini uygulayan bir sınıf kullanılır.

Mevcut haberler hakkında bilgi depolamak için makale başlığı ve yayın tarihi için alanları olan bir FeedMessage sınıfı oluşturalım:

Genel sınıf FeedMessage ( genel Dize başlığı; genel Tarih yayın Tarihi; )

Geliştirmeyi basitleştirmek ve hızlandırmak için veri modelimizi, TableModel arabiriminin neredeyse tüm yöntemlerinin hazır bir uygulamasını sunan AbstractTableModel sınıfından devralırız.

Genel sınıf RssFeedTableModel, AbstractTableModel'i genişletir (özel Liste girişler = yeni ArrayList<>(); public void updateData(Liste girişler) ( this.entries = input; fireTableDataChanged(); ) public int getRowCount() ( return input.size(); ) public int getColumnCount() ( return 2; ) public Object getValueAt(int rowIndex, int columnIndex) ( switch (columnIndex) ( durum 0: dönüş input.get(rowIndex).title; durum 1: dönüş input.get(rowIndex).publicationDate; ) dönüş null; ) )

fireTableDataChanged yöntemi, görünüme veri modelinin değiştiğini ve yeniden oluşturulması gerektiğini söyler.

Bir tablo oluşturuyoruz ve görünümünü biraz değiştirerek daha çok bir widget gibi görünmesini sağlıyoruz. Satırlar ve sütunlar arasındaki çizgileri kaldırıyoruz, satır yüksekliğini artırıyoruz ve sütun adlarıyla tablo başlığını kaldırıyoruz:

JTable tablosu = new JTable(new RssFeedTableModel()); tablo setiShowGrid(yanlış); table.setIntercellSpacing(new Dimension(0, 0)); tablo setiRowHeight(30); table.setTableHeader(null);

Şimdi meşgul olalım görünüm hücreler. Swing, bireysel görünüm sınıfları atamanıza izin verir. farklı şekiller veri. TableCellRenderer arabirimini devralan sınıf, tek tek tablo hücrelerinin işlenmesinden sorumludur. Varsayılan, bir metin etiketi olan DefaultTableCellRenderer'dır.

Hücre oluşturucumuzu String verilerine atayalım. Varsayılan yazı tipi rengini değiştirelim ve okunabilirliği artırmak için arka plan rengini alternatif yapalım.

Table.setDefaultRenderer(String.class, new DefaultTableCellRenderer() ( Color oddColor = new Color(0x25, 0x25, 0x25); Color EvenColor = new Color(0x1a, 0x1a, 0x1a); Color titleColor = new Color(0x3a, 0xa2, 0xd7) ); public Bileşen getTableCellRendererComponent(JTable tablosu, Object değeri, boolean isSelected, boolean hasFocus, int satır, int sütun) ( super.getTableCellRendererComponent(table, value, isSelected, hasFocus, satır, sütun); setBackground(satır 2 == 0 ?oddColor:evenColor); setForeground(titleColor); setFont(font); bunu döndür; ) ));

Tablonun oluşturucumuzu kullanmaya başlaması için, her hücrenin veri türünü veri modeline döndüren bir yöntem eklememiz gerekiyor:

Kamusal sınıfgetColumnClass(int columnIndex) ( switch (columnIndex) ( case 0: return String.class; case 1: return Date.class; ) return Object.class; )

Çok fazla haber olabilir, o yüzden kaydırma çubuğuna tabloyu koyalım ve widget tasarımımızı bozmamak için kaydırma çubuğunu görünmez yapalım:

JScrollPane scrollPane = new JScrollPane(tablo); table.setFillsViewportHeight(true); scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(0,0));

Pencerenin ana bölmesine kaydırma bileşeni ekleme. İkinci argüman, bileşenin konumu olabilir. Varsayılan olarak, bir pencerenin ana bölmesi, bileşenleri ana yönlere göre yerleştiren BorderLayout yerleşim yöneticisini kullanır. Ortaya kaydırmalı tabloyu yerleştirelim.

Frame.getContentPane().add(scrollPane, BorderLayout.CENTER);

Geçen seferki gibi standart pencere çerçevesini kaldıracağız. Ve pencerenin başlığı olarak, pencerenin en üstüne yerleştireceğimiz stilize bir metin etiketi kullanacağız.

JLabel titleLabel = new JLabel("Xakep RSS"); Font titleFont = new Font("Arial", Font.BOLD, 20); titleLabel.setFont(titleFont); titleLabel.setHorizontalAlignment(SwingConstants.CENTER); titleLabel.setForeground(Color.WHITE); titleLabel.setPreferredSize(yeni Boyut(0, 40)); frame.getContentPane().add(titleLabel, BorderLayout.NORTH);

SWT'den farklı olarak, "renk" ve "yazı tipi" nesneleri otomatik olarak ayrılır, böylece artık bellek sızıntıları konusunda endişelenmenize gerek kalmaz.

Pencerenin ekranda hareket ettirilebilmesi için fare dinleyicileri ekliyoruz.

MouseAdapter dinleyici = new MouseAdapter() ( int startX; int startY; public void mousePressed(MouseEvent e) ( if (e.getButton() == MouseEvent.BUTTON1) ( startX = e.getX(); startY = e.getY( ); ) ) public void mouseDragged(MouseEvent e) ( Point currCoords = e.getLocationOnScreen(); frame.setLocation(currCoords.x - startX, currCoords.y - startY); ) ); titleLabel.addMouseListener(dinleyici); titleLabel.addMouseMotionListener(dinleyici);

Şimdi pencerenin şeklini köşeleri yuvarlatılmış bir dikdörtgene dönüştürün. Bunu bileşenin dinleyicisinde yapmak en iyisidir, çünkü pencere boyutu değişirse pencerenin şekli doğru şekilde yeniden hesaplanır:

Frame.addComponentListener(new ComponentAdapter() ( public void componentResize(ComponentEvent e)) ( frame.setShape(new RoundRectangle2D.Double(0, 0, frame.getWidth(), frame.getHeight(), 20, 20)); ) ) );

Pencerenin boyutunu ayarlayın, çerçeveyi çıkarın ve pencereyi yarı saydam yapın.

Frame.setSize(520, 300); frame.setDekorasyonsuz(true); çerçeve.setOpacity(0.85f);

Son olarak, grafik dizisinde bir pencere açıyoruz. SwingUtilities.invokeLater(new Runnable() ( public void run() ( frame.setVisible(true); ) ));

Ayrı bir konuya veri yükleme eklemeye devam ediyor ve en sevdiğiniz dergiden en son haberleri içeren böyle bir widget alacağız :).


JavaFX: Hadi müzik dinleyelim

Ve son olarak, sezonun öne çıkan özelliği JavaFX. Multimedya yeteneklerini ve grafik bileşenini kullanalım ve basit bir ekolayzır yapalım.

İlk olarak, widget sınıfını Uygulama'dan devralırız. Bu, JavaFX'teki ana uygulama sınıfıdır. Uygulama ana yöntemleri içerir yaşam döngüsü uygulamalar. Form bileşenleri, argümanı Stage sınıfı olan start yönteminde oluşturulur. Stage, programın penceresini temsil eder. Kenarlığı ve düğmeleri kaldırmak için pencere stilini ŞEFFAF olarak değiştirin. Stage sınıfı, pencerenin boyutunu ve arka plan rengini ayarlayan Scene sınıfını içerir. Scene'de ise alt bileşenleri yerleştireceğimiz Group sınıfını geçiyoruz:

Public void start(Stage birincilStage) ( birincilStage.initStyle(StageStyle.TRANSPARENT); Grup kökü = yeni Grup(); Sahne sahnesi = new Scene(kök, 400, 200, Color.TRANSPARENT); PrimaryStage.setScene(scene);

Ekolayzırı görüntülemek için eksenleri boyunca frekansı ve ses gücünü göstereceğimiz bir çubuk grafik kullanıyoruz:

KategoriAxis xAxis = yeni KategoriAxis(); NumberAxis yAxis = yeni NumberAxis(0,50,10); BarChart bc = yeni BarChart (xEksen,yEksen); bc.setPrefSize(400, 200); bc.setLegendVisible(yanlış); bc.setAnimated(yanlış); bc.setBarGap(0); bc.setCategoryGap(1); bc.setVerticalGridLinesVisible(yanlış); bc.setHorizontalGridLinesVisible(yanlış); xAxis.setLabel("Sıklık"); yAxis.setLabel("Güç"); yAxis.setTickLabelFormatter(yeni NumberAxis.DefaultFormatter(yAxis, null, "dB"));

Diyagramı ilk verilerle doldurun:

XYChart.Serisi series1 = yeni XYChart.Series (); series1Data = yeni XYChart.Data; Dize kategorileri = yeni Dize; for (int i=0; ben (kategoriler[i], 50); series1.getData().add(series1Data[i]); ) bc.getData().add(series1);

Widget'a uygun şekli vermek için köşeleri yuvarlatılmış bir dikdörtgen oluşturun:

Dikdörtgen dikdörtgen = yeni Dikdörtgen(0, 0, 400, 200); Durdurma durakları = yeni Durdur ( new Stop(0, new Color(0, 0, 0, 0.8))), null); LinearGradient lg2 = new LinearGradient(0, 0, 0, 0, false, CycleMethod.NO_CYCLE, durur); dikdörtgen.setFill(lg2); dikdörtgen.setArcHeight(20); rectangle.setArcWidth(20);

Her iki bileşeni de gruba ekleyin:

Root.getChildren().addAll(dikdörtgen, bc);

Pencereyi ekranda hareket ettirmek için gruba fare dinleyicileri atayın:

Root.setOnMousePressed(yeni EventHandler () ( public void tanıtıcı(MouseEvent ben) ( initX = me.getScreenX() - birincilStage.getX(); initY = me.getScreenY() - birincilStage.getY(); ) )); root.setOnMouseDragged(yeni EventHandler () ( public void tanıtıcı(MouseEvent ben) ( birincilStage.setX(me.getScreenX() - initX); birincilStage.setY(me.getScreenY() - initY); ) ));

Şarkıyı oynatıcıya indirin:

Dosya dosyası = new File("beni buradan çıkar.mp3"); medya audioMedia = boş; audioMedia = new Media(file.toURI().toURL().toString()); audioMediaPlayer = new MediaPlayer(audioMedia);

Çubuk grafiği güncelleyecek bir dinleyici ekleyin:

AudioMediaPlayer.setAudioSpectrumListener(new AudioSpectrumListener() ( genel geçersiz spektrumDataUpdate(çift zaman damgası, çift süre, kayan büyüklükler, kayan fazlar) ( için (int i = 0; i)< series1Data.length; i++) { series1Data[i].setYValue(magnitudes[i] + 60); } } });

Sahneyi görünür yapın ve şarkıyı çalın:

PrimaryStage.show(); audioMediaPlayer.play();

Uygulamayı başlatıyoruz:

Public static void main(String args) ( launch(args); )

Ve bu güzelliğin tadını çıkarın.