Twitter: @grzegg
Kategoria: java, Tagi: - - - .

Java [30] – JavaFX cz. 2: troszkę bardziej złożona aplikacja

Tym razem tworzymy nieco bardziej złożoną aplikację, w której będziemy wprowadzać do niej tekst, który będzie przetwarzany a efekt będzie wyświetlany. Przy okazji poznamy kilka podstawowych kontrolek i dowiemy się jak je uporządkować.

Aplikacja

Nasza kolejna aplikacja będzie miała do wykonania proste zadanie. Użytkownik wprowadzi do niej długa sekwencję nukleotydów, następnie krótszą, a program poszuka miejsc w których krótsza sekwencja będzie występowała w dłuższej i wyświetli wynik. Ponieważ program opiera się na szukania jednych łańcuchów znaków w innych, niekonieczne będzie ją trzeba stosować akurat do sekwencji nukleotydów ale w zasadzie do dowolnego tekstu.

Najpierw warto się zastanowić jak tak aplikacja może wyglądać. Mój projekt wygląda tak:


Jak widać, nie jest szczególnie skomplikowany.
Teraz zastanówmy się, jakich kontrolek będziemy potrzebowali. Może nam w tym pomóc wspomniana w poprzednim wpisie aplikacja Ensemble ale warto też zajrzeć na stronę firmy Oracle z opisem kontrolek
Podpisy do poszczególnych pól, utworzymy za pomocą kontrolki Label służąca zasadniczo do wyświetlania tekstu, choć można w niej umieścić także grafikę.
Sekwencję będziemy wpisywać to kontrolki typu TextArea, która umożliwia wpisywanie wielu linii tekstu.
Do wpisywania szukanej sekwencji, która będzie raczej krótka, posłuży nam TextField, która zawiera jedną linię z ciągiem znaków.
Do wypisywania wyniku użyjemy kontrolki TextArea ale bez możliwości edycji tekstu.
Przyciski – to będą oczywiście kontrolki typu Button znane nam z poprzedniej lekcji.

Teraz warto się zastanowić nad sposobem rozmieszczenia kontrolek. Jak wspomniałem w poprzednim wpisie służą do tego węzły – panele pozwalające na kontrolę rozmieszczenia elementów interfejsu graficznego, niektóre mają w nazwie Pane. Poznaliśmy już StackPane, który umieszczał obiekty na sobie. W naszym przypadku będzie to bezużyteczne. Spróbujmy użyć do naszych celów dwu rodzajów paneli:

  • VBox – pozwala umieszczać elementy pod sobą w pionie (jeden pod drugim)
  • HBox – porządkuje obiekty w poziomie (jeden obok drugiego)

Teraz zastanówmy się jak je wykorzystać w porządkowaniu elementów naszego graficznego interfejsu. Użyję panelu typu VBox jako głównego kontenera, który możemy sobie wyobrazić jako regał z półkami. Z kolei HBox-y będą służyć nam do porządkowania elementów w poziomie. Będą one potrzebne w dwu miejscach: tam gdzie będziemy wpisywać szukaną sekwencję i do rzędu z przyciskami. Można to graficznie pokazać tak:


Na czerwono zaznaczyłem VBox, na niebiesko panele typu HBox.

Zatem czas na umieszczenie tego wszystkiego w kodzie. Sugeruję, zgodnie z instrukcją z poprzedniej lekcji stworzyć domyślą aplikację w JavieFX a potem zmodyfikować plik:

Po uruchomieniu powinniśmy uzyskać takie okienko:


Teraz krótko omówię kilka aspektów powyższego kodu. Po pierwsze zauważ, że każdy z węzłów (paneli i kontrolek), które zostały użyte, posiadają pewne modyfikowalne właściwości. Dotyczą one na przykład ich wymiarów, tekstu, który się wyświetla, możliwości edycji, widzialności itd. Niektóre z tych właściwości są charakterystyczne dla konkretnego rodzaju elementu (np. ustawianie wyświetlanego tekstu dla przycisku czy etykiety ma sens ale byłoby raczej bezcelowe dla panelu VBox). Wszystkie węzły dziedziczą po klasie Node, warto więc zapoznać się jakie właściwości i metody nam oferuje w dokumentacji. Jak zwykle zachęcam do przeglądania dokumentacji interesujących nas węzłów a także podglądania podpowiedzi sugerowanych przez NetBeans. Dużo się można nauczyć sprawdzając działanie poszczególnych metod i zmieniając ustawienia dostępnych właściwości.

Nasza prosta aplikacja potrafiła także pobrać informacje (tekst) z jednych kontrolek i po modyfikacji, umieścić je w innych kontrolkach. Pobieranie odbywało się przy pomocy „getterów” (getText()), przekazywanie informacji przez „settery”(setText()). To oczywiście zaledwie przedsmak modyfikacji wyglądu i zachowania kontrolek i innych węzłów.

Dodajemy klasę odpowiedzialną za zmianę tekstu

Warto by teraz dopisać kod, odpowiedzialny za rzeczywiste wyszukiwanie sekwencji i zaznaczanie miejsc jej występowania. Wyszukiwanie zrealizujemy za pomocą metod udostępnianych przez klasę String o czym była mowa w jednej z poprzednich lekcji. Ale zanim do tego dojdziemy stworzymy dodatkową klasę, w której umieścimy potrzebny kod. Moglibyśmy oczywiście dopisać metody do klasy, którą już mamy, ale jest dobrą praktyką oddzielanie kodu odpowiedzialnego za tworzenie interfejsu od kodu odpowiedzialnego za innego rodzaju operacje, np. wyszukiwanie, obliczenia itd.

Utwórz w pakiecie nową klasę Javy o nazwie Szukacz. W niej umieść statyczną metodę szukaj (String sekwencja, String szukana) i wypełnij ją kodem.

W naszym kodzie zastosowałem metodę statyczną, nie trzeba więc będzie tworzyć obiektu typu Szukacz aby z niej skorzystać. Nie ma ku temu jakichś ważnych powodów, równie dobrze możesz napisać metodę niestatyczną i tworzyć obiekt.

Znajdywanie miejsc występowania szukanej sekwencji można rozwiązać na różne sposoby, na przykład wykorzystując metodę indexOf() klasy String (spróbuj w ramach treningu napisać taką metodę). W moim kodzie użyłem jak widać metodę split(), która po prostu pocięła długą sekwencję na fragmenty występujące pomiędzy szukanymi sekwencjami, jeśli takich nie ma, to nie dochodzi do cięcia i zwracana jest niezmodyfikowana sekwencja wyjściowa. Później z powrotem łączę uzyskane odcinki wstawiając pomiędzy nimi znak <, szukaną sekwencję, która przecież tam się znajduje, znak > i kolejny odcinek długiej sekwencji. Znaki ostrego nawiasu mają oczywiście wizualnie zaznaczyć miejsca, w których znajduje się szukana sekwencja. To jest oczywiście rozwiązanie bardzo proste, ładniej wyglądało by na przykład pokolorowanie odpowiednich miejsc łańcucha znaków ale do takich sztuczek dopiero dojdziemy.

Wykorzystanie split() ma taką wadę, że jeśli szukana sekwencja znajduje się na końcu długiej sekwencji to „ginie” w wyniku pocięcia, stąd dodatkowy test szukający szukanego fragmentu w końcowym odcinku o długości odpowiadającym długości szukanej sekwencji.

Teraz pozostaje zmienić odpowiedni fragment kodu w klasie SzukaczSekwencji odpowiedzialny za akcję wywoływaną przez przycisk Szukaj:

Teraz możemy uzyskać np. taki wynik:


Inne panele

W naszej aplikacji użyliśmy dwóch rodzajów paneli: VBox i HBox, wcześniej poznaliśmy jeszcze StackPane. Zastosowanie tej trójki pozwala na dość dużą swobodę komponowania wyglądu interfejsu graficznego ale nie zawsze jest to najwygodniejsze. Dlatego warto się zapoznać z innymi rodzajami paneli oferowanymi przez JavaFX. Poszerzają one klasę Pane, zajrzyj do jej dokumentacji gdzie znajdziesz także spis dziedziczących po niej węzłów wraz z linkami do odpowiedniej dokumentacji. Jednym z nich jest GridPane, który sprawdza się w wielu przypadkach, ponieważ tworzy „siatkę” co pozwala na łatwe uporządkowanie elementów w rzędach i kolumnach.

Zadanie

Przerób powyższą aplikację tak aby:

  • Uporządkować elementy za pomocą panelu typu GridPane zamiast VBox i HBox. Możesz zmienić układ kontrolek.
  • Aplikacja wyświetlała liczbę znalezionych sekwencji

6 komentarzy Java [30] – JavaFX cz. 2: troszkę bardziej złożona aplikacja

  • Marek

    Dziękuję za kurs :) Naprawdę sporo się już z niego nauczyłem.

    Odnośnie powyższego zagadnienia, stworzyłem klasę Szukacz na swój sposób i chciałem się nim tu podzielić:

    public class Szukacz {

    public static String szukaj (String sekwencja, String szukana) {

    String rezultat = sekwencja.replaceAll(szukana, „”);

    return rezultat;
    }

    }

    Gdy przetestowałem program wszystko działa jak należy. Czy jednak moje rozwiązanie nie jest obarczone jakimiś błędami, których ja jako nowicjusz w tej dziedzinie być może nie zauważyłem??
    Z góry dziękuję za uwagi i pozdrawiam,
    Marek

  • Marek

    Niestety kod nie wkleił się prawidłowo :/ W metodzie replaceAll w miejscu „” wprowadziłem szukany łańcuch znaków okalając go dodatkowo znacznikami w postaci – to tak w skrócie. Mam nadzieję, że teraz będzie ok. Pozdrawiam

  • Marek

    I znowu nie poszło dobrze. Niestety nie jestem jeszcze zbyt zorientowany jak wpisywać kod aby poprawnie wyświetlała go strona www. Mam nadzieję w przyszłości go nadrobić. <>

  • Marek

    replaceAll(szukana, „”);

  • Arek

    Algorytm fajny, szukałem czegoś takiego i dobrze trafiłem, aczkolwiek jest on niedopracowany i może zwrócić zły wynik.
    Załóżmy, że mam ciąg znaków: „aabbcc aabbcc aabbcc”
    Chcę w tym ciągu znaleźć literkę „c”, wynik:
    „aabb aabb aabb”
    Na końcu znajduje tylko jedno „c”. Tak samo gdyby tych „c” było na końcu 10, zwróci tylko jedno. Moje rozwiązanie polega na dodaniu do sekwencji jednej spacji na końcu, wtedy sekwencja zostanie odpowiednio podzielona i wszystkie pojedyncze znaki będą mogły zostać wyszukane.

    Poza tym, zamiast tego:
    if (rezultat.length()==0)
    rezultat = rezultat + pomiedzy[i] + „” + pomiedzy[i+1];

    Można przed pętlą wstawić to:
    rezultat+=pomiędzy[0];

    I usunąć tamten warunek.

    To samo z tym warunkiem:
    if (pomiedzy.length > 1) {

    Można usunąć, ponieważ i tak przed pętlą przypisze nam pierwszy element tablicy pomiędzy[], a jeżeli elementu szukanego nie będzie w sekwencji, wtedy cała sekwencja będzie znajdować się w tym właśnie pierwszym elemencie.

    Jeśli gdzieś popełniłem błąd, to liczę, że mnie poprawicie :)

    Jakby co wklejam mój cały kod (robiłem bez interfejsu graficznego, przy pomocy skanera pobieram od użytkownika dane):

    public static void main (String args[]) {
    Scanner skan=new Scanner(System.in);
    System.out.printf(„Podaj tekst, w którym chcesz coś wyszukać: %n”);
    String tekst=skan.nextLine();
    System.out.printf(„Wpisz szukany tekst: „);
    String szukany=skan.nextLine();
    tekst+=” „;

    String bezSzukanego[]=tekst.split(szukany);
    String rezultat=bezSzukanego[0];
    for (int i=0;i<bezSzukanego.length-1;i++){
    rezultat+="”+bezSzukanego[i+1];
    }

    System.out.print(rezultat);
    skan.close();
    }}

    Liczę na odpowiedź, ewentualną dyskusję, pozdrawiam

    • Grzegorz

      Dziękuję za czujność i zwrócenie uwagi na błąd. Teraz nie mam czasu się tym zająć, ale z pewnością do sprawy wrócę.
      Pozdrawiam serdecznie.

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

  

  

  

Rozwiąż zadanie: * Time limit is exhausted. Please reload CAPTCHA.