Lista zadań

Z Wiki Mistrzowie Kodowania
Skocz do: nawigacji, wyszukiwania

W tym projekcie stworzymy aplikację wyświetlającą zadania do wykonania oraz dodamy możliwość dodawania nowych zadań. Utworzymy klasę, która będzie przechowywać zadania wraz z datą. Dodamy kontrolki, które wyświetlą zadanie oraz przyciski, które pozwolą nam na poruszanie się po liście zadań. Stworzymy nowe okno, w którym zapytamy o zadanie. Dodamy także walidację na polu daty.
Umiejętności, które są potrzebne do wykonania tego ćwiczenia to:

  1. znajomość środowiska Greenfoot
  2. znajomość Javy na poziomie tworzenia klas, tworzenia obiektów, pętli oraz instrukcji warunkowych if, wiedza czym jest metoda, pole i zmienna lokalna
  3. umiejętność posługiwania się dokumentacją w Greenfoot
  4. podstawowa znajomość elementów interfejsu użytkownika (GUI), czym jest pole tekstowe, etykieta, okno dialogowe, przycisk

Zaczynajmy!

Wstęp

Zadanie, które wykonamy w tym ćwiczeniu pozwoli Ci zapoznać się z elementami graficznego interfejsu użytkownika. Mówiąc inaczej ze wszystkimi rodzajami elementów, których używamy korzystając z różnych aplikacji. Są to m.in. pola tekstowe, listy rozwijane, menu, przyciski.
Na przykładzie naszego ulubionego Greenfoot-a przejrzyjmy listę kontrolek, które zapewne znasz z innych aplikacji.
Pole tekstowe

Jmk-zadania image136.png

Checkbox

Jmk-zadania image78.png

Lista wyboru

Jmk-zadania image02.png

Menu górne

Jmk-zadania image41.png

Menu kontekstowe

Jmk-zadania image109.png

Suwak

Jmk-zadania image15.png

Przyciski

Jmk-zadania image47.png

To jednak tylko część elementów, każdy z nich ma inne właściwości i używa się ich tak, aby użytkownik aplikacji w jak najprostszy sposób mógł z niej korzystać.

Zapoznanie z Greenfoot GUI Components

Greenfoot posiada rozszerzenie stworzone przez Taylora Borna, które pozwala na używanie takich elementów we własnej aplikacji. Taką aplikację stworzymy właśnie w tym ćwiczeniu. Na początek przyjrzyjmy się oferowanym przez Taylora kontrolkom.
Wyszukaj w google frazy “Greenfoot GUI compoenents” lub wejdź na poniższy link [[1]]. Powinieneś zobaczyć opis rozszerzenia jak na poniższym obrazku.

Jmk-zadania image58.png

Kliknij Open in Greenfoot. Zostanie pobrany plik o rozszerzeniu gfar, który możesz otworzyć w Greenfoot. Kliknij po prostu dwukrotnie na plik lub przez menu Greenfoot otwórz go wybierając kolejno Scenario -> Open, i wskaż na pobrany plik.
Po otwarciu powinieneś zobaczyć okno Greenfoot takie, jak na obrazku poniżej.

Jmk-zadania image101.png

Teraz skompilujmy ten program. Uwaga! Ze względu na to, że w Greenfoocie, który otrzymaliście od nas, już dodaliśmy te klasy, pojawią się ostrzeżenia (kilkanaście), jak na poniższym obrazku. Kliknij po prostu przy każdym OK.

Jmk-zadania image16.png

Po zamknięciu wszystkich wiadomości projekt się skompiluje i Twoim oczom powinno ukazać się okno takie, jak poniżej.

Jmk-zadania image44.png

Poklikaj w aplikacji, zobacz jak działają poszczególne elementy GUI.
Jak możesz zauważyć, świat nazywa się GUI_DemoWorld. Świat, jak w każdej aplikacji, pozwala na dodawanie aktorów. W tym przypadku to kontrolki są aktorami.
Przeanalizujmy strukturę kontrolek.

  1. Wszystkie z nich dziedziczą z klasy GUI_Component, jest to klasa bazowa dla wszystkich kontrolek. Jeśli zajrzysz w jej dokumentację, dowiesz się jakie ma metody i na co pozwalają wszystkie kontrolki. Klasa ta pozwala m.in. na zmianę tła, czcionki, obramowania. Oznacza to, że wszystkie dziedziczące po niej kontrolki mają te metody i możesz ich używać.
  2. Następna klasa to WindowComponent. Jest klasą bazową dla wszystkich podstawowych elementów takich jak lista rozwijana (DropDownList), pole tekstowe (TextBox), przycisk (Button), hasło (Password), itd.
  3. Kolejna klasa bazowa to Window. Jest to klasa bazowa, z której dziedziczą klasy odpowiedzialne za wyświetlanie wyskakujących okien. Jeśli w przykładowej aplikacji wybierzesz Window Examples i któryś z elementów podmenu, to zobaczysz nowe okno.

Zapoznanie z klasą GUI_DemoWorld

W pierwszej kolejności przed przystąpieniem do stworzenia nowego projektu spójrzmy jak wygląda kod klasy GUI_DemoWorld. Pozwoli to na zapoznanie się z tym, jak autor widział wykorzystanie napisanych przez niego klas. Podczas przeglądania kodu zwróć szczególną uwagę na elementu ekranu (przyciski, etykiety), jak nazywają się poszczególne klasy i jakie metody posiadają.
Otwórz klasę klikając na nią dwukrotnie.

Jmk-zadania image144.png

Na początku klasy widać pola, które są kontrolkami. Umieszczono je tutaj, aby mogły być wykorzystane w całej klasie. Zobaczmy jak są inicjowane.

Jmk-zadania image09.png

W konstruktorze, czyli w momencie tworzenia świata, tworzone są obiekty, a ich wartości są przypisane do pól.

Jmk-zadania image74.png

Do pola txtB zostaje przypisane pole tekstowe, w które można wprowadzić własny tekst.
Następnie za pomocą polecenia

Jmk-zadania image139.png

pole tekstowe txtB jest dodawane do świata, aby je wyświetlić. Obiekt ten dodaje się do świata tak samo jak wszystkich aktorów, gdyż właśnie TextBox jest dzieckiem klasy Actor.
Jeśli klikasz na przyciski, możesz zauważyć, że wywołują one pewne akcje. Zobaczmy jeszcze jak to jest obsłużone. W metodzie act() zobaczysz taki oto kawałek kodu:

Jmk-zadania image121.png

W pierwszej instrukcji sprawdzane jest, czy przycisk btnClick został kliknięty. Jeśli tak, to w następnym kroku sprawdzana jest aktualna akcja.

Jmk-zadania image114.png

Jeśli akcja ma polegać na dodaniu do licznika, to za pomocą takiej instrukcji w wyświetlanej etykiecie (label), wartość zostaje zwiększona o 1. Wartość tutaj jest pobierana z pola tekstowego o nazwie lblCounter za pomocą metody getText. Następnie za pomocą wywołania metody z klasy Integer.parseInt napis zostanie zamieniony na liczbę. Dopiero teraz zadziała dodawanie.

Jmk-zadania image30.png
Uwaga! Projekt GUI_Components warto jest mieć otwarty, aby móc się na nim wzorować. Greenfoot może być uruchomiony w kilku oknach.

Założenie projektu

W pierwszym kroku załóżmy nowy projekt w Greenfoot. Pamiętaj, aby użyć Greenfoota dostarczonego przez nas.
Wybierz z menu Scenario -> New i załóż projekt, nazwij go Zadania. Pojawi się okno jak poniżej.

Jmk-zadania image31.png

Stworzenie świata

W tym kroku utwórzmy klasę świata. Na niej będziemy pokazywać odpowiednie kontrolki. Kliknij PPM na klasie World i wybierz New subclass. W nowym oknie wpisz nazwę klasy ListaZadan.

Jmk-zadania image140.png

Skompiluj projekt. Powinieneś zobaczyć czysty ekran.

Jmk-zadania image81.png

Otwórz do edycji tę nowo utworzoną klasę. Dodamy do niej etykiety i pola tekstowe, na których później wyświetlimy zadania.
Zastanówmy się, co jest potrzebne aby pokazać zadanie. Jakie elementy interfejsu użytkownika mogą być nam potrzebne?
Potrzebne będzie nam na pewno pole tekstowe do wyświetlania daty i opisu zadania. Warto dodać też etykiety, które te pola nazwą, tak aby od razu było jasne które odpowiada za wyświetlanie jakiej informacji.
Przejdźmy do klasy i stwórzmy te elementy. Najpierw dodajmy etykietę (Label) i TextBox z opisem zadania. Opis może być duży, więc zróbmy trochę większe pole tekstowe.
Dodaj pole opisBox pod definicją klasy ListaZadan. Będziemy mogli z niego korzystać we wszystkich metodach danej klasy.
Pola można zdefiniować w dowolnym miejscu klasy (oczywiście nie w metodzie i konstruktorach), jednak ze względu na czytelność najlepiej umieszczać je na samej górze, tuż po definicji klasy a przed konstruktorami i metodami.

Jmk-zadania image38.png

Teraz stwórzmy nową metodę w tej klasie, która doda nam etykietę i zainicjuje pole tekstowe. Nowa metoda pozwoli nam lepiej zorganizować kod, zrobić go bardziej czytelnym. Warto aby klasa składała się z małych metod, które są czytelne i posiadają czytelne nazwy. Naszą metodę nazwijmy inicujPodgladZadania. Wykorzystamy tutaj klasę Point z pakietu java.awt. Z tego względu na górze pliku ListaZadan.java musimy dodać odpowiedni import. Pamiętaj o pozostawieniu starego importu, będzie on nam cały czas potrzebny, gdyż używamy między innymi klasy World, która pochodzi z pakietu greenfoot. Klasa Point jest szeroko wykorzystywana w tym scenariuszu. Z założenia miała określać punkt na osi współrzędnych, jednak w tym wypadku będzie oznaczać wielkość obiektu. Konstruktor przyjmuje dwie wartości, pierwsza to szerokość, druga to wysokość. new TextBox(new Point(160, 60) - będzie oznaczać, że ma zostać stworzone pole tekstowe o rozmiarze 160 pikseli na 60 pikseli

Jmk-zadania image113.png

W metodzie stwórz etykietę, za pomocą konstruktora Label(trescOpisu). Następnie stwórz pole tekstowe za pomocą konstruktora TextBox(rozmiar, tekst). Za pomocą setReadOnly możesz ustawić, żeby pole było tylko do odczytu. Następnie wywołaj metodę addObject(element, x, y), która doda obiekt na świat w punkcie (x,y). Obiekt będzie miał rozmiar zgodny z tym co jest podane w konstruktorze za pomocą obiektu klasy Point. Klasa Point jest szeroko wykorzystywana w tym scenariuszu. Z założenia miała określać punkt na osi współrzędnych, jednak w tym wypadku będzie oznaczać wielkość obiektu. Konstruktor przyjmuje dwie wartości, pierwsza to szerokość, druga to wysokość. new TextBox(new Point(160, 60) - będzie oznaczać, że ma zostać stworzone pole tekstowe o rozmiarze 160 pikseli na 60 pikseli

Jmk-zadania image08.png

Teraz wywołajmy tę metodę w bezparametrowym konstruktorze klasy ListaZadan, czyli tam gdzie ją stworzyliśmy. Zauważ, że jest to metoda prywatna i nie można jej wywołać w innej klasie. Dodajmy też wywołanie Greenfoot.start(), które uruchomi nam aplikację tuż po kompilacji.
Konstruktor jest wywoływany podczas tworzenia obiektu, pisząc new Klasa(parametr), wywołujemy właśnie konstruktor, który utworzy obiekt. Klasa może mieć wiele konstruktorów, ale każdy z nich musi mieć różne parametry. Konstruktor może też nie mieć parametrów. Jeśli w klasie nie ma zdefiniowanego konstruktora, posiada domyślny konstruktor bez parametrów. Konstruktor parametrowy wykorzystujemy np. używając klasy Point, której obiekt tworzymy przekazując dwie wartości x i y. Definicja konstruktora wygląda w ten sposób public Point(int x, int y).

Jmk-zadania image119.png

Skompiluj aplikację. Zobaczysz ekran z etykietą i polem tekstowym jak poniżej.

Jmk-zadania image92.png
Zadania do wykonania:
  • zakomentuj linijkę uruchomiającą aplikację (Greenfoot.start), co się zmieniło?
  • zmień wielkość pola tekstowego, jak to zrobić? (zmiana w konstruktorze TextBox)
  • zmień pozycje kontrolek, umieść je wedle uznania, pamiętaj że powinny się znaleźć obok siebie, tak aby wiadomo było jaka etykieta jest do jakiego pola
  • co się stanie, gdy w wywołaniu opisBox.setReadOnly(true), zmienisz wartość true na false? Spróbuj kliknąć i wpisać coś w polu tekstowym

Teraz w sposób analogiczny stwórzmy etykietę i pole tekstowe do terminu wykonania zadania. Dodaj pole w klasie ListaZadan.

Jmk-zadania image34.png

W metodzie inicjujPodgladZadania dodaj kod inicjujący etykietę i pole tekstowe.

Jmk-zadania image51.png

Uruchom aplikację, powinny pojawić się nowe kontrolki.

Jmk-zadania image71.png
Zadania do wykonania:
  • za pomocą metody setBackgroundColor zmień kolor tła, do tego celu użyj klasy Color, która posiada już zdefiniowane podstawowe kolory, dostępne można znaleźć pod adresem [[2]]
Jmk-zadania image106.png

Uwaga! Musisz dodać w tej sytuacji import, który pozwoli na użycie klasy Color. Na górze klasy ListaZadan dodaj:

Jmk-zadania image05.png
  • za pomocą metody setTextColor zmień kolor tekstu, sprawdź po kompilacji jak wygląda aplikacja
  • zmień tło aplikacji za pomocą metody setBackground, wywołaj ją w konstruktorze klasy ListaZadan. Pamiętaj, że musisz dodać obrazek i podać jego nazwę

Klasa zadania

Mamy już podstawowe elementy GUI (ang. Graphical user interface) na których będziemy pokazywać aktualne zadania. Brakuje nam jednak klasy, która będzie reprezentować nasze zadanie. Na ekranie mamy dwie wartości, które są nam potrzebne w zadaniu: termin wykonania i opis. Pierwsza z nich będzie polem typu Date, czyli klasy, która w Javie reprezentuje datę. Drugie pole będzie już znanym nam polem typu String, czyli napisem.

Klasę tworzymy przez wybranie w menu Edit -> New class. Podaj nazwę Zadanie. Jest to klasa pomocnicza, nie jest ona ani aktorem ani klasą świata. Odpowiada ona za przechowywanie danych. Następnie otwórz tę klasę, znajduje się w sekcji Other classes. Usuń zbędne pole x oraz metodę sampleMethod. Kod powinien wyglądać jak poniżej.

Jmk-zadania image104.png

Teraz musimy dodać potrzebne nam pola. Dodajmy jednak na górze pliku w pierwszej kolejności poniższy import.

Jmk-zadania image42.png

Następnie nad domyślnym (bezparametrowym) konstruktorem dodajmy pole z opisem i datą wykonania. Dzięki importowi możesz użyć klasę Date.

Jmk-zadania image48.png

Spróbuj skompilować program, jeśli wszystko napisałeś dobrze program skompiluje się prawidłowo i pojawi się okno aplikacji jak poprzednio. Jeśli pojawią się błędy, spróbuj je rozwiązać na podstawie komunikatu. Komunikaty są także widoczne w przypadku błędu kompilacji na dole klasy, w której pojawił się błąd.
Teraz rozszerzmy klasę o konstruktor parametrowy. Będziemy mogli dzięki temu przekazać wszystkie potrzebne informacje tworząc nowy obiekt zadania.
Zwróć uwagę, że nazwy parametrów konstruktora są takie same jak nazwy pól. Dlatego w konstruktorze piszemy this.opis i this.terminWykonania. Mówimy w ten sposób, że są to pola klasy. Instrukcja this.opis = opis oznacza, przypisz do pola opis tego obiektu zmienną (parametr) opis. Dla uproszczenia możesz zastosować inne nazwy parametrów, w takim wypadku nie pojawia się problem z tymi samymi nazwami zmiennych i nie musisz stosować słówka this.
Stosowanie słówka this jest o tyle wygodne, że nie trzeba wymyślać nowej nazwy parametru.

Jmk-zadania image27.png

Dodajmy jeszcze po dwie metody, które pozwolą pobrać i ustawić wartość dla każdego z pól. Użyjemy tu nazewnictwa Javy. Metoda, która zwraca wartość poprzedzona jest przedrostkiem get, zaś metoda ustawiająca wartość poprzedzona jest przedrostkiem set. Stwórz teraz getter i setter dla opisu i terminu wykonania. Zwróć uwagę, że nowe słowa oprócz pierwszego rozpoczynane są z dużej litery. Nie jest to konieczne, ale bardzo ułatwia czytanie kodu.
Używanie metod do pobierania i zmienia pól w klasie jest dobrą praktyką, gdyż pozwala ukryć pewne rzeczy przed osobą korzystającą z tej klasy. Pozwala łatwiej sterować tym co można zmienić, a co tylko odczytać.

Jmk-zadania image147.png

Ponownie skompiluj aplikację. Staraj się robić to jak najczęściej. Za każdym razem gdy napiszesz jakąś pełną instrukcję. W takim wypadku dużo łatwiej jest znajdować błędy, które przytrafiają się zawsze i wszystkim bez wyjątku.
To już tyle, jeśli chodzi o klasę zadania. Przechowa ona nam wszystko co nas w tym momencie interesuje.

Podgląd zadania w klasie świata.

Przejdźmy teraz do klasy ListaZadan, na której będziemy operować w tej części zadania. Stwórzmy w niej nowe pole o typie Zadanie. Będzie przechowywać aktualnie wyświetlane zadanie

Jmk-zadania image72.png

Teraz zainicjujmy (przypiszmy wartość) wartość pola w konstruktorze ListaZadan.

Jmk-zadania image20.png

Skompiluj program, zobacz czy wszystko działa.
Stwórzmy teraz metodę, która odświeży ekran, przypisując kontrolkom wartości z aktualnego zadania. Nazwijmy ją odswiezEkran. Dodaj ustawienie wartości do opisu zadania.

Jmk-zadania image50.png

Wywołaj teraz tę metodę w konstruktorze klasy, tuż przed uruchomieniem aplikacji.

Jmk-zadania image14.png

Skompiluj program. Sprawdź czy rzeczywiście w polu tekstowym opisu zadania, pojawia się spodziewana wartość “Pierwsze zadanie”. Jak na ekranie poniżej.

Jmk-zadania image133.png

Teraz dodajmy w metodzie odswiezEkran ustawianie wartości w polu terminu wykonania.

Jmk-zadania image28.png

Skompiluj program i zobacz co się stanie. Powyższa instrukcja wywołuje na dacie metodę toString, która jest dostępna w każdej klasie Javy. Pozwala na wyświetlenie każdego obiektu w postaci napisu. Jednak efekt nie zawsze może być taki, jakiego się spodziewamy. Tak jak w tym przypadku.

Jmk-zadania image29.png

Zmieńmy wyświetlanie tak, aby było czytelne dla nas. W tym celu użyjemy klasy SimpleDateFormat, która pozwoli nam łatwo poradzić sobie z wyświetlaniem daty. Najpierw dodajmy jeszcze jeden import java.text.* na górze pliku ListaZadan.

Jmk-zadania image62.png

Teraz dodaj kod jak poniżej. Tworzymy najpierw obiekt klasy SimpleDateFormat o nazwie formaterDawty. Podajemy w jego konstruktorze format w jakim chcemy wyświetlić datę. W naszym przypadku są to wartości:

  • yyyy - czterocyfrowa wartość roku (y - od ang. year),
  • MM - dwucyfrowa wartość miesiąca (M - od ang. month), uwaga muszą być dużymi literami, małe oznaczają minuty,
  • dd - dwucyfrowa wartość dnia (d - od ang. day).

Bardziej szczegółowo jest to opisane w dokumentacji klasy dostępnej pod adresem [[3]].

Następnie wywołujemy metodę format na obiekcie formaterDaty. Do metody przekazujemy datę, którą chcemy wyświetlić. I tak dostajemy już interesujący nas napis. Ustawiamy napis w polu tekstowym terminu wykonania.

Jmk-zadania image06.png

Uruchom kod. Teraz wyświetlany termin powinien być czytelny.

Jmk-zadania image143.png

Przeglądanie listy zadań

W tym kroku skupimy się na stworzeniu listy zadań i przechodzeniu po niej. Na razie stworzymy listę na starcie aplikacji. Zastanówmy się jak najwygodniej będzie przechodzić użytkownikowi po kolejnych zadaniach.
Możemy do tego celu wykorzystać np. dwa przyciski: następne zadanie i poprzednie zadanie. Zakodujmy to.
Stwórzmy najpierw listę zadań. Potrzebny będzie nam import klasy java.util.ArrayList. W klasie ListaZadan dodaj na górze odpowiedni import.
ArrayList to jeden z podstawowych typów Javy. ArrayList pozwala na przechowywanie dowolnego rodzaju danych w postaci listy. Lista charakteryzuje się tym, że wartości są w niej dodawane w kolejności, domyślnie na koniec listy. Elementy na liście są zdefiniowane w kolejności i jeśli nic nie zmieniamy, to możemy je łatwo odczytać. Sprawdźmy jakie metody ma lista i jak możemy jej używać. Należy też pamiętać, że podobnie jak z tablicami elementy są numerowane od zera. To oznacza, że po stworzeniu pustej listy i dodaniu elementu, posiadamy listę o rozmiarze 1, ale wartość pobieramy przez metodę z podaniem indeksu 0, np. lista.get(0). Analogicznie drugi element pobieramy przez podanie indeksu 1, lista.get(1). [https://docs.oracle.com/javase/7/docs/api/java/util/List.html]

Jmk-zadania image112.png

Teraz dodajmy pole z listą zadań, będzie ona przechowywać wszystkie zadania.

Jmk-zadania image100.png

Teraz musimy w konstruktorze dodać kod, który stworzy a następnie doda na listę kilka zadań, tak aby po stworzeniu świata lista nie była pusta. W konstruktorze ListaZadan dodaj na przykład taki kod.

Jmk-zadania image137.png

Jak może zauważyłeś obecnie lista nie jest w żaden sposób powiązana z aktualnym zadaniem. Musimy to poprawić.
Do tego celu będzie nam potrzebne kolejne pole typu liczbowego int. Będzie ono przechowywać indeks (numer z listy) aktualnie wyświetlanego zadania. Będzie to nam potrzebne przy przechodzeniu po liście zadań. Dodaj to pole w klasie ListaZadan.

Jmk-zadania image57.png

Teraz poprawmy kod w konstruktorze, aby ustawiał indeks na 0, będzie to początkowa wartość, a następnie ustawiał aktualne zadania pobierając je z listy. Usuńmy poprzednie przypisanie zadania do pola aktualneZadanie.
Pobieranie elementów z listy możliwe jest za pomocą metody get(int index), która zwraca element spod podanego indeksu. Trzeba pamiętać, że numerowanie rozpoczyna się od zera. Jeśli mamy dwa elementy na liście, to pierwszy z nich pobieramy za pomocą wywołania lista.get(0), a drugi za pomocą lista.get(1).

Jmk-zadania image83.png

Uruchom aplikację. Wszystko powinno działać bez zmian. Powinno pojawiać się pierwsze zadanie z nowej listy. W celu przetestowania, czy to działa, ustaw chwilo wartość indeksAktualnegoZadani na 1 lub 2 i ponownie uruchom aplikację. Czy teraz wyświetlane jest inne zadanie?

Jmk-zadania image118.png

Świetnie, zmień wartość indeksu znów na 0.
Dodajmy teraz przyciski do przechodzenia po liście. Będą to na obiekty klasy Button. Nie musisz dodawać importu, aby z niej skorzystać. Utwórz dwa pola poprzednieZadanie oraz nastepneZadanie.

Jmk-zadania image21.png

Teraz stwórzmy obiekty przycisków i ustawmy je na ekranie. Zróbmy to w nowej metodzie. Dodaj metodę inicujujPrzyciskiNawigacji w klasie ListaZadan i wprowadź kod inicjujący przyciski.

Jmk-zadania image11.png

Czy to już zadziała, czy przyciski się pojawią? Uruchom aplikację, aby się przekonać.
Jak zapewne zauważyłeś, przyciski nie są widoczne. Czy wiesz czego brakuje? Musimy wywołać tę metodę w konstruktorze ListaZadan. Trzeba pamiętać, że deklaracja (kod powyżej) jest zupełnie czymś innym niż wywołanie metody (kod poniżej). Metoda nigdy nie będzie wywołana sama, programista musi wywołać ją jawnie na obiekcie.

Jmk-zadania image115.png

Uruchom teraz aplikację. Czy przyciski są widoczne? Pamiętaj, że możesz poeksperymentować z wyglądem, wielkością i położeniem przycisków.

Jmk-zadania image43.png

Świetnie, ale czy coś się stanie po kliknięciu na przycisk?
Oczywiście, że nie. Musimy to zaprogramować.
Wszystkie kliknięcia na przyciski jesteśmy w stanie obsłużyć w metodzie act. Musimy sprawdzić w niej czy przycisk został wciśnięty. Następnie zależnie od tego czy wciśnięto następny, czy poprzedni musimy zwiększyć lub zmniejszyć indeks aktualnego zadania. Zacznijmy od przechodzenia w przód, czyli sprawdzania czy naciśnięto nastepneZadanie.
Act to jedna z najważniejszych metod w Greenfoot, w niej obsługiwane są akcje w danym punkcie działania aplikacji.
Najpierw dodaj nową metodę w klasie ListaZadan: sluchajNaZmianieZadania, w której umieścimy odpowiedni kod. Pamiętaj o dodaniu metody act i wywołaniu w niej metody sluchajNaZmianieZadania.

Jmk-zadania image91.png

Zwróć uwagę, że kolejność metod nie ma znaczenia. Możemy najpierw wywołać metodę, która jest zakodowana gdzieś poniżej.
Przyjrzyj się metodzie sluchajNaZmianieZadania, zwróć uwagę co się w niej dzieje. Najpierw sprawdzamy w za pomocą if czy wciśnięto przycisk. Metoda wasClicked() zwraca nam wartość true jeśli ktoś wcisną przycisk. W przeciwnym wypadku zwraca false, wtedy nie musimy nic robić. Po wciśnięciu przycisku zwiększamy indeks o jeden.
Uruchom aplikację i wciśnij przycisk “Następne zadanie”. Czy zadanie się zmieniło? Niestety nie, brakuje nam dwóch rzeczy. Czy wiesz jakich?
Musimy przypisać nową wartość do pola aktualneZadanie oraz wywołać metodę odświeżającą ekran. Zróbmy to.

Jmk-zadania image69.png

Uruchom teraz aplikację. I kliknij ponownie kilkukrotnie na przycisk “Następne zadanie”.
Na początku powinno wszystko zadziałać, ale jeśli klikniemy więcej razy niż jest zadań na liście pojawi się błąd. Powinieneś zobaczyć okno jak poniżej.

Jmk-zadania image17.png

Greenfoot pozwoli nawet przejść w miejsce wystąpienia błędu. Kliknij na pierwszą czerwoną linię. Zostaniesz przekierowany w miejsce gdzie jest błąd.

Jmk-zadania image61.png

Błąd pojawia się przy pobieraniu aktualnego zadania. Patrząc na komunikat o błędzie:
Warto nieznane błędy skopiować i wrzucić do wyszukiwarki internetowej. Większość problemów została już rozwiązana i bardzo łatwo jest znaleźć opis rozwiązania na różnych stronach internetowych.
java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
Możemy się domyślić, że chodzi tutaj o próbę pobrania zadania spod indeksu 3. Jednak na liście mamy tylko trzy zadania, a próba pobrania zadania o numerze 3, tak naprawdę powoduje odwołanie do nieistniejącego, czwartego elementu listy. Musimy teraz zrobić pewne obejście.
Dodajmy sprawdzanie czy nie przeszliśmy za daleko i w takim wypadku zacznijmy indeksowanie od początku. Czy wiesz jak to zrobić? Możesz skorzystać z metody size, którą oferuje nam lista. Jak można się domyślić zwraca nam liczbę elementów.

Jmk-zadania image66.png

Uruchom ponownie aplikację. Kliknij kilka razy na przycisk i sprawdź jak działa aplikacja. Po przekroczeniu indeksu lista powinna iść od początku.
Teraz spróbuj napisać podobny kod dla przycisku poprzednieZadanie. Pamiętaj, że teraz chcemy iść wstecz, czyli trzeba zmniejszać indeks aktualnego zadania.

Jmk-zadania image55.png

Uruchom aplikację czy wszystko działa. Jeśli tak to świetnie. Teraz będziemy mogli przejść dalej i dodawać swoje zadania do listy.

Dodawania nowego zadania

Teraz zastanówmy się jak możemy zrobić dodawanie nowego zadania. W większości aplikacji pojawia się nowe okno, które pozwala na wprowadzenie danych. Po ich wprowadzeniu nowe dane pojawiają się na liście.
Spróbujmy to teraz zaimplementować. Zacznijmy od stworzenia nowego okna.
Stwórz nową klasę OknoZadania. Stwórz ją wybierając z menu Edit -> New class. Podaj jej nazwę, następnie otwórz stworzoną klasę. Usuń jak poprzednio niepotrzebne pole x i przykładową metodę
sampleMethod. Pozostaw konstruktor. Klasa powinna wyglądać jak poayList.
W ten sposób tworzymy klasy, które nie są ani aktorami ani klasami świata. Mogą one służyć do np. przechowywania i pobierania informacji, komunikowania się z innymi systemami. Mogą być klasami pomocniczymi, które tworzą metody wykorzystywane przez inne klasy. Możesz patrzeć na takie klasy jak na te, używane przez nas, które są w Javie np. Date, ArrayList.

Jmk-zadania image129.png

Żeby można byłoby ją traktować jako wyskakujące okno musimy zmienić klasę, aby dziedziczyła z klasy Window. Pamiętaj, że klasę Window możesz podejrzeć w projekcie GuiComponents. Dodajmy też wywołanie konstruktora klasy Window w konstruktorze OknoZadania, bez tego aplikacja nie może się skompilować, gdyż klasa Window nie ma bezparametrowego konstruktora. Robimy to przez wywołanie super(super pozwala na odwołanie się do dziedziczonej klasy z jej podklasy).
Dziedziczenie możesz traktować jako rozszerzanie. Rozszerz klasę dodając do jej definicji extends i nazwę klasy, z której następuje dziedziczenie.
Przejdźmy do klasy ListaZadan i dodajmy tam nowe pole z przyciskiem i drugie pole z naszą klasą OknoZadania.

Jmk-zadania image90.png

Zainicjuj te pola w konstruktorze ListaZadan i dodaj przycisk na ekranie.

Jmk-zadania image54.png

Uruchom aplikację, zobacz czy pojawił się nowy przycisk.

Jmk-zadania image43.png

Jak może zauważyłeś, po jego kliknięciu nic się nie dzieje. Dodajmy odpowiednią metodę o nazwie sluchajNaDodaniuZadania w klasie ListaZadan, którą wywołamy w metodzie act. Niech pokaże nam nowe okno wywołując metodę toogleShow, po kliknięciu przycisku. ToogleShow pokazuje okno, gdy jest ukryte lub ukrywa, gdy okno jest widoczne.

Jmk-zadania image84.png

Wywołanie w metodzie act.

Jmk-zadania image77.png

Uruchom aplikację. Po kliknięciu na “Dodaj zadanie” powinno pojawić się mało wyraźne okno z przyciskiem x.

Jmk-zadania image131.png

Jak widać okno nie jest jeszcze zbyt przydatne. Aby dodać zadanie potrzebujemy kliku rzeczy. Zastanówmy się jakich. Na pewno są to pola tekstowe. Etykiety do ich opisu. Przydadzą się też dwa przyciski: dodaj i zamknij.
Przyciski i pola tekstowe dodajmy jako pola klasy OknoZadania, gdyż będą nam później potrzebne w różnych metodach.

Jmk-zadania image79.png

Oczywiście musimy te pola zainicjować i dodać do okna, podobnie jak robiliśmy to dla świata, w konstruktorze OknoZadania.
Ponownie musimy dodać na górze pliku OknoZadania import klasy java.awt.Point, aby móc tworzyć obiekty klasy Point, które wykorzystamy do tworzenia kontrolek.

Jmk-zadania image99.png

Niestety przy pracy z oknem musimy korzystać z kontenerów. Są to takie obiekty, które można traktować jak tabelki. W tabelki wkładamy odpowiednie elementy GUI jak przycisk czy etykieta.
W naszym przypadku potrzebujemy głównej tabeli, który będzie miał wymiar 3x1 (3 wiersze, 1 kolumna), oraz trzech tabelek o wymiarach 1x2 ( 1 wiersz, 2 kolumny). W te trzy tabelki dodamy odpowiednio etykietę i pole dla opisu, etykietę i pole dla terminu oraz w ostatnim dwa przyciski: dodaj i zamknij.
Zacznijmy od zdefiniowania w konstruktorze głównej tabeli (kontenera), etykiety i pola opisu, dodaniach ich do własnej tabeli o rozmiarze 2x1. Na końcu dołączymy główną tabelę do okna.

Jmk-zadania image25.png

Teraz uruchom aplikację, po kliknięciu powinien już zobaczyć pole tekstowe do opisu.

Jmk-zadania image148.png

Teraz w konstruktorze OknaZadania dodaj podobny kod dla terminu wykonania.

Jmk-zadania image105.png

Ponownie uruchom aplikację i sprawdź czy pojawiły się kolejne pola w oknie dodawania zadania.
Spróbuj wpisać różne wartości w pole terminu wykonania. Jak może zauważyłeś możesz ich wpisać różne znaki. Jednak data składa się tylko z cyfr i myślników oraz ma długość 10 znaków. Dodajmy takie ograniczenie na polu terminuWykonaniaBox. W konstruktorze po utworzeniu pola terminWykonaniaBox wywołaj metodę acceptOnly, w której w postaci napisu możesz przekazać dozwolone wartości. Wywołaj też metodę setMaxLength, do której przekażesz maksymalną długość tekstu. Greenfoot ma bardzo przydatną funkcję podpowiadania nazw. Wystarczy, że wpiszesz “terminWykonaniaBox.” i naciśniesz Ctrl+Spacja, wtedy pojawią się podpowiedzi z nazwami pól i metod.

Jmk-zadania image59.png
Jmk-zadania image65.png

Uruchom aplikację i zobacz jakie wartości możesz teraz wpisać w pole termin wykonania.
Jeśli wszystko działa prawidłowo dodajmy jeszcze przyciski dodawania i zamykania okna w konstruktorze OknoZadania.

Jmk-zadania image39.png

Uruchom po raz kolejny aplikację, zobacz czy pojawiły się nowe przyciski.

Jmk-zadania image22.png

Spróbuj kliknąć na przycisk dodaj lub zamknij. Nic się nie dzieje. Musimy oczywiście dodać odpowiednie akcje w kodzie.
Zacznijmy od prostszej akcji zamykania okna. Najpierw dodajmy metodę act w klasie OknoZadania. W metodzie dodajmy sprawdzanie czy kliknięto przycisk zamknij. Jeśli tak ukryjmy okno metodą toogleShow. Na samej górze metody act wywołaj super.act(). Wywołanie super.act() spowoduje, że wywołana zostanie najpierw metoda act z dziedziczonej klasy Window. Dodano już tam odpowiedni kod i jeśli nie chcemy zmieniać podstawowego zachowania tej klasy, musimy wywołać właśnie tę instrukcję, która po prostu uruchomi metodą z dziedziczonej klasy.
Użycie super to jedyny sposób do odwołania się do nadpisanej metody.

Jmk-zadania image117.png

Uruchom aplikację i zobacz czy pojawia się okno. Przetestuj działanie przycisku zamknij.

Zadanie do wykonania:
  • Pola po zamknięciu nie są czyszczone. Za pomocą metody setText ustaw wartości pól na puste po zamknięciu

Teraz dodajmy akcję dla przycisku dodaj. Musi ona sprawdzać kliknięcie przycisku. Następnie musi pobrać dane z pola opis i termin wykonania. Następnie trzeba stworzyć zadanie i przypisać je do pola w klasie.
Najpierw dodajmy pole w klasie OknoZadania, które przechowa dodawane zadanie.

Jmk-zadania image138.png

Będziemy potrzebować klasy java.util.Date. Dodajmy odpowiedni import w klasie OknoZadania.

Jmk-zadania image98.png

Teraz w metodzie act dodajmy kod, który sprawdzi wciśnięcie przycisku dodaj. pobierze dane z pól tekstowych. Stworzy nowe zadanie i przypisze do pola wprowadzoneZadanie. Na końcu musimy ukryć okno.

Jmk-zadania image141.png

Na razie nie pobieramy daty z pola terminu, zajmiemy się tym za chwilę. Póki co wywołujemy domyślny konstruktor new Date(), który tworzy obiekt z aktualną datą.

Tutaj jako zadanie dodatkowe także możesz dodać czyszczenie pól.

Teraz skompiluj program. Zobacz czy wszystko działa prawidłowo. Spróbuj wprowadzić dane i kliknij zapisz zadanie. Czy zostało dodane nowe?
Oczywiście, że tak się nie stało. Brakuje jeszcze po stronie klasy ListaZadan sprawdzania czy stworzono w oknie nowe zadania. To w niej trzeba dodać zadanie na listę. Musimy móc je przekazać do tej klasy. Dodajmy jeszcze w klasie OknoZadania metodę pobierzWprowadzoneZadanie, która zwróci wprowadzone zadanie, ale także je wyczyści.

Jmk-zadania image88.png

W ten sposób wywołując tę metodę możemy sprawdzić czy w oknie zostało dodane zadania i jeśli tak się stało pobrać je. Pole wprowadzoneZadanie musi być czyszczone, ponieważ jeśli za każdym wywołaniem tej metody zwracalibyśmy zadanie, to aplikacja dodawałaby je w nieskończoność i po prostu pojawiłby się błąd, a aplikacja zamknęłaby się.

Jako ćwiczenie możesz sprawdzić co się stanie, gdy nie będzie czyszczenia wartość, czyli gdy usuniesz linię wprowadzoneZadanie = null.

Przejdźmy do klasy ListaZadan i jej metody sluchajNaDodaniuZadania. Musimy umieścić w niej kod, który wywoła wcześniej dodaną metodę pobierzWprowadzoneZadanie z okna dodawania zadania. Jeśli zostanie zwrócona wartość, a nie null, to dodajmy zadanie na listę i uwaga, zmieniamy indeks aktualnie wyświetlanego zadania i samo aktualne zadanie na ostatnio dodane. Odświeżamy okno. Dzięki temu od razu będziemy mieli podgląd nowego zadania.

Jmk-zadania image96.png

Uruchom aplikację. Dodaj zadanie. Czy pojawiło się kolejne zadanie na liście?
Teraz możemy wrócić do pobierania terminu wykonania. Aby pobrać termin musimy zmienić napis String na datę Date. W tym celu wykorzystamy znaną już nam klasę java.text.SimpleDateFormat.
Przejdźmy do klasy OknoZadania. Dodajmy tam odpowiedni import.

Jmk-zadania image60.png

Teraz stwórzmy metodę, która pobierze nam z pola termin wykonania i zmieni go na datę. Utwórz metodę wczytajTermin w klasie OknoZadania. Jeśli pojawi się błąd w formacie zwróćmy aktualną datę.

Jmk-zadania image122.png

Najpierw tworzony jest obiekt parser. Pozwoli on nam na łatwą zamianę tekstu na datę. Następnie wywoływana jest metoda parser.parse(data), która próbuje konwertować napis na obiekt klasy Date. Jeśli się nie uda pojawi się wyjątek który łapiemy przez zastosowanie try - catch, dzięki czemu wiemy, gdy data jest zła i będziemy mogli odpowiednio zareagować. Jest to sposób na walidację (sprawdzenie) daty.
Wyjątki są skomplikowanym mechanizmem. Mogą pojawić się, gdy użytkownik aplikacji zachowuje się w nieprzewidziany sposób, na przykład przekazując datę w nieznanym formacie lub gdy program został źle napisany. Jeśli nie przechwycimy niektórych wyjątków, aplikacja może się nie skompilować. Za pomocą try{ kod mogący powodować błąd }catch(Exception e){kod do wykonania w przypadku błędu}, mówimy że jeśli w klamrach po try pojawi się błąd to należy go złapać (catch(Exception e)) i wykonać kod po bloku catch. Exception e deklaruje nam wyjątek i pozwala użyć go za pomocą zmiennej e (można ją nazwać dowolnie), aby np. sprawdzić co poszło nie tak.
Teraz użyjmy tej metody przy tworzeniu zadania w metodzie act. Zmieńmy sposób tworzenia zadania, tak aby jako datę otrzymywał wprowadzony termin. Pamiętaj o przekazaniu do metody wczytajTermin wartości pola tekstowego terminWykonaniaBox.

Jmk-zadania image134.png

Teraz uruchom aplikację i dodaj nowe zadania. Wprowadź datę, pamiętaj, że musi być w formacie rok-miesiąc-dzień np. 1939-09-01. Dodaj też zadanie z błędną datą, powinno wtedy wprowadzić aktualną datę.
To już wszystko. Jako ćwiczenia dodatkowe możesz wykonać rozszerzoną wersję zadania, gdzie będziesz miał możliwość zapisu danych do prawdziwej bazy danych.

Lista zadań do wykonania - ZAAWANSOWANE

W tej części ćwiczenia prześlemy listę zadań przez internet do bazy danych Mongo, którą założymy na stronie internetowej [https://mongolab.com].
Zaczynajmy! Przypominam, że potrzebna jest nasza wersja Greenfoot.

Rozszerzenie klasy zadania

Zacznijmy od stworzenia klasy IdObiektu. Będzie ona przechowywać jedno pole z id zadania. Dzięki id będziemy rozróżniali zadania. Będzie nam to potrzebne przy ich zapisie do bazy danych i późniejszym odczycie.
Id traktuj jako unikalny identyfikator, coś co wyróżnia dany obiekt wśród innych. Możesz porównać ten identyfikator do numeru ucznia w dzienniku szkolnym. Każdy uczeń w klasie ma swój numer, który jest niezmienny. Podobnie zachowuje się identyfikator.
Stwórz nową klasę: Edit -> New Class. W edytorze usuń pole x oraz przykładową metodę.
Dodaj pole id typu String, oraz stwórz dwie metody: getId oraz setId. Pierwsza z nich zwraca id, a druga ustawia id.

Jmk-zadania image33.png

Metody muszą nazwać się get(NazwaPola) i set(NazwaPola). Jest to pewien standard, który w tym wypadku będzie nam potrzebny do przesyłania danych do bazy danych.
Dodajmy od razu jeszcze jedną rzecz. Jest to pewna ciekawostka.
Najpierw dodaj, na samej górze otwartej w edytorze klasy, linię z potrzebnym dla nas importem.

Jmk-zadania image32.png

Następnie dodaj taką konstrukcję przy polu id. Bardzo ważna jest tutaj kolejność.

Jmk-zadania image13.png

@SerializedName jest adnotacją. Dostarcza ona dodatkowych informacji, które są potrzebne przy przesyłaniu danych do bazy Mongo. We fragmencie kodu, który właśnie napisaliśmy, mówimy kompilatorowi, żeby traktował to pole jakby miało nazwę $oid. Musimy zastosować adnotacją nad nazwą pola, jest to wymóg Javy, aby adnotacja pojawiała się nad: polem, metodą, klasą.
Skompiluj aplikację. Zobacz czy wszystko działa poprawnie i nie zrobiliśmy nigdzie błędu.
Przejdźmy do klasy Zadanie. Przechowuje ona dane o zadaniu. Dodajmy nowy import.

Jmk-zadania image110.png

Następnie rozszerzmy klasę zadania, dodając pole id o typie IdObiektu, z odpowiednią adnotacją.

Jmk-zadania image19.png

Podobnie jak w klasie IdObiektu, dodajemy tutaj adnotację do pola id, podając własną nazwę.
Potrzebujemy jeszcze metod pobierających i ustawiających id (get oraz set).

Jmk-zadania image18.png

Takie rozszerzenie pozwoli przechowywać nam dane w bazie Mongo.

MongoDB

Mongo jest bazą danych. Oznacza to, że można w niej przechowywać interesujące nas informacje, które mają być bezpiecznie i trwale zachowane.
Jeśli pamiętasz przykład z zapisem ocen do pliku, to być może pamiętasz, że zapis pozwalał na ponowny odczyt danych z pliku. Załadowanie poprzedniego stanu aplikacji, tzn. ocen i uwag, uczniów i przedmiotów, które były wprowadzone wcześniej.
Baza danych pozwala na coś podobnego, jednak ma kilka innych zalet. Może być udostępniana wielu aplikacjom jednocześnie, nawet jeśli są uruchomione na różnych komputerach. Baza danych ma też wiele mechanizmów, które dają dodatkowe bezpieczeństwo.
W ćwiczeniu z listą zadań masz okazję użyć bazy danych. Jest to wcześniej wspomniana baza danych Mongo. Wybraliśmy ją także dlatego, że w internecie można założyć bezpłatnie bazę danych i z niej korzystać. Wystarczy mieć dostęp do sieci.

Założenie bazy danych

Bezpłatnie bazę danych możemy założyć przez serwis [https://mongolab.com/].
Wejdź na powyższą stronę.

Jmk-zadania image86.png

W prawym górnym rogu wybierz Sign up (zarejestruj). Wprowadź swoje dane logowania. Pamiętaj o kliknięciu w link Master Services Agreement i zaznaczeniu ptaszka przy I accept MongoLab’s … . Account name może być takie jak Username.

Jmk-zadania image12.png

Zostaniesz przekierowany na nową stronę. Pojawi się informacja o konieczności potwierdzenia adresu email.

Jmk-zadania image108.png

Wejdź na swoje konto mailowe i otwórz email z prośbą o weryfikację (Verify your MongoLab email address).

Jmk-zadania image53.png
Jmk-zadania image135.png

Kliknij na wskazany link. Zostaniesz przekierowany na swoje konto w MongoLab.

Jmk-zadania image23.png

Teraz stwórzmy nową bazę danych, której użyjemy w niniejszym projekcie . Masz do wykorzystania 512 MB, co jest całkiem sporą ilością danych (o ile nie będziesz tam przechowywać plików: filmów, muzyki, obrazów, dokumentów etc.).
Przejdź na stronę główną.

Jmk-zadania image26.png

Wybierz Create new. Pojawi się nowa strona z ustawieniami Twojej bazy.

Jmk-zadania image123.png

Wybierz na samej górze ikonkę jedną z ikon. Są to nazwy dostawców, którzy rzeczywiście będą przechowywać dane. W tej chwili nie ma znaczenia co wybierzesz, bo wszyscy oferują darmową wersję do wspomnianego 0,5 GB danych.
Poniżej wybierz Single-node. Na dole w sekcji Standard Line wybierz Sandbox.

Jmk-zadania image73.png

Przejdź poniżej i wybierz MongoDB version 2.6.x.
Jeśli widzisz sekcję Security wybierz Not applicable. Jest ona widoczna tylko dla niektórych dostawców.
Podaj nazwę swoje bazy danych np. zadania.
Wybierz Create new MongoDB deployment.

Jmk-zadania image07.png

Zostanie stworzona baza danych i następuje przekierowanie na ekran do jej zarządzania.

Jmk-zadania image94.png

Kiedy klikniesz na nazwę bazy danych, nastąpi przekierowanie na ekran, w którym możesz nią zarządzać.

Jmk-zadania image10.png

Widzisz ostrzeżenie, że nie posiadasz użytkownika i należy stworzyć nowego. Kliknij na zakładkę Users.

Jmk-zadania image67.png

Wybierz Add database user i wprowadź dane użytkownika bazy danych.

Jmk-zadania image89.png

Kliknij Create-na liście użytkowników zobaczysz właśnie stworzonego.

Jmk-zadania image128.png

Żeby korzystać ze stworzonej przez nas aplikacji, musisz zrobić jeszcze jedną rzecz, a mianowice pozwolić na dostęp do aplikacji przez internet (dokładniej mówiąc - przez serwisy REST wystawione na protokole HTTP).
W tym celu kliknij na nazwę użytkownika w prawym górnym rogu.

Jmk-zadania image37.png

Pojawi się ekran do zarządzania użytkownikiem.
Możesz tutaj zmienić nazwę użytkownika, adres email, hasło, a nawet wprowadzić dwustopniową autoryzację.
Nas jednak interesuje sekcja umieszczona na samym dole.

Jmk-zadania image146.png

Podany tam jest API Key. Jest to klucz, który pozwala nam łaczyć się z naszym kontem w MongoLab i korzystać z naszych baz danych.
Poniżej jest jeszcze możliwość włączenia dostępu przez serwisy korzystające z REST. Włączenie tej opcji nie jest niezbędne do korzystania przez aplikację do zarządzania zadaniami.
Wybierz Enable Data API access.

Jmk-zadania image95.png

Potwierdź klikając Enable.
Status powinien zmienić się na Enabled - tak, jak poniżej.

Jmk-zadania image40.png

Na razie to wszystko. Możesz już korzystać z MongoDB w aplikacji do zarządzania zadaniami.

JSON

JSON jest sposobem przechowywania i przesyłania danych. W informatyce wykorzystuje się bardzo wiele sposobów przechowywania danych.
Zawsze jednak można traktować te zapisy jako dane binarne lub tekstowe.
Różnica jest taka, że dane tekstowe są czytelne dla użytkownika. Przykładem jest zwykły plik tekstowy, na przykład taki, jak poniżej:.

Jmk-zadania image24.png

Jednak, gdy w notatniku otworzysz plik pdf, to zobaczysz dane podobne do tych poniżej. Ewidentnie nie da się ich odczytać bez rozumienia ich “zapisu binarnego”.

Jmk-zadania image68.png

Dane w formacie JSON są danymi tekstowymi. Są czytelne dla człowieka. Ich zapis także je strukturyzuje. Jeśli przyjrzysz się jak wyglądają dane zapisane w MongoDB i przyjrzysz się klasie Zadania z aplikacji, to możesz zauważyć, że zapis odzwierciedla jednoznacznie pola w klasie.

Jmk-zadania image125.png
Jmk-zadania image03.png

Wszystkie pola są odzwierciedlone w zapisie JSON. Obiekty zagnieżdżone są także objęte klamrą {}.
W zapisie JSON po lewej stronie dwukropka ( : ) znajdują się klucze (w Javie odpowiadają nazwom pól), a po prawej wartości.
Przecinek pozwala na wymienienie kolejnych pól.
Klamry {} mówią, że jest opisywany obiekt (w Javie nazywamy go klasą). Obiekty mogą być zagnieżdżone.
Z kolei, gdy chcesz wymienić kilka obiektów po sobie, stosujesz nawiasy kwadratowe [ ].

Jmk-zadania image82.png

Klasa SerwisMongo

Jest to klasa, która pozwala na zarządzanie bazą w MongoDB. Przyjrzyjmy się jej dokładniej.

Jmk-zadania image85.png

W klasie na początku zdefiniowane jest pole ze słowami static final. Oznacza to stałą: wartość, która jest zawsze taka sama i nie można jej zmienić. Tutaj jest podany adres bazowy dostępu do bazy danych.
Kolejne trzy pola to API Key. Jak wspomniałem w poprzednim rozdziale jest to wartość, po której możesz dostać się do bazy danych.
Następne pola to nazwaBazy i nazwaKolekcji. Są to dwa pola, które przechowują informację o tym, w jakiej bazie i w jakiej kolekcji przechowywać zadania. Możesz tworzyć różne bazy danych dla różnych aplikacji. Możesz mieć również różne kolekcje obiektów (np. zadań), dla różnych użytkowników. Tak aby mieć łatwy dostęp do danych konkretnego użytkownika.
Pole klasa mówi, jakie obiekty będzie przechowywać i odczytywać za pomocą tego serwisu.
Wszystkie te wartości podajesz w konstruktorze i są one wymagane, aby połączyć się z bazą danych i pracować z serwisem.

Jmk-zadania image76.png

Jeśli spojrzałeś w kod klasy, to pewnie zauważyłeś jest jeszcze jedno pole.

Jmk-zadania image145.png

Gson jest to obiekt, który pozwala na zamianę obiektu klasy na zapis w postaci napisu (String), w formacie JSON. Dane w postaci JSON są wysyłane i odbierane z bazy MongoDB, dlatego jest nam potrzebna taka klasa. Korzystamy z dwóch metod.

Jmk-zadania image111.png

Lub bardziej przejrzyście.

Zadanie zapisaneZadanie = gson.fromJson(rezultat, Zadanie.class);

Metoda fromJson konwertuje napis rezultat na obiekt klasy Zadanie.

Jmk-zadania image142.png

Metoda toJson przekształca obiekt klasy Zadanie na napis (String).
Jest jeszcze jedno wywołanie, trochę bardziej skomplikowane.

Jmk-zadania image93.png

To wywołanie konwertuje napis na tablicę specjalnych obiektów Json.
W klasie ZadaniaMongo mamy też trzy metody. Postaram się opisać każdą z nich.
Metoda dodajZadanie.

public T dodajDoKolekcji(T obiekt) {
   try {
       String adresPobieraniaKolekcji = MONGO_URL + nazwaBazy + "/collections/" + nazwaKolekcji + "?apiKey=" + apiKey;
       String obiektString = gson.toJson(obiekt);
       String rezultat = Request.Post(adresPobieraniaKolekcji)
               .bodyString(obiektString,     ContentType.APPLICATION_JSON)
               .execute()
               .returnContent().asString();
       T zapisaneZadanie = gson.fromJson(rezultat, klasa);
      return zapisaneZadanie;
     } catch (IOException e) {
       System.out.println("Nieudany zapis obiektu");
       e.printStackTrace();
   }
   return null;
}

Metoda przyjmuje obiekt, który ma zapisać. Zwraca dodany obiekt. Nie widać tego w kodzie, ale ma uzupełnione id.
W linijce 3 tworzony jest adres URL (taki adres jaki widzisz i wpisujesz w przeglądarce internetowej w pasku adresu), na przykład:

Jmk-zadania image103.png

Tutaj jest to adres, który trzeba podać, aby dodać obiekt.
W linii 4 zapisana jest zmiana obiektu na napis. Tak, aby był czytelny dla MongoDB.

Jmk-zadania image36.png

Obiekt, który będziemy przesyłać do Mongo, nie ma podanego id.
W linijce 5 zaczyna się bardziej skomplikowana operacja. Na klasie Request wywoływana jest metoda Post z podanym adresem URL. W linijce 6, na zwróconym przez metodę Post obiekcie, wywołana jest metoda bodyString z przekazanymi danymi w postaci napisu (stworzone w 4 linii).
W linii 6 wywoływane jest żądanie. Dopiero teraz przez internet wysyłana jest informacja do MongoDB z żądaniem dodania nowego obiektu.
Linia 7 jest wywołana, gdy Mongo doda obiekt i zwróci odpowiedź. Ta linijka mówi, aby zwrócona odpowiedź została pobrana i zamieniona na napis (String). Napis jest przypisany do zmiennej rezultat. W tej zmiennej powinniśmy mieć taki oto napis (bez numerów linii):

Jmk-zadania image107.png

Teraz pozostaje nam już tylko przekonwertować napis na obiekt klasy, który został podany w konstruktorze serwisu. Odpowiada za to linijka 10.
Zaś w linijce 11 obiekt jest zwracany jako wynik wywołania metody.
W linijkach 2 oraz 12-15 mamy przechwycenie wyjątku. Jest to związane z tym, że podczas łączenia się z internetem dochodzi do różnych sytuacji (jak np. brak zasięgu), w których dane nie mogą zostać zwrócone. Dlatego niektóre metody klasy Request wyrzucają wyjatek IOException, który przechwytujemy i wypisujemy.
Jeśli wystąpił wyjątek, to kod dojdzie do linijki 16 i zostanie zwrócony null.
Pozostałe dwie metody to:

  • pobierzWszystkie - zwraca listę obiektów z kolekcji
  • aktualizuj - zmienia obiekt o podanym id jako pierwszy parametr.

Obie metody są bardzo podobne. Różnica polega głównie na wywołaniu adresów i rodzaju wywołań (Post, Get, Put) oraz przesyłanych danych. Co i jak trzeba przesyłać opisane jest w dokumentacji MongoDB. Jest ona dostępna pod adresem: [http://docs.mongolab.com/data-api/].

Dodanie zapisu zadań w bazie Mongo

Teraz dodamy kod, który pozwoli zapisać nasze zadania w bazie danych.
Zacznijmy od dodania pola z serwisem w klasie ListaZadan, który będzie odpowiadał za obsługę MongoDB. Znajdź swój ApiKey, nazwę bazy danych i kolekcji. Jeśli pracujesz z kilkoma uczniami lub kolegami, możesz korzystać z jednego ApiKey i jednej bazy danych -podajesz tylko inne nazwy kolekcji.

Jmk-zadania image35.png

Teraz na starcie aplikacji zaczytajmy listę zadań. Zrób to w konstruktorze, przed wywołaniem metody odswiezEkran.

Jmk-zadania image87.png

Usuń stary kod tworzenia listy zadań. Trzeba także sprawdzić czy pobrana lista nie jest pusta. Musimy też w metodzie odśwież zadanie sprawdzać czy aktualneZadanie nie jest nullem.

Jmk-zadania image70.png

W przeciwnym wypadku pojawi się błąd.
W metodzie sluchajNaDodaniuZadania przed dodaniem do listy zapisz obiekt w bazie danych. Następnie zwrócone przez dodajDoKolekcji zadanie dodaj do listy zadań, wyświetlanej na ekranie.

Jmk-zadania image75.png

Ostatni krok to poprawienie metody inicjujPodgladZadania, aby ustawiała na starcie puste pola.

Jmk-zadania image132.png

Uruchom aplikację i przetestuj dodawanie. Następnie zamknij aplikację i uruchom ponownie. Czy zadania się pojawiły?
Sprawdź jeszcze czy nowo dodane zadania faktycznie pojawiły się w bazie MongoDB.

Pogląd danych

Gdy uruchomisz aplikację i dodasz kilka pierwszych zadań możesz na stronie MongoLab przejrzeć dane, które zapisałeś do bazy danych.
W tym celu zaloguj się do konta MongoLab na stronie [https://mongolab.com/].
Przejdź do swojej bazy danych klikając na jej nazwę.

Jmk-zadania image116.png

Pojawi się ekran z kolekcjami (traktuj je jak grupy danych).

Jmk-zadania image127.png

Po wejściu na kolekcje można zobaczyć, co jest w niej przechowywane. Wygląda to mniej więcej tak, jak na zrzucie ekranu poniżej.

Jmk-zadania image80.png

Można tutaj dokładnie odczytać jak wyglądają dane.
Przyglądając się pierwszemu wpisowi można odnaleźć id obiektu, ale także opis, datę wykonani. Czyli jest to dokładnie to samo co można zobaczyć w aplikacji Zadań. Jedyna różnica jest taka, że id obiektu ukrywamy przed użytkownikiem.
Uwaga! Te dane możesz zmienić lub je usunąć, wystarczy wybrać odpowiednią opcję po prawej stronie wiersza.

Zapis do pliku

W tej części dodamy zapis danych do pliku tekstowego.
Zacznijmy od dodana przycisku jako pole w klasie ListaZadan.

Jmk-zadania image00.png

Teraz ustawmy ten przycisk na ekranie. Dodajmy metodę inicujPrzyciskiPlikow, w której stworzymy przycisk i dodamy na ekran.

Jmk-zadania image52.png

Wywołajmy metodę w konstruktorze ListaZadan.

Jmk-zadania image130.png

Uruchom aplikację i zobacz czy przycisk się pojawia.

Jmk-zadania image97.png

Teraz dodajmy metodę, która będzie zapisywać dane. Nazwijmy ją zapiszDane. Musi ona przejść po liście zadań. Stworzyć dla każdego zadania napis, rozdzielając wartości średnikiem ;. Wszystkie wartości ma dodać na listę, a listę zapisać za pomocą klasy Pliki i metody zapisz.

Jmk-zadania image124.png

Najpierw tworzymy formater daty. Następnie w pętli for idziemy zadanie po zadaniu. Dla każdego zadania zamieniamy datę na napis. Później tworzymy linię, zwróć uwagę, że z pola id zadania jest pobierane kolejne id, gdyż to jest wartość napisu. Wartości w linii rozdzielamy średnikiem, aby móc łatwo rozdzielić wartości przy wczytaniu danych.
Linię dodajemy do listy. Na końcu wywołujemy zapis do pliku o nazwie “plik.csv”.
Teraz musimy dodać metodę nasłuchującą na wciśnięcie przycisku. Nazwij ją sluchajNaPrzyciskachPlikow. I wywołać w niej zapiszDane.

Jmk-zadania image45.png

Teraz metodę słuchającą wywołaj w metodzie act.

Jmk-zadania image49.png

Uruchom aplikację, upewnij się, że istnieją zadania, jeśli nie to dodaj nowe i wciśnij przycisk zapisz plik. Teraz przejdź do katalogu w którym jest projekt. Powinien się naleźć w nim plik plik.csv. Otwórz go za pomocą notatnika lub w programie excel lub calc. Powinieneś zobaczyć dane podobne do tych.

Jmk-zadania image46.png

Lub w excel.

Jmk-zadania image04.png

Są tu kolejno zapisane: id zadania, opis, data.

Odczyt pliku

Teraz dodamy jeszcze funkcjonalność odczytu z pliku.
Zacznijmy podobnie od zdefiniowania pola przycisku wczytajPlik.

Jmk-zadania image126.png

Następnie dodaj go na ekranie, dodając inicjację w metodzie inicjujPrzyciskiPlikow.

Jmk-zadania image56.png

Uruchom aplikację i sprawdź czy pojawił się nowy przycisk.

Jmk-zadania image64.png

Teraz musimy dodać metodę, która pobierze dane. Nazwij ja wczytajDane.

Jmk-zadania image01.png

W metodzie tej najpierw za pomocą klasy Pliki i metody wczytaj pobierany jest wcześniej zapisany plik. Dane są pobrane za pomocą listy linii, podobnie jak zapisywaliśmy.
Następnie tworzony jest formaterDaty potrzebny do zamiany daty na napis. Następnie czyścimy aktualną listę zadań.
W kolejnym kroku idziemy w pętli for linia po linii. Każdą linię rozdzielamy po średniku metodą split, która tworzy tablice. W pierwszej wartości tablicy będzie id, w kolejnej opis, a w ostatniej terminWaznosci.
Najpierw odczytujemy datę za pomocą formatera. Kod jest podobny do tego, który został użyty przy odczycie wartości z pola terminWaznosci w oknie dodawania zadania.
Później tworzone jest zadania. Następnie obiekt IdObiektu, do którego przypisujemy id. Zadanie dodajemy do list.
Na końcu zerujemy indeks aktualnegoZadania, jeśli lista nie jest pusta ustawiamy nowe aktualne zadanie i odświeżamy ekran.
Teraz musimy tę metodę wywołać po wciśnięciu przycisku wczytajPlik. Do metody sluchajNaPrzyciskachPlikow dodaj odpowiedni kod.

Jmk-zadania image102.png

Uruchom aplikację. Dodaj zadanie i zapisz plik. Następnie dodaj kolejne zadanie. Później kliknij wczytaj plik. Zobacz jakie są zadania. Powinno brakować zadań, które dodałeś po zapisie pliku.