Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Tworzymy programy okienowe w JAVA z Eclipse+visualswing4eclipse. Część 2

To drugi (i ostatni) wpis z tej serii. Powód: dzięki jednemu z komentarzy dowiedziałem się o jeszcze lepszym sposobie na projektowanie UI w Eclipse bez konieczności płacenia twórcom wtyczki, a mianowicie WindowBuilder. Skupimy się w nim na wywoływaniu dodatkowych okien, np. powiadomień. Zaczynamy!

Główne okno programu

Robimy sobie taki projekt interfejsu jak poniżej:

Od razu sugeruje nam, że program nie będzie skomplikowany, bo nie jest istotą tego przykładu zrobienie „programu do wszystkiego”. Do tego podczas rozciągania/zwężania elementów mogą pojawiać się przerywane linie przy brzegach lub na środku, co zakotwicza widżet w układzie okna — element będzie na stałym miejscu niezależnie od rozmiaru okna. Może się również rozciągać, aby się przystosować do nowego rozmiaru okna.

Sam program ma robić napisy wspak, tak więc program ten nie będzie skomplikowany, chociaż zrobimy sobie model w postaci klasy Napis.

Mając już interfejs i model, utworzymy sobie do każdego z przycisków zdarzenie mouseClicked

Dla jButton0: private void jButton0MouseMouseClicked(MouseEvent event) { String texcik= new Napis(jTextField0.getText()).getOdwrocony(); //odwrócony tekst bez klasycznego tworzenia obiektu jTextField1.setText(texcik); }

Dla jButton1: jTextField0.setText(""); jTextField1.setText("");

Dla jButton2: new AboutDialog().setVisible(true);

Dorabiamy model

Zadaniem klasy Napis jest reprezentacja napisu oraz odwrócenie go. Dla utrzymania minimalizmu, będzie składać się z dwóch konstruktorów, dwóch pól i dwóch metod, ale publiczne będą dwa konstruktory i jedna metoda. Zaczynamy!

Oto szkielet klasy. public class Napis { }

Najpierw wypełnimy go prywatnymi polami: normalny i wspak. Obydwa typu String. public class Napis { private String normalny; private String wspak; }

Teraz utworzymy dwa publiczne konstruktory: bezargumentowy i jednoargumentowy. Tak będzie to wyglądać wewnątrz klasy: public class Napis { private String normalny; private String wspak; public Napis() { normalny=""; wspak=""; } public Napis(String wejscie) { normalny=wejscie; wspak=""; } }

A teraz utworzymy prywatną metodę odwroc() i wstawimy ją za konstruktory (ale wewnątrz klasy). Wygląda ona tak:

private void odwroc() { int len = normalny.length()-1; char[] aarray = new char[len]; for(int j=0; j<len; i++) { aarray[j] = normalny.charAt(len-j); } odwrocony = new String(aarray); }

Jak już mamy metodę odwracającą napis, to zrobimy sobie gettera (taką metodę zapewniającą pośredni dostęp do pól, ale tylko do odczytu), którego zadaniem jest dobranie się do pola odwrocony po to, aby odczytać odwrócony napis. Jego konstrukcja jest następująca:

public String getOdwrocony() { odwroc(); return odwrocony; }

Okno z informacjami o programie

Okno to będzie reprezentowane przez klasę AboutDialog i będzie dziedziczyć po klasie JDialog, tak więc utworzymy klasę odpowiadającą oknu dialogowemu. Będzie wyglądać tak:

Do przycisku dodamy obsługę zdarzenia mouseClicked: private void jButton0MouseMouseClicked(MouseEvent event) { this.setVisible(false); } To spowoduje, że okno dialogowe zostanie zamknięte. Okno dialogowe będzie modalne (do initComponents() dodamy setModal(true)).

Pole tekstowe będzie wypełnione zawartością widoczną na ekranie (poniżej znajduje się kod dotyczący tego elementu): private JTextArea getJTextArea0() { if (jTextArea0 == null) { jTextArea0 = new JTextArea(); jTextArea0.setEditable(false); jTextArea0.setText("Prosty program robiący napisy wspak."); jTextArea0.setAutoscrolls(true); jTextArea0.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent event) { jTextArea0MouseMousePressed(event); } }); } return jTextArea0; }

Następnie dodamy do pola tekstowego zdarzenie mouseEntered: private void jTextArea0MouseMousePressed(MouseEvent event) { easterEgg(); }

Oraz zdarzenie mouseExited: private void jTextArea0MouseMousePressed(MouseEvent event) { jTextArea0.setText("Prosty program robiący napisy wspak."); }

Robimy Easter Egga

Nasz Easter Egg ma być niespodzianką, do której dostęp nie będzie taki oczywisty. Do tego będzie takim szczególnym oknem ze szczególną zawartością. Będzie reprezentować go metoda easterEgg(), którą dodamy do klasy AboutDialog. Jej celem jest zmiana napisu na „Are you as creepy as creeper?”.

A oto cała metoda: private void easterEgg() { jTextArea0.setText("Are you as creepy as creeper?"); }

Podsumowanie

To już koniec przygody z tą wtyczką, bo przeniesiemy się na coś lepszego :D Nauczyliśmy się tworzyć programy z oknami dialogowymi oraz zamykania okien.

Bardziej ciekawskich odsyłam do strony projektu podanej w poprzednim wpisie z tej tematyki oraz do własnych eksperymentów albo do przypatrzenia się generowanemu kodowi, dzięki któremu nauczymy się posługiwania klasami z pakietu javax.Swing.

I na osłodę demonstracja działania programu

 

porady programowanie

Komentarze

0 nowych
budda86   9 #1 26.06.2012 15:54

Może to kwestia gustu i przyzwyczajenia, ale mnie osobiście strasznie drażni nadawanie zmiennym nazw w języku polskim. Wychodzą z tego potworki językowe właśnie takie jak "getOdwrocony()".

I masz strasznie nieczytelne formatowanie kodu.

Sorry że czepiam się może szczegółów, ale warto wyrabiać dobre nawyki bo czytelność kodu ma ogromne znaczenie dla późniejszych kosztów utrzymywania i rozwijania aplikacji.

Autor edytował komentarz.
DanKar REDAKCJA  13 #2 26.06.2012 17:55

@budda86: Masz oczywiście racje, ale z drugiej strony takie potworki językowe są czytelniejsze dla początkujących w przypadku bardziej złożonych programów niż odpowiedniki nazw zmiennych czy metod w języku angielskim. Wiem to z własnego doświadczenia. Pamiętam jak dobrze rozumiałem przykłady z Symfonii Grębosza gdy zaczynałem swoją przygodę z C++. Później w toku studiów nie używałem C++ i kompletnie go zapomniałem. Przyszedł czas na Javę, którą uczyłem się z Thinking in Java, w której przykłady były właśnie ze zmiennymi w języku angielskim i ich dokładna analiza (próba zrozumienia) nie była już tak sprawna jak w przypadku Symfonii i zajmowała więcej czasu.

Autor edytował komentarz.
alucosoftware   7 #3 26.06.2012 20:20

@DanKar
Ale, jak zaznaczył budda86, takie potworki nie wyrabiają dobrych nawyków. Później, młodzi programiści zamiast łańcuchów znaków widzą stringi - a nie o część ubioru tutaj przecież chodzi. Pinglisz sprawdza się dobrze w komentarzach do kodu, nie w nazwach zmiennych :)

BTW:

public String getOdwrocony() { odwroc(); return odwrocony; }

WTF?

Doceniam wysiłek i chęci autora, ale taki kod wyrządza krzywdę początkującym programistom... nadmienię, że na początku swej przygody z programowaniem także chciałem góry zdobywać (z pominięciem podstawowej wiedzy), ale naprawdę - nie tędy droga.

Autor edytował komentarz.
budda86   9 #4 26.06.2012 21:39

@DanKar
Rozumiem, że to może być ułatwienie dla początkujących, ale ja mam już spaczenie zawodowe i oceniam surowo... Poza tym mnie to po prostu razi, choć oczywiście nikomu tutaj niczego nie narzucam.

@alucosoftware
Za to dziewczyny mogą się chwalić, że mają całą kolekcję Stringów ;)

@skrzeczol755
Twój kod jest strasznie niechlujny, a poza tym niepoprawny.

1. Na odwrócony napis tworzysz tablicę o 1 mniejszą niż długość napisu oryginalnego. Przy utworzeniu obiektu klasy Napis z napisem "" (tak jak w bezparametrowym konstruktorze) spróbujesz utworzyć tablicę o rozmiarze -1 i dostaniesz wyjątek. W pozostałych przypadkach odwrócony napis będzie ucięty.
2. W pętli zwiększasz wartość zmiennej i, której nigdzie nie deklarujesz - błąd kompilacji.
3. Po co przy każdym wywołaniu getOdwrocony() odwracać napis? Przecież przy odwracaniu zapisujesz go w polu klasy, wystarczy raz odwrócić i potem zwracać wartość tego pola.
4. Czemu kod nie jest sformatowany? Strasznie źle się to czyta.

Podsumowując - bardzo dobrze, że uczysz się programować. Tak trzymaj i nie ustawaj w wysiłkach. Ale nie próbuj na razie uczyć innych czegoś, z czym sam ledwo sobie radzisz, bo efekt jest niestety opłakany. A wstawianie kodu, który nie tylko nie działa, ale nawet się nie kompiluje, to już wyjątkowe niechlujstwo i lekceważenie czytelnika. Mógłbyś chociaż sprawdzić ten kod przed opublikowaniem wpisu.

Autor edytował komentarz.
kostek135   8 #5 26.06.2012 23:32

proponuje odwracać tak:

String rev = new String(new StringBuilder(text).reverse());

gdzie text, to obiekt klasy java.lang.String przed odwróceniem.
Poza tym co koledzy wyżej wymienili masz błędy w logice tej aplikacji, a raczej hołdujesz podejściu "bo działa". Zauważ, że każde wywołanie pobrania odwróconego napisu przez ten dziwacznie nazwany getter, zmusza do odwracania napisu na nowo. Odwrócony napis powinien być utworzony zaraz po przekazaniu napisu-wzorca do konstruktora. Ewentualnie metody powinny zostać rozdzielone i należy pamiętać o wywołaniu odwrócenia jednorazowo przed wywołaniem gettera. Tak czy siak śmierdzą te atrybuty (nie logiczne z punktu obiektowego): masz klasę napis, która składa się z dwóch napisów de facto, odwrócony napis to też napis. Wystarczy zrobić klasę z jednym atrybutem. Tylko wtedy opakowujesz String (aby go modyfikować) co jest bez sensu, bo modyfikowania napisu dostarcza StringBuilder / StringBuffer, czyli innymi słowy wyważasz otwarte drzwi.

Autor edytował komentarz.
kostek135   8 #6 27.06.2012 23:55

Nie wiem gdzie w pierwszej wersji widzisz do bani. Będzie wyglądał dokładnie jak twój z tym, że pod zmienną napis, przechowywana będzie referencja do już odwróconego napisu, utworzonego po przekazaniu do konstruktora napisu wzorca. + getter, by można było się do tego dobrać. W twoim przypadku jak ktoś zapętli funkcję odwracająca dla długiego wyrazu to będzie robić dużo nie potrzebnych operacji (zakładam po tym co już napisałeś, że chcesz tworzyć każdorazowo nowy napis i go zwracać). To co jest po ewentualnie, to jest ewentualne. Podaje tylko lepszą wersję niż wrzucanie funkcji odwracającej do gettera. Wydaje się to mnie tragiczne. Ale wiesz, jak ktoś będzie chciał to zrobić thread-safe są inne mechanizmy to zapewniające. Nie dywagujemy w tym momencie nad tym.
Poza tym niechlujny kod mało mnie to obchodzi, krytykuję póki co logikę, ci co psioczą na wcięcia to są śmieszni CTRL + SHIFT + F i mam tak jak chcę. W sumie prawdopodobnie już tu nie zajrzę. Myślałem, że będzie tu coś ciekawego n/t menadżerów rozkładu, w ogóle był to powód dla którego tu coś napisałem/przeczytałem.

kostek135   8 #7 28.06.2012 11:29

A jednak napisze jak pytasz, bo to niegrzeczne zostawiać kogoś bez odpowiedzi.

"Do bani i koniec. Wyobraź sobie, że potrzeba ci odwrócić jeden wyraz z połowy wczytanego słownika j. chińskiego. I cio? Za każdym utworzonym obiektem będziesz przygotowywać odwrócone wyrazy? ;) Ile będzie trwać wczytywanie takiego słownika z jednoczesnym odwracaniem? "

Podejrzewam, że O(nlogn) aby wczytać słownik do drzewa AVL i logn, aby znaleźć słowo i potem przy pomocy mojej klasy (albo i bez klasy tą jedną linijką co to ją gdzieś tam wyżęj napisałem) je odwrócić (tu czas zależny liniowo od długości słowa), ale jakie to ma znaczenie?

Btw. zagrałeś nie fair. Twoja pierwsza klasa nie ma jednego pola, które pojawiło się w drugim przykładzie. Stąd myślałem, że każdorazowo, chcesz odwracać słowo.

W słowniku ponadto nie ma słów odwróconych, więc przechowywanie jako węzeł obiektu tej klasy jest sprzeczne z podejściem obiektowym, które ma jak najwierniej odzwierciedlać rzeczywistość poprzez obiekty.
Słownik powinien zawierać same słowa, z niego możesz wyciągnąć słowo (przepisać na kartkę) i sobie je modyfikować (odwrócić, anagram, cokolwiek).

Nie foch, raczej wskazanie byś nie odpisywał, bo jak wyżej nadmieniłem, nie lubię zostawiać kogoś z pytaniem.

Autor edytował komentarz.