Huśtawka (Java)

Przykładowe widżety Swing w Javie

Swing to zestaw narzędzi widżetów GUI dla języka Java . Jest częścią Java Foundation Classes (JFC) firmy Oracle — interfejsu API zapewniającego graficzny interfejs użytkownika (GUI) dla programów Java.

Swing został opracowany w celu zapewnienia bardziej wyrafinowanego zestawu komponentów GUI niż wcześniejszy zestaw narzędzi Abstract Window Toolkit (AWT) . Swing zapewnia wygląd i sposób działania emulujący wygląd i sposób działania kilku platform, a także obsługuje podłączany wygląd i sposób działania , który umożliwia aplikacjom wygląd i sposób działania niezwiązany z podstawową platformą. Ma mocniejsze i bardziej elastyczne komponenty niż AWT. Oprócz znanych komponentów, takich jak przyciski, pola wyboru i etykiety, Swing udostępnia kilka zaawansowanych komponentów, takich jak panel z kartami, panele przewijania, drzewa, tabele i listy.

W przeciwieństwie do komponentów AWT, komponenty Swing nie są implementowane przez kod specyficzny dla platformy. Zamiast tego są napisane w całości w Javie i dlatego są niezależne od platformy.

W grudniu 2008 roku firma Sun Microsystems (poprzednik Oracle) wydała framework oparty na CSS / FXML , który miał być następcą Swinga, o nazwie JavaFX .

Historia

Internet Foundation Classes (IFC) to biblioteka graficzna dla języka Java, pierwotnie opracowana przez Netscape Communications Corporation i wydana po raz pierwszy 16 grudnia 1996 r. 2 kwietnia 1997 r. firmy Sun Microsystems i Netscape Communications Corporation ogłosiły zamiar włączenia IFC do innych technologii w celu tworzą klasy Java Foundation . „Java Foundation Classes” zostały później przemianowane na „Swing”.

Swing wprowadził mechanizm, który umożliwiał zmianę wyglądu i sposobu działania każdego komponentu aplikacji bez wprowadzania istotnych zmian w kodzie aplikacji. Wprowadzenie obsługi podłączanego wyglądu i sposobu działania umożliwia komponentom Swing naśladowanie wyglądu komponentów natywnych przy jednoczesnym zachowaniu korzyści płynących z niezależności platformy. Pierwotnie dystrybuowany jako biblioteka do pobrania oddzielnie, Swing jest częścią Java Standard Edition od wersji 1.2. Klasy i komponenty Swing są zawarte w pakiecie javax.swing hierarchia.

Rozwój następcy Swinga, JavaFX , rozpoczął się w 2005 roku i został oficjalnie zaprezentowany dwa lata później na JavaOne 2007. JavaFX był open source w 2011 roku, aw 2012 roku stał się częścią pakietu Oracle JDK do pobrania. JavaFX zastępuje Swing ze względu na kilka zalet, w tym mniejszą wagę, styl CSS , eleganckie elementy sterujące oraz użycie FXML i Scene Builder. W 2018 roku JavaFX został włączony do OpenJDK w ramach projektu OpenJFX, aby zwiększyć tempo jego rozwoju.

Członkowie zespołu Java Client, który był odpowiedzialny za Swing, to James Gosling (architekt), Rick Levenson (menedżer), Amy Fowler i Hans Muller (kierownicy techniczni), Tom Ball, Jeff Dinkins, Georges Saab, Tim Prinzing, Jonni Kanerva oraz Jeannette Hung i Jim Graham (grafika 2D).

Architektura

Swing to niezależna od platformy platforma GUI „ model-view-controller ” dla Javy, która jest zgodna z jednowątkowym modelem programowania. Dodatkowo ta struktura zapewnia warstwę abstrakcji między strukturą kodu a graficzną prezentacją GUI opartego na Swingu.

Podwaliny

Swing jest niezależny od platformy, ponieważ jest w całości napisany w Javie. Pełną dokumentację dla wszystkich klas Swing można znaleźć w przewodniku Java API Guide for Version 6 lub Java Platform Standard Edition 8 API Specification for Version 8.

Rozciągliwy

Swing to wysoce modułowa architektura, która pozwala na „podłączanie” różnych niestandardowych implementacji określonych interfejsów ramowych: Użytkownicy mogą dostarczać własne niestandardowe implementacje tych komponentów, aby zastąpić domyślne implementacje za pomocą mechanizmu dziedziczenia Java za pośrednictwem LookAndFeel .

Swing to platforma oparta na komponentach , której wszystkie komponenty ostatecznie wywodzą się z klasy JComponent . Obiekty Swing asynchronicznie uruchamiają zdarzenia, mają powiązane właściwości i reagują na udokumentowany zestaw metod specyficznych dla komponentu. Komponenty Swing to JavaBeans , zgodne ze specyfikacją JavaBeans .

Konfigurowalny

Duża zależność Swing od mechanizmów wykonawczych i pośrednich wzorców kompozycji pozwala mu reagować w czasie wykonywania na fundamentalne zmiany w jego ustawieniach. Na przykład aplikacja oparta na Swingu może wymieniać interfejs użytkownika podczas pracy. Co więcej, użytkownicy mogą zapewnić własną implementację wyglądu i stylu, co pozwala na jednolite zmiany w wyglądzie i działaniu istniejących aplikacji Swing bez żadnych programistycznych zmian w kodzie aplikacji.

Lekki interfejs użytkownika

Wysoki poziom elastyczności Swing znajduje odzwierciedlenie w jego nieodłącznej zdolności do zastąpienia kontrolek GUI natywnego systemu operacyjnego hosta w celu wyświetlania samego siebie. Swing „maluje” swoje elementy sterujące przy użyciu interfejsów API Java 2D, zamiast wywoływać natywny zestaw narzędzi interfejsu użytkownika. W związku z tym komponent Swing nie ma odpowiedniego natywnego komponentu GUI systemu operacyjnego i może renderować się w dowolny sposób, jaki jest możliwy z bazowymi graficznymi interfejsami GUI.

Jednak w swej istocie każdy komponent Swing opiera się na kontenerze AWT , ponieważ JComponent (Swing) rozszerza kontener (AWT). Dzięki temu Swing może podłączyć się do struktury zarządzania GUI systemu operacyjnego hosta, w tym do kluczowych mapowań urządzenia/ekranu i interakcji użytkownika, takich jak naciśnięcia klawiszy lub ruchy myszy. Swing po prostu „transponuje” swoją własną (niezależną od systemu operacyjnego) semantykę na bazowe (specyficzne dla systemu operacyjnego) komponenty. Na przykład każdy komponent Swing maluje swoją wersję na urządzeniu graficznym w odpowiedzi na wywołanie metody component.paint(), która jest zdefiniowana w kontenerze (AWT). Ale w przeciwieństwie do komponentów AWT, które delegowały malowanie do widżetu „ciężkiego” natywnego dla systemu operacyjnego, komponenty Swing są odpowiedzialne za własne renderowanie.

Ta transpozycja i oddzielenie nie jest jedynie wizualna i rozciąga się na zarządzanie i stosowanie przez Swing własnej semantyki niezależnej od systemu operacyjnego dla zdarzeń uruchamianych w ramach jego hierarchii zawierania komponentów. Ogólnie rzecz biorąc, architektura Swing deleguje zadanie mapowania różnych smaków semantyki GUI systemu operacyjnego na prosty, ale uogólniony wzorzec do kontenera AWT. Opierając się na tej uogólnionej platformie, ustanawia własną bogatą i złożoną semantykę GUI w postaci modelu JComponent .

Luźno powiązane i MVC

Biblioteka Swing w dużym stopniu wykorzystuje wzorzec projektowy oprogramowania model-view-controller , który koncepcyjnie oddziela przeglądane dane od elementów sterujących interfejsu użytkownika, za pomocą których są przeglądane. Z tego powodu większość komponentów Swing ma powiązane modele (które są określone w terminach interfejsów Java ), a programiści mogą korzystać z różnych domyślnych implementacji lub dostarczać własne. Ramy zapewniają domyślne implementacje interfejsów modelu dla wszystkich jego konkretnych komponentów. Typowe użycie frameworka Swing nie wymaga tworzenia niestandardowych modeli, ponieważ framework zapewnia zestaw domyślnych implementacji, które domyślnie są przejrzyście powiązane z odpowiednim JComponent klasa potomna w bibliotece Swing. Ogólnie rzecz biorąc, tylko złożone komponenty, takie jak tabele, drzewa, a czasem listy, mogą wymagać implementacji niestandardowego modelu wokół struktur danych specyficznych dla aplikacji. Aby dobrze zrozumieć potencjał, jaki umożliwia architektura Swing, rozważmy hipotetyczną sytuację, w której niestandardowe modele tabel i list są nakładkami na DAO i/lub EJB .

Zazwyczaj obiekty modelu komponentu Swing są odpowiedzialne za zapewnienie zwięzłego interfejsu definiującego wyzwalane zdarzenia i dostępne właściwości dla (koncepcyjnego) modelu danych do użytku przez powiązany JComponent. Biorąc pod uwagę, że ogólny wzorzec MVC jest luźno powiązanym wzorcem relacji między obiektami, model zapewnia programistyczne środki do dołączania detektorów zdarzeń do obiektu modelu danych. Zazwyczaj zdarzenia te są zorientowane na model (np. zdarzenie „wstawienia wiersza” w modelu tabeli) i są odwzorowywane przez specjalizację JComponent na znaczące zdarzenie dla komponentu GUI.

Na przykład JTable ma model o nazwie TableModel , który opisuje interfejs umożliwiający dostęp tabeli do danych tabelarycznych. Domyślna implementacja tego działa na dwuwymiarowej tablicy .

Komponent widoku Swing JComponent jest obiektem używanym do graficznego przedstawienia koncepcyjnego elementu sterującego GUI. Swing, jako framework GUI, wyróżnia się tym, że polega na programowo renderowanych kontrolkach GUI (w przeciwieństwie do używania kontrolek GUI natywnego systemu operacyjnego hosta). Przed aktualizacją Java 6 Update 10 to rozróżnienie było źródłem komplikacji podczas mieszania kontrolek AWT, które używają kontrolek natywnych, z kontrolkami Swing w GUI (patrz Mieszanie komponentów AWT i Swing ).

Wreszcie, jeśli chodzi o kompozycję wizualną i zarządzanie, Swing preferuje układy względne (które określają relacje pozycyjne między komponentami) w przeciwieństwie do układów bezwzględnych (które określają dokładną lokalizację i rozmiar komponentów). To odchylenie w kierunku „płynnego” porządku wizualnego wynika z jego pochodzenia w apletów , w którym zaprojektowano i opracowano oryginalny zestaw narzędzi Java GUI. (Pod względem koncepcyjnym ten pogląd na zarządzanie układem jest dość podobny do tego, który informuje o renderowaniu zawartości HTML w przeglądarkach i dotyczy tego samego zestawu problemów, które motywowały ten pierwszy).

Stosunek do AWT

Hierarchia klas AWT i Swing

Od wczesnych wersji Javy część pakietu Abstract Window Toolkit (AWT) udostępnia niezależne od platformy interfejsy API dla komponentów interfejsu użytkownika. W AWT każdy komponent jest renderowany i kontrolowany przez natywny komponent równorzędny, specyficzny dla podstawowego systemu okienkowego.

Z kolei komponenty Swing są często opisywane jako lekkie , ponieważ nie wymagają alokacji natywnych zasobów w zestawie narzędzi okienkowych systemu operacyjnego. Komponenty AWT są określane jako komponenty wagi ciężkiej .

Znaczna część Swing API jest na ogół komplementarnym rozszerzeniem AWT, a nie bezpośrednim zamiennikiem. W rzeczywistości każdy lekki interfejs Swing ostatecznie istnieje w dużym komponencie AWT, ponieważ wszystkie komponenty najwyższego poziomu w Swing ( JApplet , JDialog , JFrame i JWindow ) rozszerzają kontener najwyższego poziomu AWT. Przed aktualizacją Java 6 Update 10 używanie zarówno lekkich, jak i ciężkich komponentów w tym samym oknie było generalnie odradzane ze względu na kolejność Z niezgodności. Jednak późniejsze wersje Javy rozwiązały te problemy, a komponenty Swing i AWT mogą być teraz używane w jednym GUI bez problemów z kolejnością Z.

Podstawową funkcjonalność renderowania używaną przez Swing do rysowania jego lekkich komponentów zapewnia Java 2D , inna część JFC.

Stosunek do SWT

Standard Widget Toolkit (SWT) to konkurencyjny zestaw narzędzi pierwotnie opracowany przez IBM , a obecnie utrzymywany przez społeczność Eclipse . Implementacja SWT ma więcej wspólnego z ciężkimi komponentami AWT. Zapewnia to korzyści, takie jak dokładniejsza wierność bazowemu natywnemu zestawowi narzędzi okienkowych, kosztem zwiększonej ekspozycji na natywną platformę w modelu programistycznym.

Odbyła się znacząca debata i spekulacje na temat wydajności SWT kontra Swing; niektórzy sugerowali, że duża zależność SWT od JNI spowalniałaby, gdy komponent GUI i Java musiałyby komunikować się z danymi, ale szybciej renderowałaby się, gdy model danych został załadowany do GUI, ale tak czy inaczej nie zostało to potwierdzone. Dość dokładny zestaw testów porównawczych z 2005 roku wykazał, że ani Swing, ani SWT nie uzyskały wyraźnie lepszych wyników w ogólnym przypadku.

Przykłady

Witaj świecie

Ta przykładowa aplikacja Swing tworzy pojedyncze okno z komunikatem „Witaj, świecie!” wewnątrz:


 

     
      
        
        
         
        
        
     // Hello.java (Java SE 8)  import  javax.swing.*  ;  klasa  publiczna  Hello  rozszerza  JFrame  {  public  Hello  ()  {  super  (  "Hello World"  );  setDefaultCloseOperation  (  WindowConstants  .  EXIT_ON_CLOSE  );  dodaj  (  nowy  JLabel  (  "Witaj, świecie!"  ));  paczka  ();  setVisible  (  prawda  );  } 

         
        
    
 public  static  void  main  (  String  []  args  )  {  SwingUtilities  .  invokeLater  (  Witaj  ::  nowy  );  }  } 

Pierwszy import obejmuje wszystkie publiczne klasy i interfejsy z pakietu javax.swing .

Klasa Hello jest rozszerzeniem klasy JFrame ; klasa JFrame implementuje okno z paskiem tytułu i zamkniętą kontrolą .

Konstruktor Hello() inicjuje ramkę, najpierw wywołując konstruktor nadklasy, przekazując parametr „hello” , który jest używany jako tytuł okna. Następnie wywołuje setDefaultCloseOperation(int) odziedziczoną z JFrame , aby ustawić domyślną operację, gdy kontrolka zamykania na pasku tytułu jest wybrana na WindowConstants.EXIT_ON_CLOSE – powoduje to, że JFrame do usunięcia, gdy ramka jest zamknięta (w przeciwieństwie do zwykłego ukrycia), co pozwala wirtualnej maszynie Java na wyjście i zakończenie programu. Następnie tworzona jest etykieta JLabel dla ciągu „Witaj, świecie!” a metoda add(Component) odziedziczona z klasy nadrzędnej Container jest wywoływana w celu dodania etykiety do ramki. Metoda pack() odziedziczona z nadklasy Window jest wywoływana w celu określenia rozmiaru okna i rozplanowania jego zawartości.

Metoda main() jest wywoływana przez wirtualną maszynę Java podczas uruchamiania programu. Tworzy instancję nowej ramki Hello i powoduje jej wyświetlenie przez wywołanie metody setVisible(boolean) odziedziczonej z nadklasy Component z parametrem boolowskim true . Kod wykorzystuje invokeLater(Runnable) do wywołania konstruktora z wątku wysyłającego zdarzenia AWT w celu zapewnienia wykonania kodu w sposób bezpieczny dla wątków sposób. Po wyświetleniu ramki wyjście z main nie powoduje zakończenia działania programu, ponieważ wątek wysyłania zdarzeń pozostaje aktywny, dopóki wszystkie okna najwyższego poziomu Swing nie zostaną usunięte.

Okno z guzikiem

Podstawowy przykładowy kod działający w systemie Windows 7

Poniżej przedstawiono dość prosty program oparty na Swingu. Wyświetla okno (JFrame ) zawierające etykietę i przycisk.

 
 
 
 
 
 
 
     
      
       
        
          importuj  java.awt.FlowLayout  ;  import  javax.swing.JButton  ;  importuj  javax.swing.JFrame  ;  importuj  javax.swing.JLabel  ;  import  javax.swing.WindowConstants  ;  importuj  javax.swing.SwingUtilities  ;  klasa  publiczna  SwingExample  implementuje  Runnable  {  private  JFrame  f  ;  public  SwingExample  ()  {  // Utwórz okno  f  =   
        
        
        
         
        
          nowa  ramka JFrame  (  "Witaj świecie!"  );  // Ustawia zachowanie po zamknięciu okna  f  .  setDefaultCloseOperation  (  WindowConstants  .  EXIT_ON_CLOSE  );  // Dodaj menedżera układu, aby przycisk nie znajdował się na górze etykiety  f  .  setLayout  (  nowy  FlowLayout  ());  // Dodaj etykietę i przycisk  f  .  dodaj  (  nowy  JLabel  (  "Witaj, świecie!" 
            
    

    
       
        
        
        
        
    
 
         ));  fa  .  add  (  new  JButton  (  "Naciśnij mnie!"  ));  }  @Override  public  void  run  ()  {  // Ułóż komponenty w oknie  f  .  paczka  ();  // Domyślnie okno jest niewidoczne. Uczyń to widocznym.   fa  .  setVisible  (  prawda  );  }  public  static  void  main  (  String  []  args  
        
         
    

 )  {  // Planuje uruchomienie aplikacji we właściwym czasie w kolejce zdarzeń.  SwingUtilities  .  invokeLater  (  nowy  SwingExample  ());  }  } 

Zwróć uwagę, jak całe tworzenie instancji i obsługa komponentów Swing odbywa się poprzez utworzenie instancji klasy, która implementuje interfejs Runnable. Jest to następnie uruchamiane w wątku wysyłania zdarzeń przy użyciu metody SwingUtilities.invokeLater(Runnable) ), utworzonej w metodzie main (zobacz Swing i bezpieczeństwo wątków ). Chociaż kod Swing można uruchomić bez użycia tej techniki (na przykład nie implementując Runnable i przenosząc wszystkie polecenia z metody run do metody main), uważa się, że jest to dobra forma, ponieważ Swing nie jest bezpieczny dla wątków , co oznacza, że ​​wywoływanie zasobów z wielu wątków może spowodować zakłócenia wątków i błędy spójności pamięci.

Inny przykład

W tym przykładzie niech javax.swing.JFrame będzie super klasą i doda do niej własne widżety (w tym przypadku JButton).

 
 
 
 

 
 

     
	      

	   importuj  javax.swing.JFrame  ;  import  javax.swing.JButton  ;  importuj  javax.swing.JOptionPane  ;  importuj  javax.swing.SwingUtilities  ;  import  java.awt.event.ActionListener  ;  import  java.awt.event.ActionEvent  ;  klasa  publiczna  Próbka  rozszerza  JFrame  {  prywatny  końcowy  JButton  b  =  nowy  JButton  ();  próbka  publiczna  ()  { 
		
		
		
		   
		
		
		 super  ();  to  .  setTitle  (  "HelloApp"  );  to  .  getContentPane  ().  setLayout  (  null  );  to  .  setBounds  (  100  ,  100  ,  180  ,  140  );  to  .  dodaj  (  makeButton  ());  to  .  setVisible  (  prawda  );  to  . 
	

	   
		
		   
		  
			   setDefaultCloseOperation  (  EXIT_ON_CLOSE  );  }  prywatny  JButton  makeButton  ()  {  b  .  setText  (  "Kliknij mnie!"  );  b  .  setBounds  (  40  ,  40  ,  100  ,  30  );  b  .  addActionListener  (  nowy  ActionListener  ()  {  public  void  actionPerformed  (  ActionEvent   
				 
			
		
		 
	

	        
		
		  e  )  {  JOptionPane  .  showMessageDialog  (  b  ,  "Witaj świecie!"  );  }  });  powrót  b  ;  }  public  static  void  main  (  String  []  args  )  throws  InvocationTargetException  ,  InterruptedException  {  // Wywołania Swing muszą być uruchamiane przez wątek wywołujący zdarzenie.  SwingUtilities  .  invokeAndWait  (()  ->   
	
 nowa  próbka  ());  }  } 

Układ jest ustawiany na null przy użyciu metody Container.setLayout(LayoutManager), ponieważ JFrame używa java.awt.BorderLayout jako domyślnego menedżera układu. Dzięki BorderLayout wszystko, co jest dodawane do kontenera, jest umieszczane na środku i rozciągane, aby pomieścić inne widżety. Oczywiście większość rzeczywistych aplikacji GUI wolałaby używać menedżera układu zamiast umieszczać wszystko na bezwzględnych współrzędnych.

Zobacz też

Cytaty

Źródła

Linki zewnętrzne