Aplikacje w Javie wykład 12 Programowanie GUI



Podobne dokumenty
Programowanie w środowisku graficznym- wykład 9 Programowanie GUI cz1

Programowanie graficznych interfejsów użytkownika

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Aplikacje w Javie wykład 12 Programowanie GUI

Programowanie zdarzeniowe

Podstawy Języka Java

Java - interfejs graficzny

Kontenery i komponenty graficzne

Programowanie zdarzeniowe

Programowanie obiektowe

Programowanie graficznego interfejsu użytkownika. Wykład 8. Maciej Wołoszyn 10 maja 2006

Tworzenie elementów graficznych

Informatyka I. Interfejs GUI wysokiego poziomu. Biblioteka Swing. Programowanie zdarzeniowe. Politechnika Warszawska Wydział Transportu 2018

Programowanie w Javie Wykład 6 Okienka w Javie (AWT)

Graphic User Interfaces pakiet Swing

Kurs programowania. Wykład 4. Wojciech Macyna. 23 marca 2016

Język JAVA podstawy. Wykład 5, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Podstawy Swing. Tomasz Borzyszkowski

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

SWING. dr Jarosław Skaruz

PROGRAMOWANIE APLIKACJI MULTIMEDIALNYCH

Marcin Luckner Warsaw University of Technology Faculty of Mathematics and Information Science

Tworzenie i obsługa graficznego interfejsu uŝytkownika

Informatyka i Ekonometria Programowanie komputerów Ćwiczenia Tworzenie aplikacji wykorzystaniem graficznego interfejsu użytkownika - Swing.

Marcin Luckner Warsaw University of Technology Faculty of Mathematics and Information Science

Klasy abstrakcyjne. Klasę abstrakcyjną tworzymy przy pomocy modyfikatora abstract

Java biblioteka Swing

Java niezbędnik programisty spotkanie nr 12. Graficzny interfejs użytkownika

Materiał pomocniczy do kursu Podstawy programowania Autor: Grzegorz Góralski ggoralski.com

SWING ZAGADNIENIA: wprowadzenie, kontenery I komponenty, LayoutManager, komponenty tekstowe.

JAVA. Strumienie wejścia i wyjścia. Pliki - zapis i odczyt

Grafika i komunikacja człowiek komputer Laboratorium. Część 1: Wstęp do grafiki

Programowanie Obiektowe GUI

Dokumentacja do API Javy.

GUI - projektowanie interfejsów cz. II

Visual Studio instalacja

Dodanie nowej formy do projektu polega na:

Ćwiczenia 9 - Swing - część 1

Architektura interfejsu użytkownika

Rysowanie prostych obiektów graficznych przy użyciu biblioteki AWT (Abstract Window Toolkit)

Obsługa zdarzeń w JAVIE ((ActionListener,ItemListener,TableModelListener))

PWŚG Ćwiczenia 13. Ukończoną pracę należy przesłać na adres lub

Aplikacje w Javie- wykład 11 Wątki-podstawy

Język JAVA podstawy. Wykład 5, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Programowanie w języku JAVA. Wykład IV Swing - GUI

Programowanie w języku Java WYKŁAD

Programowanie obiektowe

JAVA CZ.2 Programowanie obiektowe. poniedziałek, 20 kwietnia 2009

Sposoby tworzenia projektu zawierającego aplet w środowisku NetBeans. Metody zabezpieczenia komputera użytkownika przed działaniem apletu.

Zaawansowane programowanie obiektowe. Wykład 3 część 2

JAVA Materiały do laboratorium III wersja niezaawansowana Marcin Borkowski WSEiZ czerwiec 2006

Interaktywne aplety obsługa zdarzeń, uruchamianie apletu przez przeglądarkę lub maszynę wirtualną Javy. Tworzenie łącz w apletach

Kurs programowania 2 - listy

SWING c.d. przydatne narzędzia: JFileChooser, JOptionPane. drag'n drop, menu kontekstowe.

Programowanie graficznych interfejsów uŝytkownika

Multimedia JAVA. Historia

Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia

Jak dodać własny szablon ramki w programie dibudka i dilustro

Applety Java. Applety są przykładem kodu Java wykonywanego po stronie klienta, ale bez ujawnionej (jak w przypadku skryptu) wersji źródłowej

Wykład 4_1. Interaktywne aplety obsługa zdarzeń, uruchamianie apletu przez przeglądarkę lub maszynę wirtualną Javy.

Język Java część 2 (przykładowa aplikacja)

MS Access formularze

SWING ZAGADNIENIA: wprowadzenie, kontenery i komponenty, LayoutManager, komponenty tekstowe. inne przydatne komponenty.

BAZY DANYCH Formularze i raporty

Java Podstawy. Michał Bereta

BAZY DANYCH Panel sterujący

Tworzymy projekt File->New Project->Java Application, przy czym tym razem odznaczamy create main class

Scenariusz Lekcji. Część organizacyjna:

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Tworzenie projektu zawierającego aplet w środowisku NetBeans. lab1. Dr inż. Zofia Kruczkiewicz Programowanie aplikacji internetowych

Język JAVA podstawy. wykład 2, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

LABORATORIUM 7 Cel: 1_1

Tworzenie prezentacji w MS PowerPoint

Aplikacja wielowątkowa prosty komunikator

Wykład 3: Projektowanie graficznych interfejsów użytkownika w Java

I. Spis treści I. Spis treści... 2 II. Kreator szablonów Tworzenie szablonu Menu... 4 a. Opis ikon Dodanie nowego elementu...

Adobe InDesign lab.1 Jacek Wiślicki, Paweł Kośla. Spis treści: 1 Podstawy pracy z aplikacją Układ strony... 2.

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Interfejsy w Java. Przetwarzanie równoległe. Wątki.

Systemy operacyjne na platformach mobilnych

1. Język JAVA. 1. Pierwszy program. 2. Kalkulator. 3. Klasy. 4. Dziedziczenie

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Podręcznik użytkownika programu. Ceremonia 3.1

Instrukcja obsługi funkcji specjalnych szablonu C01 v.1.0

Programowanie obiektowe zastosowanie języka Java SE

Edytor tekstu MS Office Word

Java SE Laboratorium nr 5. Temat: Obsługa zdarzeń

JavaFX. Zaawansowane technologie Javy 2019

Delphi podstawy programowania. Środowisko Delphi

Komputery I (2) Panel sterowania:

Programowanie obiektowe

1. Umieść kursor w miejscu, w którym ma być wprowadzony ozdobny napis. 2. Na karcie Wstawianie w grupie Tekst kliknij przycisk WordArt.

Kompleksowe tworzenie aplikacji klasy Desktop z wykorzystaniem SWT i

Aplikacja wielow tkowa prosty komunikator

Padlet wirtualna tablica lub papier w Internecie

Arkusz strona zawierająca informacje. Dokumenty Excela są jakby skoroszytami podzielonymi na pojedyncze arkusze.

Dodawanie grafiki i obiektów

Oficyna Wydawnicza UNIMEX ebook z zabezpieczeniami DRM

Tworzenie okna dialogowego w edytorze raportu SigmaNEST. część 1

Wymiarowanie, kreskowanie, teksty

Transkrypt:

Aplikacje w Javie wykład 12 1 Programowanie GUI Treści prezentowane w wykładzie zostały oparte o: Barteczko, JAVA Programowanie praktyczne od podstaw, PWN, 2014 http://docs.oracle.com/javase/8/docs/ C. S. Horstmann, G. Cornell, Java. Podstawy, Helion, Gliwice 2008

GUI komponenty wizualne i kontenery 2 Standardowe pakiety java.awt (AWT) oraz javax.swing (Swing) zawierają klasy definiujące wiele różnorodnych komponentów wizualnej interakcji programu z użytkownikiem (okna, przyciski, listy, menu, tablice itp.). Komponenty wywodzą się z abstrakcyjnej klasy Component. Tworzymy je za pomocą wyrażenia new wywołującego odpowiedni konstruktor klasy komponentu, któremu podajemy argumenty, określające niektóre właściwości komponentu (np. tekst/ikonę na przycisku). Komponenty mają właściwości (np. kolory, czcionka tekstu na przycisku), które możemy ustalać (lub pobierać) za pomocą metod z odpowiednich klas komponentów (metody setnnn(...), getnnn(...), isnnn(...), gdzie NNN nazwa właściwości). Większość właściwości komponentów jest reprezentowane przez obiekty odpowiednich klas (np. czcionka klasa Font, kolor klasa Color) Komponenty, które mogą zawierać inne komponenty nazywają się kontenerami. Do kontenerów dodajemy inne komponenty (w tym inne kontenery) Z każdym kontenerem związany jest określony zarządca rozkładu, który określa układ komponentów w kontenerze i ich zachowanie (zmiany rozmiarów i położenia) przy zmianie rozmiarów kontenera (rozkład jest jedną z właściwości kontenera). Zarządcy rozkładu są obiektami odpowiednich klas.

Komponenty wizualne i kontenery Aplikacja komunikuje się z użytkownikiem za pomocą okna lub wielu okien Okna AWT są kontenerami, do których dodajemy komponenty wizualnej interakcji z użytkownikiem (w tym inne kontenery) Okna Swing zawierają tzw. contentpane, który jest kontenerem do którego domyślnie dodajemy komponenty wizualnej interakcji (w tym inne kontenery). Okna (w tym "okno" apletu) są zawsze kontenerami najwyższego poziomu w hierarchii zawierania się komponentów Współdziałanie użytkownika z aplikacją odbywa się na zasadzie obsługi zdarzeń (np. zdarzenia kliknięcia w przycisk). Obsługą zdarzeń zarządza specjalny, równolegle z naszym programem wykonujący się kod w JVM wątek obsługi zdarzeń. AWT (Abstract Windowing Toolkit) obecny w Javie od samego początku - jest zestawem klas, definiujących proste komponenty wizualnej interakcji. Są to komponenty ciężkie tzn. realizowane poprzez użycie graficznych bibliotek GUI systemu operacyjnego: ubogie możliwości graficzne i interakcyjne komponentów, brak komponentów istotnych dla oprogramowania nowoczesnych GUI (np. tabel) zależny od platformy systemowej wygląd komponentów 3

Komponenty wizualne i kontenery 4 Odpowiedzią na te problemy oraz ich rozwiązaniem jest pakiet Swing (JFC Java Foundation Classes) (javax.swing i podpakiety), który zawiera dużo więcej niż AWT komponentów - nowych wobec AWT oraz mających rozbudowane właściwości odpowiedników AWT. Wszystkie komponenty Swingu oprócz kontenerów znajdujących się najwyżej w hierarchii zawierania się komponentów (kontenerów najwyższego poziomu) są komponentami lekkimi. Komponenty lekkie: są rysowane za pomocą kodu Javy w obszarze jakiegoś komponentu ciężkiego znajdującego się wyżej w hierarchii zawierania się komponentów (zwykle jest to kontener najwyższego poziomu). mogą być przezroczyste, a zatem mogą przybierać wizualnie dowolne kształty mają wygląd niezależny od platformy i modyfikowalny (Look&Feel) Uwaga: możliwe jest umieszczanie w jednym kontenerze komponentów lekkich (np. Swingu) i ciężkich (AWT), jednak jest to nie polecane i obarczone pewnymi restrykcjami. Zalecane jest, aby dodawać komponenty Swingu do contentpane okna ramowego Swingu (JFrame).

Hierarchia komponentów AWT i Swing 5

Hierarchia komponentów AWT i Swing 6

Hierarchia komponentów AWT i Swing 7 Wnioski, które wynikają z tej hierarchii : podstawowe właściwości wszystkich komponentów (i AWT i Swingu) określa klasa Component z pakietu java.awt; w klasie tej znajdziemy mnóstwo użytecznych metod do ustalania i pobierania właściwości dla każdego z możliwych komponentów, podstawowe właściwości i użyteczne metody dla wszystkich kontenerów określa klasa Container, szczególne dla lekkich komponentów Swingu, ale wspólne dla nich wszystkich, właściwości określa klasa JComponent specyficzne właściwości i funkcjonalność poszczególnych rodzajów komponentów zdefiniowane są w klasach tych komponentów

Komponenty Swing Przyciski JButton odpowiednik Button z AWT, JToggleButton przycisk dwustanowy o wyglądzie normalnego przycisku, JCheckBox odpowiednik CheckBox z AWT, JRadioButton odpowiednik RadioButton z AWT. Podstawowe funkcje wszystkch klas przycisków określone są w klasie AbstractButton. Przyciski przełącznikowe implementują JToggleButton. Możliwości: tekst i/lub ikona na przycisku z dowolnym pozycjonowaniem różne ikony dla różnych stanów (wciśnięty, kursor myszki nad przyciskiem etc) ustalanie tekstu w HTML programistyczne symulowanie kliknięć (metoda doclick()) ustalanie mnemoników (metoda setmnemonic()) Etykieta: klasa JLabel Możliwości: tekst i/lub ikona z dowolnym pozycjonowaniem tekst HTML ustalenie mnemonika i związanie go z innym komponentem (setlabelfor(...)), np. polem edycyjnym (wciśnięcie alt+mnemonik powoduje przejście fokusu do danego komponentu np. pola edycyjnego) 8

Komponenty Swing 9

Komponenty Swing Menu rozwijalne: klasy JMenu, JMenuItem, JCheckBoxMenuItem, JRadioMenuItem. Ponieważ pochodzą od AbstractButton, to posiadają wszystkie właściwości przycisków. Menu kontekstowe: klasa JPopupMenu Suwak: klasa JSlider Ustalanie wartości za pomocą suwaka. W pełni konfigurowalny, jako etykiety może zawierać ikony. Dialog wyboru koloru: JColorChooser łatwy w użyciu w wersji standardowej. W pełni konfigurowalny - możliwość tworzenia wersji niestandardowych i wbudowywania ich w inne komponenty GUI. Inny dialog wyboru - JFileChooser - wybór plików. Pole edycyjne: JTextField do wprowadzania hasła: JPasswordField W JDK 1.4 - nowa klasa JFormattedTextField - z wbudowaną weryfikacją tekstu 10

Komponenty Swing 11

Komponenty Swing 12 Wielowierszowe pole edycyjne: JTextArea Uwaga: wszystkie komponenty tekstowe pochodzą od klasy JTextComponent, która zapewnia bardzo elastyczne możliwości tworzenia różnych edytorów. Komponenty tekstowe są bardzo rozbudowane, jesli chodzi o architekturę. Procesory dokumentów: JEditorPane i JTextPane Lista: klasa JList oparta na współpracy modelu danych listy z widokiem tych danych elementy: teksty i/lub obrazki, a nawet inne komponenty GUI (wygląd) różne elementy listy mogą mieć różny wygląd (kolor, czcionkę, obrazek lub nie etc). Lista rozwijalna: JComboBox oszczędność miejsca w GUI te same właściwości co lista + możliwość przechodzenia do elementu tekstowego po wciśnięciu pierwszej litery napisu, który on reprezentuje Tabela: klasa JTable Ogromne możliwości konfiguracyjne, przestawianie kolumn (myszką i programistycznie), różny wygląd kolumn (teksty, obrazki, komponenty interakcyjne), sortowanie wierszy, wielozaznaczanie (po wierszach i po kolumnach) Drzewo: klasa JTree Reprezentowanie hierarchii. Węzły drzewa mają te same właściwości co elementy tabeli (tzn. mogą być reprezentowane w postaci napisów i/lub ikon oraz innych komponentów)

Komponenty Swing 13

Właściwości komponentów (AWT i Swing) 14 Wszystkie komponenty wywodzą się z abstrakcyjnej klasy Component, która definiuje metody, m.in. ustalające właściwości komponentów. Mamy dwa rodzaje komponentów: komponenty-kontenery (takie, które mogą zawierać inne komponenty) oraz komponenty terminalne (nie mogą zawierać innych komponentów). Właściwości mogą być pobierane za pomocą metod getnnn() lub (dla właściwości typu boolean) isnnn() i ustalane (jeśli to możliwe) za pomocą metod setnnn(...)., gdzie NNN nazwa właściwości. Do najogólniejszych właściwości wszystkich komponentów należą: rozmiar (Size), szerokość (Width), wysokość (Height), położenie (Location), rozmiar i położenie (Bounds), minimalny rozmiar (MinimumSize), preferowany rozmiar (PreferredSize), maksymalny rozmiar (MaximumSize),wyrównanie po osi X (AlignmentX), wyrównanie po osi Y (AlignmentY), czcionka (obiekt klasy Font), kolor tła (Background) (kolor jest obiektem klasy Color, kolor tła ma znaczenie tylko dla nieprzezroczystych komponentow), kolor pierwszego planu (Foreground), rodzic (Parent) (kontener, który zawiera dany komponent), nazwa (Name) (komponenty otrzymują domyślne nazwy; można je zmieniać), widzialność (Visible), lekkość (LigthWeight), przezroczystość (Opaque), dostępność (Enabled).

Właściwości komponentów Rozmiary i położenie komponentów nie są znane dopóki komponenty nie zostaną zrealizowane (uwidocznione lub okno, w którym się znajdują nie zostanie spakowane). Położenie komponentu określane jest przez współrzędne (x,y), a punkt (0,0) oznacza lewy górny róg obszaru, w którym znajduje się komponent (jest to ten obszar kontenera, do którego mogą być dodane komponenty). Zmiana położenia i rozmiarów za pomocą metod set ma w zasadzie sens tylko dla komponentów znajdujących się w kontenerach bez zarządcy rozkładu lub dla komponentów-okien. Aby ustalić rozmiar okna frame piszemy np.: frame.setsize(200, 200); Metoda pack()w klasie Window (dziedziczonej przez Frame i JFrame) pozwala ustalić rozmiary okna, tak by były dokladnie takie (i nie większe), żeby zmieścić wszystkie znajdujące się w nim komponenty: frame.pack(); Czcionka jest obiektem klasy Font, tworzonym za pomocą konstruktora gdzie: Font(nazwa_czcionki, styl, rozmiar) nazwa_czcionki - jest łańcuchem znakowym, określającym rodzaj czcionki (np. "Dialog") styl - jest jedną ze stałych statycznych typu int z klasy Font: Font.BOLD, Font.ITALIC, Font.PLAIN (kombinacje uzyskujemy poprzez sumę logiczną np. Font.BOLD Font.ITALIC) rozmiar - liczba całkowita określająca rozmiar czcionki w punktach. 15

Właściwości komponentów Podstawowe, logiczne nazwy czcionek to: Serif, SansSerif, Dialog i MonoSpaced. Zatem, aby np. dla przycisku b ustalić czcionkę, piszemy JButton b = new JButton("Tekst na przycisku"); b.setfont(new Font("Dialog", Font.PLAIN, 14); Kolor jest obiektem klasy Color, która ma kilka konstruktorów oraz udostępnia stałe statyczne typu Color z predefiniowanymi kolorami, np. Color.red, Color.blue, Color.white,... Kolory przycisku możemy więc ustalić za pomocą takich konstrukcji: b.setbackground(color.blue); b.setforeground(color.white); albo: int r = 200, g = 200, b = 255; b.setbackground(new Color(r,g,b)); Zablokowanie/odblokowanie komponentu Komponenty gotowe do interakcji są odblokowane (enabled). Zablokowanie komponentu uniemożliwia interakcję z nim. Np. jeśli b jest przyciskiem // zablokowanie; kliknięcia w przycisk nie będą "przyjmowane" b.setenabled(false); // odblokowanie: if (!b.isenabled()) b.setenabled(true); 16

Właściwości komponentów 17 Uwidacznianie komponentów Wszystkie komponenty, oprócz tych wywodzących się z klasy Window, są domyślnie widoczne. Pojawiają się one na ekranie, gdy zostały dodane do jakiegoś kontenera i kontener jest/został uwidoczniony. W trakcie działania programu można czynić komponenty niewidocznymi i przywracać ich widzialność, np: JButton b = new JButton(...);... b.setvisible(false); // stanie się niewidoczny... if (!b.isvisible()) b.setvisible(true); // gdy niewidoczny, uwidaczniamy Przezroczystość komponentów Wszystkie komponenty AWT (jako ciężkie) są nieprzezroczyste (isopaque() zwróci true). Komponenty lekkie mogą być przezroczyste lub nie. Domyślnie większość lekkich komponentów Swingu jest nieprzezroczysta. Wyjątkiem jest etykieta JLabel. Zatem aby ustalić tło etykiety Swingu musimy napisać: JLabel l = new JLabel("Jakaś etykieta"); l.setopaque(true); l.setbackground(color.yellow);

Kontenery Swing Kontenery - to komponenty, które mogą zawierać inne komponenty (w tym inne kontenery). Podstawowe kontenery to: Panel: klasa JPanel - służy do grupowania komponentów W Swingu mamy też wyspecjalizowane kontenery (panele dzielone, zakładkowe, przewijane), które mają specjalną konstrukcję i wobec nich używamy innych metod ustalania zawartości: Panel dzielony: klasa JSplitPane - podział kontenera na dwie części (poziomo lub pionowo) z możliwością przesuwania belki podziału dla ustalenia rozmiarów widoków części Panel zakładkowy: JTabbedPane - zakładki służą do wybierania komponentów, które mają być uwidocznione w panelu Panel przewijany: JScrollPane - służy do pokazywania komponentów, które nie mieszczą się w polu widoku; suwaki umożliwiają "przewijanie" widoku komponentu, tak, by odsłaniać kolejne jego fragmenty. JTextArea i JList powinny być umieszczane w JScrollPane, jeśli ich zawartość (wiersze tekstu, elementy listy) może się powiększać. Pasek narzędzi: JToolBar Panele są umieszczane w innych kontenerach - np. oknach. Domyślnie panele są widoczne, a okna - nie. 18

Kontenery Swing 19

Kontenery Swing metody. Okna. 20 Podstawowe metody (oprócz odziedziczonych z klasy Component) to: add(<nazwa komponentu>) dodawanie komponentu do kontenera, remove(<nazwa komponentu>) usunięcie komponentu z kontenera. A ponadto: getcopmonentcount() zwraca liczbę komponentów, getcomponent(int n) zwraca referencję do n-tego komponentu, getcomponents() zwraca tablicę wszystkich komponentów, setlayout(...) ustawia rozmieszczenie komponentów. Okna to kontenery najwyższego poziomu, za pomocą których aplikacja komunikuje się z użytkownikiem. Najważniejsze klasy, które tworzą okna to: JFrame, JDialog, JWindow, JApplet, JInternalFrame. Główne okno aplikacji jest obiektem klasy JFrame, np: JFrame okno = new JFrame( Okno główne ); W AWT komponenty dodajemy bezpośrednio do okien. W Swingu zwykle dodajemy komponenty (w tym kontenery) do contentpane (specjalnego kontenera, stanowiącego standardową zawartość okna). Dostęp do tego kontenera umożliwia metoda getcontentpane(), np: Container cp = okno.getcontentpane(); Kolejne komponenty umieszcza się w kontenerze przy użyciu metody add(...)

Okna podstawowe pojęcia 21 Podstawowe pojęcia, dotyczące okien okno wtórne (secondary window, child window) = okno które ma właściciela - inne okno okno pierwotne, właściciel innych okien (owner) = okno, które jest właścicielem innych okien Skutki prawa własności: zamknięcie okna pierwotnego powoduje zamknięcie okien wtórnych, które są jego własnością, minimalizacja okna pierwotnego powoduje minimalizację okien wtórnych, przesunięcie okna pierwotnego powoduje przesunięcie okien wtórnych (nie na wszystkich platformach). Okno wtórne może być oknem modalnym lub nie. Modalność oznacza, iż interakcja z oknem pierwotnym jest zablokowana do chwili zamknięcia okna wtórnego. Przy niemodalnym oknie wtórnym - możemy dalej działać na oknie pierwotnym. Z-order = uporządkowanie okien "po osi Z" (czyli jak się okna na siebie nakładają). Wszystkie okna w Javie, za wyjątkiem "okna" apletu (które tak naprawdę jest panelem) oraz okien wewnętrznych Swingu, pochodzą od klasy Window.

Okna ramowe - JFrame 22 Ważnym rodzajem okna jest okno ramowe, mające ramki, pasek tytułowy, ikonki sterujące, oraz ew. pasek menu. Realizowane jest ono przez klasy Frame (w AWT) i JFrame (w Swingu). Nie ma właściciela i nie może być oknem modalnym. Główne okno naszej aplikacji będzie zwykle obiektem klasy pochodnej od JFrame Okno ramowe tworzymy za pomocą konstruktora bezparametrowego lub z argumentem String, stanowiącym tytuł okna. Niektóre metody klas Frame/JFrame Image geticonimage() jaka ikonka przy minimalizacji? MenuBar getmenubar() pasek menu (dla Frame) JMenuBar getjmenubar() pasek menu (dla JFrame) String gettitle() tytul boolean isresizable() czy możliwe zmiany rozmiarów? remove(menucomponent) usunięcie paska menu seticonimage(image) ustala ikonkę używaną przy minimalizacji setmenubar(menubar) ustala pasek menu (dla Frame) setjmenubar(jmenubar) ustala pasek menu (dla JFrame) setresizable(boolean) ustalenie możliwosci zmiany rozmiarów settitle(string) zmiana tytułu setundecorated(boolean) ustala, czy okno ma mieć "dekoracje" (tj. pasek tytułu, ramkę itp.) setextendedstate(int stan) ustala stan okna, reprezentowany przez jedną ze stałych statycznych z klasy Frame (podawane jako argument - stan): NORMAL, ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT, MAXIMIZED_BOTH. Uwaga: nie na wszystkich platformach wszystkie w/w stany są możliwe do osiągnięcia. Aby stwierdzić, które tak, a które nie, używamy metody: Toolkit.isFrameStateSupported(int stan)

Okna dialogowe, wewnętrzne. 23 Dialog (obiekty klas Dialog i JDialog ) - to okno z ramką i tytułem, które ma właściciela i nie może mieć paska menu. Może natomiast być oknem modalnym lub nie, co zależy od naszych ustaleń. Podobnie jak Frame/JFrame klasa Dialog/JDialog zawiera metody pozwalające na pobieranie - ustalanie tytułu oraz możliwości zmiany rozmiarów. Dodatkowo metody boolean ismodal() i setmodal(boolean) pozwalają sprawdzać i ustalać właściwość modalności. Okna wewnętrzne (JInternalFrame) dostępne w Swingu są lekkimi komponetami o funkcjonalności okien ramowych. Podstawowe różnice wobec zwykłych okien ramowych (JFrame): niezależny od platformy wygląd muszą być dodawane do innych kontenerów dodatkowe możliwości programistyczne (np. dynamicznych zmian właściwości takich jak możliwość zmiany rozmiaru, możliwość maksymalizacji itp.) Operacja zamknięcia okna. Wszystkie okna Swingu (JFrame, JDialog, JInternalFrame...) pozwalają na ustalenia co ma się stać w przypadku zamknięcia okna. Służy temu metoda setdefaultcloseoperation(int), której argument może przyjmować następujące wartości (są to nazwy odpowiednich statycznych stałych): DO_NOTHING_ON_CLOSE HIDE_ON_CLOSE - operacja domyślna (chowa okno, ale nie likwiduje go) DISPOSE_ON_CLOSE - usunięcie okna, ale bez zamknięcia aplikacji EXIT_ON_CLOSE - powoduje zamknięcie aplikacji W AWT - dla wywołania określonych efektów przy zamknięciu okna (np. zakończenia aplikacji) musimy obsługiwać zdarzenie zamykania okna.

Umieszczanie komponentów w oknie - przykład 24 import java.awt.*; import javax.swing.*; public class Ramka extends JFrame{ public Ramka(){ super("ramka 2"); //Wywołanie konstruktora nadklasy setsize(250,70); //Ustawienie rozmiaru okna ramki setdefaultcloseoperation(jframe.exit_on_close); //Umieszczanie komponentów w oknie JPanel p = new JPanel(); p.add(new JLabel("Etykieta") ); p.add(new JButton("Przycisk") ); p.add(new JTextField("Pole textowe")); Container cp = getcontentpane(); cp.add(p); setvisible(true);//wyświetlenie ramki na ekranie public static void main(string []args){ new Ramka();

Zarządcy rozkładów 25 Z każdym kontenerem jest skojarzony tzw. zarządca rozkładu, który określa rozmiary i położenie komponentów przy wykreślaniu kontenera (a więc gdy jest on uwidaczniany lub zmieniają się jego rozmiary). W klasie każdego z komponentów znajdują się metody: getpreferredsize(), getminimumsize() i getmaximumsize(), zwracające - różne w zależności od typu komponentu - rozmiary preferowane, minimalne i maksymalne (obiekty typu Dimension z publicznymi polami width i height) Rozmiary te - w różny sposób przez różnych zarządców rozkładów - są brane pod uwagę przy układaniu komponentów. Dla lekkich komponentów Swingu rozmiary te możemy ustalać za pomocą odpowiednich metod set... Zdarza się czasem, że zmiany rozmiarów jakiegoś komponentu, umieszczonego w kontenerze (np. na skutek jakichś pośrednich odwołań z programu) nie skutkują w rozkładzie komponentów w kontenerze. Należy wtedy wywołać metodę revalidate() na rzecz komponentu, którego rozmiary uległy zmianie, co spowoduje ponowne ułożenie komponentów w kontenerze przez zarządcę rozkładu. Jeśli zmiany ułożenie nie będą uwidocznione na ekranie - należy dodatkowo wywołać metodę repaint(), również na rzecz zmienionego komponentu. Użycie pack() wobec okna zawsze powoduje wywołanie metod układania komponentów przez zarządców rozkładu dla wszystkich kontenerów w hierarchii zawierania się komponentów w oknie.

Zarządcy rozkładów Jak prawie wszystko w Javie - zarządcy rozkładu są obiektami odpowiednich klas. Klasy te implementują interfejs LayoutManager lub rozszerzający go LayoutManager2. Np. rozkłady Flow, Border i Grid są zarządzane przez obiekty klas FlowLayout, BorderLayout i GridLayout. Aby ustalić rozkład komponentów musimy: stworzyć obiekt-zarządcę rozkładu, ustalić ten rozkład dla kontenera. Ustalenie zarządcy rozkładu w AWT dla kontenera odbywa się za pomocą metody setlayout np. FlowLayout flow = new FlowLayout(); Frame f = new Frame(); f.setlayout(flow); Okna Swingu mają złożoną architekturę i zwykle rozkład komponentów ustalamy dla contentpane okna np.: JFrame frame = new JFrame(); frame.getcontentpane().setlayout(new FlowLayout()); Samo odwołanie: frame.setlayout(...) domyślnie ustala rozkład w contentpane (a nie w oknie). 26

Rozkład - FlowLayout 27 FlowLayout (rozkład domyślny dla Panel, JPanel) Komponenty ułożone są w wierszu. Przy zmianie rozmiarów kontenera rozmiary komponentów nie zmieniają się Jeśli szerokość kontenera jest za mała, pojawiają się dodatkowe wiersze. Można ustalić, jak mają być wyrównane komponenty (do lewej, w centrum, do prawej): służą temu stałe FlowLayout.LEFT, FlowLayout.CENTER, FlowLayout.RIGHT podawane jako argument konstruktora Można ustalić odstępy (w pionie i poziomie) pomiędzy komponentami. Wersje konstruktorów FlowLayout() // (center, odstępy 5) FlowLayout(int) // podane wyrównanie FlowLayot(int, int, int) // podane wyrównanie oraz odstępy // poziom, pion

Rozkład - BorderLayot 28 BorderLayout (układ domyślny dla Frame, Window i Dialog oraz contentpane okien Swingu) Komponenty ułożone są "geograficznie": "North", "East", "South", "West", "Center" Używa się metody cont.add(comp, loc), gdzie loc - napis oznaczający miejsce lub stałą całkowitoliczbową BorderLayout.NORTH, BorderLayout.CENTER, etc. Komponent dodany w miejscu "Center" wypełnia całe pozostawiane przez inne komponenty miejsce. Komponenty zmieniają rozmiary wraz ze zmianami rozmiaru kontenera: "North" i "South" - w poziomie, ale nie w pionie "West" i "East" - w pionie, ale nie w poziomie "Center" - w obu kierunkach Można podać odstępy między komponentami (pion, poziom) new BorderLayout(odst_poz, odst_pion)

Rozkład - GridLayout 29 GridLayout Siatka (tablica) komponentów Rozmiary wszystkich komponentów będą takie same Zmieniają się wraz ze zmianami rozmiaru kontenera Konstruktory: GridLayout(n, m) // tablica n x m komponentów, Jeśli n=0 lub m=0, to dany wymiar tablicy zostanie ustalony dynamicznie na podstawie drugiego wymiaru i liczby komponentów w kontenerze. GridLayout(n, m, hgap, vgap) // z podanymi odstępami w poziomie i pionie

Rozkład BoxLayout BoxLayout to bardzo elastyczny rozkład, który układa komponenty w jednym wierszu lub w jednej kolumnie (poziomo lub pionowo). W odróżnieniu od rozkładu GridLayout brane są przy tym pod uwagę preferowane, mnimalne i maksymalne rozmiary komponentów (dla komponentów Swingu setminimumsize() i setmaximumsize()) oraz ich wyrównanie w kontenerze (w Swingu: metody setalignmentx(...) i setalignmenty(...) z argumentami - stałymi statycznymi z klasy Component: LEFT_ALIGNMENT, CENTER_ALIGNMENT, RIGHT_ALIGNMENT, BOTTOM_ALIGNMENT, TOP_ALIGNMENT). Aby istniejącemu kontenerowi cont nadać rozkład BoxLayout: pionowy: cont.setlayout(new BoxLayout(cont, BoxLayout.Y_AXIS)); poziomy: cont.setlayout(new BoxLayout(cont, BoxLayout.X_AXIS)); W przypadku tworzenia nowego kontenera można użyć klasy Box, która definiuje kontener lekki o rozkładzie BoxLayout (uwaga: Box nie jest J-komponentem) Tworzenie obiektu Box: za pomocą konstruktora: Box(orient), gdzie orient - BoxLayout.X_AXIS lub Y_AXIS za pomocą statycznych metod zwracających referencję do utworzonego obiektu Box: Box.createHorizontalBox() lub Box.createVerticalBox(). W klasie Box zdefiniowano też wygodne metody statyczne do wprowadzania "wypełniaczy" przestrzeni w rozkładzie BoxLayout. Te wypełniacze to: klej (glue) (Box.createGlue()), sztywny obszar (rigid area) (Box.createRigidArea(Dimension)) oraz wypełniacz (boxfiller) (new Box.Filler(min, pref, max)). 30

Rozkłady Do bardziej zaawansowanych rozkładów należą: GridBagLayout, CardLayout oraz GroupLayout(przeznaczony raczej do stosowania w środowiskach wizualnych edytorów GUI). Wszystkie te klasy implementują interfejs LayoutManager2, który rozszerza interfejs LayoutManager. Implementując te interfejsy we własnych klasach możemy również tworzyć własnych zarządców rozkładu. Dostępne są także gotowe, przygotowane przez różnych programistów, ciekawe rozkłady, które nie są w "standardzie" Javy, ale mogą być łatwo doinstalowane. Np. bardzo elastyczne i łatwe w użyciu są rozkłady TableLayout i MigLayout. Możliwe jest także, by kontener nie miał żadnego rozkładu. Ponieważ wszystkie kontenery (oprócz ScrollPane w AWT i wyspecjalizowanych kontenerów Swingu) mają jakiś domyślny rozkład, to brak rozkładu musimy zaordynować sami za pomocą odwołania: kontener.setlayout(null); W takim kontenerze posługujemy się "absolutnym" pozycjonowaniem i wymiarowaniem komponentów, np. za pomocą metody setbounds(x,y,w,h), gdzie x, y - współrzędne położenia komponentu, w,h - szerokość i wysokość. Podsumowując: użycie rozkładów pozwala programiście unikać oprogramowania zmian rozmiarów i położenia komponentów przy zmianie rozmiarów kontenera. Wyszukane układy komponentów GUI zwykle uzyskamy łatwiej poprzez umiejętne łączenie paneli z różnymi prostszymi rozkładami. 31

Schemat aplikacji Swing 32 Interakcja użytkownika z aplikacją graficzną odbywa się poprzez obsługę zdarzeń (takich jak np. kliknięcie w przycisk). Obsługą zdarzeń zajmuje się specjalny, uruchamiany przez JVM równolegle z głównym wątkiem aplikacji, wątek obsługi zdarzeń. Zanim dojdzie do interakcji z użytkownikiem, okno aplikacji musi być zbudowane i uwidocznione, muszą być skonstruowane komponenty, muszą uzyskać one jakieś właściwości (np. kolor, czcionkę) i być dodane do kontenerów, a w końcu i do okien. Komponenty Swingu zostały zbudowane w taki sposób, że wszelkie manipulacje na nich (tworzenie, odczytywanie i zmiany ich właściwości) muszą się odbywać w jednym wątku - najwygodniej w wątku obsługi zdarzeń. Zatem kod, który działa na komponentach Swingu, umieszczamy w metodach obsługujących zdarzenia albo w wątku obsługi zdarzeń za pomocą statycznych metod invokelater oraz invokeandwait z klasy java.awt.eventqueue. Tak samo nazwane metody znajdują się również w klasie SwingUtilities (delegują one odwołania do odpowiednich metod z klasy EventQueue). Argumentem tych metod jest referencja do obiektu klasy implementującej interfejs Runnable. Kod operujący na komponentach Swingu umieszczamy w zdefiniowanej w tej klasie metodzie run(). Metoda invokelater przekaże ten kod do wykonania przez wątek obsługi zdarzeń (umieści kod w kolejce zdarzeń), wykonanie bieżącego wątku będzie kontynuowane, natomiast nasz kod umieszczony w kolejce zdarzeń zostanie wykonany wtedy, gdy wątek obsługi zdarzeń obsłuży zdarzenia znajdujące się w kolejce przed nim. Tak samo działa metoda invokeandwait, z tą różnicą, że po jej wywołaniu działanie bieżącego wątku zostanie wstrzymane do chwili wykonania przekazanego kodu przez wątek obsługi zdarzeń. Zatem nie należy wywoływać tej metody z wątku obsługi zdarzeń, bowiem może to zablokować GUI.

Schemat aplikacji Swing 33 Schemat wywyołania metody invokelater(..) SwingUtilities.invokeLater(new Runnable() { public void run() { // tu działania na komponentach Swingu ); Generalnie wszelkie działania na GUI (tworzenie komponentów, dodawanie komponentów do kontenerów, ustalanie właściwości komponentów wizualnych) winny być wykonywane w wątku obsługi zdarzeń. Od tej reguły są wyjątki. Mianowicie, niektóre metody działające na komponentach Swingu są wielowątkowo bezpieczne (mogą być wywoływane z wielu watków, nie tylko z wątku obsługi zdarzeń). Należy do nich np. metoda repaint(). W dokumentacji metod zawsze zaznaczono, czy są one wielowątkowo bezpieczne (thread-safe).

Szablon aplikacji Swing 34 import java.awt.*; import javax.swing.*; public class GuiSwing extends JFrame { public GuiSwing() { //działania inicjacyjne, nie związane z komponentami Swing // // budujemy okno; // ponieważ jest to działanie na komponentach wizualnych // - zrobimy to w wątku obsługi zdarzeń SwingUtilities.invokeLater(new Runnable() { @Override public void run() { creategui(); );

Szablon aplikacji Swing 35 protected void creategui() { // ustalenie tytułu okna settitle("okno aplikacji"); // ustalenie (jeśli trzeba) rozkładu setlayout(new FlowLayout()); // tworzenie komponentów np. JLabel lab = new JLabel("Etykieta"); JButton b = new JButton("Przycisk"); // Ustalenie właściwości komponentów, lab.setforeground(color.red); b.setforeground(color.blue); // Dodanie komponentów do okna np. add(lab); add(b); // Ustalenie domyślnej operacji zamknięcia okna setdefaultcloseoperation(exit_on_close); // ustalenie rozmiarów okna, np.: pack();

Szablon aplikacji Swing 36 // ustalenie położenia okna np. wycentrowanie setlocationrelativeto(null); // pokazanie okna setvisible(true); public static void main(string[] args) { new GuiSwing(); Uwaga. Wszelkie długotrwałe działania (np. wyszukiwanie w systemie plików, ściąganie danych z Internetu) winny być wykonywane poza wątkiem obsługi zdarzeń. W przeciwnym razie będą blokować interakcję z GUI (GUI staje się "zamrożone"). Do uruchamiania takich działań z kodów wykonujących się w wątku obsługi zdarzeń służy klasa SwingWorker.

Delegacyjny model obsługi zdarzeń 37 Interakcja użytkownika z GUI naszej aplikacji polega na wywoływaniu zdarzeń (np. kliknięcie w przycisk, wciśnięcie klawisza na klawiaturze etc). Zatem programowanie GUI jest programowaniem zdarzeniowym. Jest ono oparte na koncepcji tzw. funkcji callback. Funkcja typu callback zawarta w naszym programie jest wywoływana (zazwyczaj) nie przez nasz program, ale przez sam system na przykład w reakcji na zdarzenia takie jak wciśnięcie klawisza czy kliknięcie myszką. Funkcja ta obsługuje zdarzenie. W Javie dodatkowo zastosowano koncepcję delegacyjnego modelu obsługi zdarzeń, która umożliwia przekazanie obsługi zdarzenia, które przytrafia się jakiemuś obiektowi (źródło zdarzenia (source)) do innego obiektu (słuchacza zdarzenia (listener)). Zdarzenia (event) są obiektami odpowiednich klas, określających rodzaj zdarzeń. (Obsługa zdarzeń jest zawarta w pakiecie java.awt.event. ) Słuchacze są obiektami klas implementujących interfejsy nasłuchu. Interfejsy nasłuchu określają zestaw metod obsługi danego rodzaju zdarzeń. W klasach słuchaczy definiuje się metody odpowiedniego interfejsu nasłuchu zdarzeń, które określają co ma się dziać w wyniku zajścia określonego zdarzenia (metody obsługi odpowiednich zdarzeń) Zdarzenie (obiekt odpowiedniej klasy zdarzeniowej) jest przekazywane do obsługi obiektowi-słuchaczowi tylko wtedy, gdy Słuchacz ten jest przyłączony do Źródła zdarzenia (przyłączenie za pomocą odwołania z.addnnnlistener(h), gdzie: z Źródło zdarzenia, NNN - rodzaj zdarzenia, h Słuchacz danego rodzaju zdarzenia)

Delegacyjny model obsługi zdarzeń 38 Przekazanie zdarzenia do obsługi polega na wywołaniu odpowiedniej dla danego zdarzenia metody obsługi zdarzenia (zdefiniowanej w klasie Słuchacza) z argumentem obiekt-zdarzenie. Argument (obiekt klasy zdarzeniowej) zawiera informacje o okolicznościach zajścia zdarzenia (np. komu się przytrafiło? kiedy? jakie ma inne właściwości?). W Javie standardowo zdefiniowano bardzo dużo różnych rodzajów zdarzeń i interfejsów ich nasłuchu. Rozpatrzmy ogólne zasady na przykładzie zdarzenia "akcja" (obiekt klasy ActionEvent), które powstaje: po kliknięciu w przycisk lub naciśnięciu spacji, gdy przycisk ma fokus (zdolność do przyjmowania zdarzeń z klawiatury), po naciśnięciu ENTER w polu edycyjnym, po wyborze opcji menu, po podwójnym kliknięciu myszką / wciśnięciu ENTER na liście AWT (ale tylko AWT, nie dotyczy to listy Swingu - JList) lub na liście rozwijalnej Swingu - JComboBox (powstaje - o ile do Źródła przyłączono odpowiedniego Słuchacza akcji czyli obiekt klasy implementującej interfejs nasłuchu akcji - ActionListener) Uwaga: zdarzenie "akcja" jest zdarzeniem semantycznym - niezależnym od fizycznego kontekstu (zauważmy jak w różnych fizycznych okolicznościach ono powstaje kliknięcie, naciśnięcie spacji lub ENTER, w różnych "fizycznych" kontekstach na przycisku, w polu edycyjnym, w menu). Nie należy go mylić ze zdarzeniem kliknięcia myszką (czysto fizyczne zdarzenie).

Delegacyjny model obsługi zdarzeń 39 Przykład. Wyobraźmy sobie teraz, że w naszym GUI mamy jeden przycisk. Klikając w ten przycisk (w tym programie) nie uzyskamy żadnych efektów (oprócz widocznej zagwarantowanej przez domyślny look&feel zmiany stanu przycisku: wyciśnięty wciśnięty wyciśnięty). Chcemy by po kliknięciu w przycisk (lub naciśnięciu SPACJI, gdy przycisk ma fokus) wyprowadzony został na konsolę napis "Wystąpiło zdarzenie!". Kliknięcie lub naciśnięcie spacji na przycisku wywoła zdarzenie "akcja", jeśli do przycisku przyłączymy słuchacza akcji. Musimy zatem stworzyć obiekt słuchacza akcji i przyłączyć go do przycisku. Klasa słuchacza akcji musi implementować interfejs nasłuchu akcji (ActionListener), i w konsekwencji - zdefiniować jego jedyną metodę actionperformed. W tej metodzie zawrzemy kod, który zostanie uruchomiony po kliknięciu w przycisk, np. wyprowadzenie na konsolę napisu. public class Handler implements ActionListener { public void actionperformed(actionevent e) { // instrukcje obsługujące zdarzenie Klasa-słuchacz może też implementować większą liczbę interfejsów nasłuchu (określamy w ten sposób zestaw obsługiwanych zdarzeń).

Delegacyjny model obsługi zdarzeń Przyłączanie słuchacza do komponentu. Wszystkie komponenty Swing umożliwiają przyłączanie/odłączanie określonych typów słuchaczy. Służą do tego metody: addxxxlistener() oraz removexxxlistener(), gdzie XXX jest typem słuchacza. Np.: zdarzenie ActionEvent może być obsłużone przez słuchacza implementującego interfejs ActionListener. Słuchacz taki może być przyłączony do komponentów, które mają dostęp do metody addactionlistener(). Są to: Button, List, TextField, MenuItem oraz klasy pochodne. Np.: Handler sluchacz = new Handler(); przycisk.addactionlistener(sluchacz); Przedstawimy teraz trzy sposoby obsługi powyższego zdarzenia: definiując osobną klasę słuchacza implementując interfejs ActionListener w klasie, definiującej okno naszej aplikacji używając anonimowych klas wewnętrznych W przypadku interfejsów z wieloma metodami obsługi, spośród których interesuje nas tylko jedna lub dwie, lepszym rozwiązaniem może okazać się odziedziczenie odpowiedniego adaptera w anonimowej klasie wewnętrznej niż implementacja interfejsu w klasie GUI, gdyż obciąża nas ona koniecznością zdefiniowania pustych metod obsługi (metod obsługi tych zdarzeń, którymi nie jesteśmy zainteresowani) 40

41 Delegacyjny model obsługi zdarzeń - przykład import java.awt.event.*; // konieczny dla obsługi zdarzeń import javax.swing.*; //procedura obsługi class Handler implements ActionListener { public void actionperformed(actionevent e) { System.out.println("Wystąpiło zdarzenie!"); public class GUI extends JFrame { public GUI() { JButton b = new JButton( "<html><center>przycisk<br>reagujący na wciśnięcie</center></html>"); Handler h = new Handler(); b.addactionlistener(h);//dodanie słuchacza add(b); setdefaultcloseoperation(dispose_on_close); pack(); setlocationrelativeto(null); setvisible(true); public static void main(string[] a) { SwingUtilities.invokeLater(new Runnable() { public void run() { new GUI(); );

Delegacyjny model obsługi zdarzeń przykład 2 42 Możemy implementować interfejs ActionListener w klasie, definiującej okno naszej aplikacji: class GUI extends JFrame implements ActionListener { GUI() { JButton b = new JButton("Przycisk"); b.addactionlistener(this); //TEN obiekt będzie słuchaczem add(b); pack(); show(); public void actionperformed(actionevent e) { System.out.println("Wystąpiło zdarzenie!"); public static void main(string[] a) { SwingUtilities.invokeLater(new Runnable() { public void run() { new GUI(); );

Delegacyjny model obsługi zdarzeń przykład 3 43 Możemy też implementację interfejsu nasłuchu umieścić w anonimowej klasie wewnętrznej: public class InnerHandler extends JFrame { ActionListener al = new ActionListener(){ public void actionperformed(actionevent e){ System.out.println("Wystąpiło zdarzenie!"); ; public InnerHandler(){ JButton b = new JButton( "<html><center>przycisk<br>reagujący na wciśnięcie</center></html>"); b.addactionlistener(al);//dodanie słuchacza add(b); setdefaultcloseoperation(dispose_on_close); pack(); setlocationrelativeto(null); setvisible(true); public static void main(string[] a) { SwingUtilities.invokeLater(new Runnable() { public void run() { new GUI(); );