Pierwszy program okienkowy

Po krótkim wstępie czas przejść do rzeczy i napisać Hello World po raz trzeci. Tym razem będzie to jednak aplikacja okienkowa a nie tylko tekst na konsoli. W celu ułatwienia sobie pracy skorzystaj ze środowiska Eclipse.

Jak wspomnieliśmy we wstępie, podstawowym komponentem, dzięki któremu możemy stworzyć okienko jest JFrame. Aby ją wykorzystać moglibyśmy utworzyć nowy obiekt w dowolnej metodzie main(), byłoby to jednak bardzo niepraktyczne, ciężko byłoby dodawać do ramki inne elementy.

Kurs Java

Podejście, które powinieneś stosować jest następujące:

  • Utwórz klasę rozszerzającą klasę JFrame
  • Dodaj wszystkie elementy (panele, przyciski ...) w konstruktorze
  • Ustaw podstawowe cechy (rozmiar, akcja na zamknięcie aplikacji)
  • Uwidocznij ramkę za pomocą metody setVisible() z parametrem true
  • Utwórz obiekt swojej klasy w nowym wątku dystrybucji zdarzeń

Aby to wszystko omówić nieco dokładniej zacznijmy od razu od przykładu. Utwórzmy dwie klasy:

  • Klasa z ramką o nazwie MyFrame, która rozszerza klasę JFrame
  • Klasa Testowa o nazwie Test, w której stworzymy obiekt naszego okna
import javax.swing.JFrame;
 
 public class MyFrame extends JFrame {
 
 	public MyFrame() {
 		super("Hello World");
 		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 		setVisible(true);
 	}
 }
import java.awt.EventQueue;
 
 public class Test {
 	public static void main(String[] args) {
 		EventQueue.invokeLater(new Runnable() {
 			@Override
 			public void run() {
 				new MyFrame();
 			}
 		});
 	}
 }

W klasie MyFrame rozszerzamy (extends) klasę JFrame, ponieważ chcielibyśmy w przyszłości dodać do niej dodatkowe funkcjonalności i przede wszystkim ją ustawić po swojemu. Utworzyliśmy w niej jeden publiczny i bezparametrowy konstruktor (równie dobrze może przyjmować jakieś wartości, lub nawet być prywatny, a klasa udostępniać statyczną metodę zwracającą instancję klasy). W pierwszej kolejności zarówno w prostym oknie jak i innych komponentach powinniśmy wywołać instrukcję super(), czyli konstruktor nad klasy - w naszym wypadku podajemy również parametr "Hello World", który będzie stanowił tytuł naszego okna.

Następnie musimy zadbać o to, że nasza aplikacja po wciśnięciu przycisku zamknięcia (krzyżyk w rogu) będzie faktycznie zamykana. W tym celu należy wywołać metodę setDefaultCloseOperation() z odpowiednim argumentem. My chcemy, aby program się zamykał, więc podajemy stałą zdefiniowaną w klasie JFrame - EXIT_ON_CLOSE . Wpisując w Eclipse JFrame. i wciskając Ctrl+spacja możesz podejrzeć jakie inne wartości możesz przekazać (np DO_NOTHING_ON_CLOSE).

Ostatnią rzeczą jaką musimy zrobić to wyświetlenie naszej ramki na ekranie, za co odpowiedzialna jest metoda setVisible() . Przekazujemy jej wartość true, lub false, dzięki czemu, możemy naszą ramkę również ukryć - w końcu nasz program może posiadać kilka okienek i nie chcemy, aby zamknięcie jednego z nich zawsze powodowało koniec aplikacji. Żeby nasz program działał nie możemy oczywiście zapomnieć o zaimportowaniu odpowiedniej biblioteki, nam będzie potrzebna jedynie klasa JFrame znajdująca się w pakiecie javax.swing. (Najłatwiej zaimportować ją w Eclipse klikając na podkreślony tekst JFrame i wcisnąć kombinację klawiszy Ctrl+Shift+M, lub skorzystać z automatycznej organizacji importów - Ctrl+Shift+O).

Kurs Java

W drugiej klasie dzieje się nieco magii. Aplikacje wykorzystujące komponenty Swing powinny być podatne na przechwytywanie zdarzeń (na przykład na wciśnięcie przycisku zamknięcia okna), w tym celu powinniśmy je uruchamiać z tzw. wątku dystrybucji zdarzeń. Ponieważ nie zajmowaliśmy się jeszcze problemem wielowątkowości potraktujmy drugą klasę jako magiczny fragment kodu i wykorzystujmy ją jako wzorzec w swoich kolejnych projektach, będzie ona prawie zawsze wyglądała tak samo.Wykorzystano tu również klasę anonimową, której jeszcze nie omawialiśmy - w skrócie implementacja klasy odbywa się podczas tworzenia obiektu.

Ciekawostką może być też dla niektórych adnotacja @Override. Pisząc programy w Eclipse i importując metody, których wymaga implementowany interfejs adnotacja ta pozwala zachować bezpieczeństwo przed na przykład literówkami w nazwach. Jeżeli zmienilibyśmy nazwę run() na np. runnn(), wyświetlony zostałby komunikat o błędzie.

hello world swing

Po uruchomieniu programu w lewym górnym rogu ekranu powinna pokazać się nasza ramka w najbardziej skondensowanej formie, jakiej tylko się dało. Co ciekawe można zauważyć, że możemy dowolnie rozciągać naszą ramkę pomimo, że nie dodawaliśmy samodzielnie takiej funkcjonalności - jest ona domyślna i można ją oczywiście wyłączyć - konkretnie za pomocą metody setResizable(), z argumentem false.

W celu ćwiczenia wypróbuj tą metodę w swoim programie. Spróbuj także ustawić inne parametry, jak na przykład położenie, lub rozmiar, odpowiednio używając metod setLocation() i setSize(). To co należy im przekazać podejrzyj za pomocą kombinacji klawiszy Ctrl+spacja w Eclipse.

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.

Poniżej znajdziesz archiwalne wpisy z czasów, gdy strona była jeszcze hobbystycznym blogiem.

Jakub

Hey! Taka sie zastanwiem czym sie roznie i w czym jest lepsze, takie tworzenie okna: public class Main { public static void main(String[] args) { EventQueue.invokeLater(new Runnable(){ public void run(){ new MyFrame(); } }); } } od takiego: public class Main { public static void main(String[] args) { new MyFrame(); } }

``

Jestem początkujący ale wygląda mi na to że w pierwszym sposobie tworzysz okno w osobnym wątku. Drugim sposobem okno jest tworzone w tym samym wątku.

Anonim

To sa dwie klasy, a nie 2 sposoby do wyboru. Chyba nie czytales programowania obiektowego

NAME (WYMAGANE)

Witam, ja mam pytanie - dlaczego autor ustawia setDefaultExitAction? Wykomentowalem to i okno sie zamyka. Czy chcial pokazac ze takie cos istnieje czy jest inny powod?

DjCoraxa

Teraz otworz sobie menadzer zadan i zobacz ze ten program okienkowy jest dalej w pamieci ...

Tomek

Eclipse domaga się serialVersionUID, ale wyczytałem, że serializowanie nie jest konieczne, a jedynie mocno zalecane, więc uznałem, że na razie sobie to daruję. Działam na Eclipse 3.5.2 pod Ubuntu 11.04 i niestety przy kodzie klasy Test jaki podałeś w kursie okienko pojawia się u mnie w wersji prawie szpiegowskiej. Tzn. jest praktycznie niewidocznym prostokątem o wymiarach około 2x3 pixele. Kombinowałem już z ustawieniami setSize(), ale nic to nie daje. Przy użyciu kodu jaki podał Jakub, czyli: public class Main { public static void main(String[] args) { new MyFrame(); } } Okienko jest widoczne, pojawia się tam gdzie chcę setLocation()) i w takim rozmiarze, jak chcę (setSize()). Niestety setResizable() wciąż nie działa. Z czego wynikają te komplikacje?

bartek

spróbuj tak: import javax.swing.JFrame; public class Ramka extends JFrame{ public Ramka () { super("Program Bartka"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); setLocation(300,100); setResizable(false); setSize(400,400); } }

Norbert

Witam, mam taki problem, że gdy klikam CTRL+SHIFT+M lub O to nic się nie dzieje. Klikając CTRL+SHIFT+O pisze na dole "0 imports added". Klikałem to prawie w każdym miejscu i nic. Gdy próbuje uruchomić aplikacje pisze Errors exist in required project(s): Frame. Proszę pomóżcie!

Norbert

Albo jednak coś się dodaje ale mam dalej ten błąd. Exception in thread "main" java.lang.Error: Unresolved compilation problem: at pl.javastart.first.Test.main(Test.java:4)

Yaqp

Warto dodać, że setLocation() i setSize() można zastąpić setBounds()

POTTER

Jak powinien wyglądać JFrame??

lukas

dlaczego przy linijkach z frazą JFRAME pojawia mi się wykrzyknik z objaśnieniem: "the type jframe is not accessible due to restriction on required library c:\Program Files\java\jre7\lib\rt.jar" biblioteka nie jest aktualna ??

Slawek

Szczerze nie spotkałem się z tym błędem, ale tutaj są rozwiązania, które podobno działają: http://stackoverflow.com/questions/860187/access-restriction-on-class-due-to-restriction-on-required-library-rt-jar osobiście wypróbowałbym tą z usunięciem i ponownym dodaniem biblioteki do projektu.

lukas

Neatbeans nie pokazuje żadnego błędu, lecz po kompilacji nie wyskakuje żadne okienko.

lukas

Jre już mi nie krzyczy :) wyskakuje natomiast inny problem : The serializable class MyFrame does not declare a static final serialVersionUID field of type long

Slawek

Ale to tylko warning, a nie błąd, nie powinno mieć to wpływu na działanie programu. Dla spokoju można powiedzieć eclipsowi, czy netbeansowi, żeby sobie dodał to pole w postaci domyślnej, lub losowej. Jest ono potrzebne, gdy serializujemy obiekty, czyli zapisujemy je na dysku, dzięki polu serialVersionUID można je identyfikować.

70stick

Szkoda, że nie robisz filmików było by łatwiej bo mi wciąż wychodzą błędy' i za chwile napisze że mam błąd bo mam nie chce się odpalić, ale i tak super poradniki/lekcje/kursy

Akryl

Utwórz klasę rozszerzającą klasę JFrame. Nic mi to nie mówi.

Witek

Witam Tworzysz nową klasę o nazwie MyFrame, która dziedziczy po klasie JFrame, tak jak masz to napisane w przykładzie musisz to jeszcze raz dokładnie przeczytać jest bardzo dobrze wyjaśnione.

Akryl

Tak zrobiłem i chyba już to rozumiem.

radek

Czy jest ktoś kto pomógłby zrobić zadanie z diagramami?

bartman001

Można jeszcze zrobić tak: setDefaultCloseOperation(3); zamiast JFrame.EXIT_ON_CLOSE dać 3

Marcin

Hej mam takie pytanko: w klasie 'Test' przy "new MyFrame();" wyskakuje mi błąd "Myframe cannot be resolved to a type" co może być tego powodem?

Marcin

Damn o_o Sorry za moją głupotę, problem rozwiązany. Dzięki wielkie za ten kurs, odwaliłeś kawał ŚWIETNEJ roboty :)

bronkz

spoko tylko ja niemoge odpalic tego programu. biore run as i nic niema dalej

Karol2

Jak zrobić żeby okno automatycznie się maksymalizowało(pełny ekran)?

bartek

setExtendedState(JFrame.MAXIMIZED_BOTH);

Anonim

Jak ustawić ikonke programu??? (ta z lewego gornego rogu)

Witek

Witam Ten kod poniżej wstawia nową ikonkę w lewym górnym rogów zamiast ikonki z logiem Javy masz inową ikonkę w tym wypatku jet to Flaga Włoch Toolkit zdjecie = Toolkit.getDefaultToolkit(); Image imag = zdjecie.getImage("wlochy.jpg"); setIconImage(imag);

bartek

Nie wiem dlaczego ale mi się obrazek nie podmienia ? Ktoś wie dlaczego ? W jakiej ma być lokalizacji ?

Janusz

Gdzie umarł nieźle zapowiadający się kurs? Java Start umarło na Swingu. Już polimorfizm został przedstawiony po łebkach z przykładami na kolekcjach. Początkującemu w żaden sposób nie wyjaśniło to po co to dziedziczenie i interfejsy, bo się z kolekcjami nie zapoznał. Pierwsze okienko graficzne i mamy thread runnable uruchamiany run. Proste dla kogoś, kto poznał wątki javy. Cóż, wątków na tym kursie nie było w ogóle. Autorowi zabrakło czasu i weny twórczej, ale chciał kontynuować kurs, więc skończył zagadnienia GUI na skróty, posiłkując się kodem niezrozumiałym dla początkującego. np: EventQueue.invokeLater(new Runnable() { @Override public void run() { new MyFrame();

Sławek Ludwiczak

<i>Autorowi zabrakło czasu i weny twórczej</i> Niestety to prawda - szczególnie pierwszy wymieniony element

Pedro

A jest szansa, że kurs zostanie reaktywowany?

krzysiek

kurs pierwsza klasa, super robota wykonana ale dołączam się do kolegów :) "my chcemy cd kursu" hehe nie zależnie od tego czy będzie cd. czy nie powodzenia i dziękuję za Twoją pracę.

pawel

wyrzuca mi: Error: Could not find or load main class Test dlaczego?

ja

jak sobie z nim poradziles?

pawel

ok już działa

Marcinowy

Sławku, czy jest szansa, że będziesz się opiekował dalej tym kursem, uzupełniając treści? Siedzę już jakiś czas w javie dlatego dużo łatwiej przełyka mi się elementy które tutaj się pojawiają, ale sądzę, że fajnie by było zrozumieć po co się wstawia tego EventQueue z tymi a nie innymi parametrami i w ogóle. Pozdrawiam i dzięki wielkie

m

szkoda że u konkurencji lepiej jest opisana lekcja

Marcin Kunert

Dobrze, że nasi czytelnicy potrafią korzystać z więcej niż jednego źródła :)

NAME (WYMAGANE)

Witam, ja mam pytanie – dlaczego autor ustawia setDefaultExitAction? Wykomentowalem to i okno sie zamyka. Czy chcial pokazac ze takie cos istnieje czy jest inny powod? //Czytaj więcej na: http://javastart.pl/grafika_awt_swing/pierwszy-program-okienkowy/#ixzz2FycaEQTv

Mateusz

Witam, mam takie pytanie, moze sie wydać błache ale nie wiem w jakiej kolejności mam czytać te kursy. Przeniosło mnie do tego kursu ale nic z niego praktycznie nie rozumiem. Mam klikać porostu następna lekcja i samemu dochodzić ocb czy po koleji lecieciec.

PIotrek 112

Witam chciałbym stworyć silnik gry w Javie a potem wrzucić go na strone HTML. Wiem że to nie jest takie proste chciałbym poprosić jak zacząć pisać taki silnik podstwawy.

fokadobra

Zaczynasz od zaawansowane programowanie, pozniej polecalbym przeczytac przydatne klasy, pozniej efektywne programowanie, dopiero pozniej podstawy jezyka java. Pozostałe czesci to juz jak chcesz.

Alex

Po napisaniu: import java.awt.EventQueue; public class Test { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new MyFrame(); } }); } } Pokazuje mi błąd The method run() of type new Runnable(){} must override a superclass method w @Override

Piotr

Mam pytanie, tworze aplikację w Netbeans, jednak dostaje komunikat że w jednym pliku mogę utworzyć tylko jedną klasę publiczną. A ponadto importy muszę zrobić w górnej części pliku(a nie w środku). Czy autor tworzy obie klasy w osobnych plikach?

bartek

Jeśli chcesz utworzyć klasy w jednym pliku to jedna z nich powinna być bez public. Jeśli obydwie mają być public to powinny być w osobnych plikach.

fdgfd

haha

Damian

Wie może ktoś jaka jest funkcja która zamyka cały program? Chcę zrobić przycisk który będzie wychodził z programu ale nie mam pojęcia jak to zrobić.

Zatherz

dispose();

Janosch

Czy ktoś może odpowiedzieć na moje pytanie? Treść i kod umieściłem na forum bo tutaj coś nie zapisywało gdy chciałem wysłać komentarz. http://forum.javastart.pl/Thread-Pierwszy-program-okienkowy?pid=1071#pid1071

Kaśka

"Tym razem będzie to jednak aplikacja okienkowa a nie tylko tekst na konsoli. W celu ułatwienia sobie pracy skorzystaj ze środowiska Eclipse." Ach, czyżby? Autor tego kursu zakłada oczywiście, że osoby, które pierwszy raz na poprzednich lekcjach poznały środowisko Eclipse, od razu będą w nim smigać??? Niestety kompletnie nie moge sobie poradzić z ta lekcją, próbuję robić na czuja, ale wciąż jakies błedy wyskakują, nie ma w tej lekcji słowa, co jak zrobić z Eclipse, by to zadziałało, tylko sam kod. Kod sprawy nie załatwia niestety... bo błedy wyskakują Szkoda, bo szło tak dobrze chciałam się nawet ten praktyczny kurs wykupić, bo na studiach nie uczą, sesja się zbliża, a tu taki zonk :/ więcej irytacji niż nauki :(

Kaśka

już nie ważne, zagotowałam sie trochę i to mi chyba pomogło rozwiażać problem, zobaczymy jak to dalej pójdzie, może poprzez "metodą prób i błędów" naucze się jakoś tej Eclipse :) Lecimy dalej :)

lolo

A czytałaś: http://javastart.pl/wprowadzenie/eclipse-ide-wstep-i-instalacja/ http://javastart.pl/wprowadzenie/eclipse-ide-pierwszy-projekt/ http://javastart.pl/wprowadzenie/eclipse-ide-uzytkowanie/

H264

Podzielam wypowiedź #48 Kaśka Troszkę czasu mi to zajęło również mimo że programuję także w innych językach. Mimo to uważam że jest to dość dobrze napisane. Wystarczy pomyśleć i uważnie czytać poprzednie lekcje. Dzięki temu wie się jak to działa tutaj. Początkujący którzy są niecierpliwi mogą się zniechęcić, jednak by programować trzeba mieć cierpliwość, zatem uczyć się :-) Idę dalej z kursem, ciekawe jakie będą następne przeszkody...

lukipt

Tyle ze pamietajmy ze to mial byc kurs od zera.. A tu pierwsza aplikacja okienkowa i mamy tylko dwa kody i tyle... Jest napisane utwórz dwie klasy ale skąd to się bierze: import javax.swing.JFrame; już nie ma ani słowa... tylko coś tam rozszerz jrame..

Lolo

Teoretycznie po wcześniejszych lekcjach powinieneś już potrafić zrozumieć to co jest w tej lekcji. import javax.swing.JFrame; Jest to zaimportowanie Klasy JFrame z pakietu Swing znajdującego się w bibliotece Javax. Była wcześniej mowa o dziedziczeniu więc powinieneś wiedzieć co oznacza rozszerzanie klasy.

bartek

Mam taki problem: zmienną typu string mam w głównej klasie (tam gdzie main) i tam wykonuję większość operacji. W drugim pliku typu class mam zadeklarowane buttony i cały interfejs użytkownika. W jaki sposób (proszę o przykład kodu) przypisać wartość z pola text1 do zmiennej typu string w klasie głównej (wewnątrz main) po kliknięciu buttona ?