Przejdź do głównej treści
INF.04-03-23.06-SGCzerwiec 2023 · 25 kroków · ok. 69 min · 30 kryteriów z klucza

Rozwiązanie krok po kroku: Wypożyczalnia filmów i formularz (C# + React)

Rozwiązujemy arkusz z wypożyczalnią filmów w wersji C# + React: w konsoli klasa Film z polami chronionymi (tytuł i liczba wypożyczeń), metodami ustawiającą i pobierającymi oraz bezargumentową metodą zwiększającą liczbę wypożyczeń, a w programie głównym testy tych metod; w przeglądarce jednokomponentowy formularz React z Bootstrapem - tytuł filmu, lista rodzajów i przycisk „Dodaj”, który wypisuje dane w konsoli przeglądarki. Do tego nagłówek klasy według wzoru z arkusza, zrzuty i dokument egzamin.

Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się poleceniem z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Najpierw piszemy najprostszą wersję, której wymaga klucz, a w etapie „Dobre praktyki” poprawiamy to, czego klucz nie sprawdza.

Co widać w podglądzie. Wyniki programu konsolowego pochodzą z prawdziwego uruchomienia kodu z danego kroku (.NET 10). Podgląd aplikacji webowej wykonuje kod komponentu z kroku w prawdziwym Reakcie z Bootstrapem i stylem z index.css, a u dołu ma panel konsoli przeglądarki (to, co na egzaminie widać po F12): wpisz tytuł, wybierz rodzaj, kliknij „Dodaj”. Wszystkie scenariusze sprawdziliśmy też na prawdziwym projekcie Vite.

Arkusz pozwala też na C++, Javę albo Pythona w konsoli i na Angulara w części webowej - ten wariant to jedna z możliwych dróg.

Jak liczą się punkty. Klucz ma 30 kryteriów (R.1.1 - R.4.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 23 punkty - można stracić 7 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Przygotowanie

    Krok 1 · po tym etapie masz 0 z 30 kryteriów (pkt)

    Krok 1: Folder zdającego i trzy podfoldery

    ok. 2 min
    Polecenie z arkusza

    Utwórz folder i nazwij go numerem zdającego. W folderze utwórz podfoldery: konsola, web, dokumentacja.

    Na pulpicie zakładamy folder o nazwie z numerem PESEL, a w nim konsola, web i dokumentacja. Zrzuty obu aplikacji i dokument egzamin trafiają do folderu dokumentacja. Arkusz nie ma archiwum z materiałami.

  2. Etap 2: Aplikacja konsolowa

    Kroki 2-6 · po tym etapie masz 9 z 30 kryteriów (pkt)

    Krok 2: Projekt konsola w C#

    ok. 3 min
    Polecenie z arkusza

    Korzystając z mechanizmów programowania obiektowego zaprojektuj część logiki systemu wirtualnej wypożyczalni filmów. Obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym, jeden z: C++, C#, Java, Python.

    Wybieramy C#. W Visual Studio: Utwórz nowy projekt → Aplikacja konsolowa, nazwa konsola (stąd archiwum konsola.zip); w terminalu to samo daje dotnet new console -n konsola. W Program.cs zostawiamy klasę Program z pustą metodą Main - klasę filmu dopiszemy nad nią.

    konsola/Program.cs C# nowy plik
    class Program
    {
        static void Main()
        {
        }
    }
  3. Krok 3: Klasa Film z chronionymi polami tytułu i liczby wypożyczeń

    Kryteria: , , ,

    R.2.1 W programie zdefiniowano klasę film (wielkość liter nie ma znaczenia, dopuszczone jest nazewnictwo angielskie)

    R.2.2 Zdefiniowano pola o zakresie protected reprezentujące: tytuł dowolnego typu napisowego przyjmujący domyślnie null lub 0 lub "" i liczbę wypożyczeń dowolnego typu całkowitego o domyślnej wartości 0 (przypisanie lub konstruktorem) (w Python zgodnie z konwencją zastosowano do nazwy jeden podkreślnik)

    R.1.4 Użyto znaczące nazewnictwo zmiennych. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli itp. Kryterium nie jest spełnione tylko wtedy, gdy nazwy zmiennych nic nie znaczą, np. x, a, tab, fun

    R.1.5 Zastosowano typy pól pasujące do problemu (na przykład nazwa filmu jako typ napisowy, liczba wypożyczeń jako typ całkowity, obiekt typu klasy; lub inne pasujące do aplikacji web), w przypadku Python, tam gdzie jest to wymagane zastosowano jawną konwersję do odpowiednich typów

    ok. 3 min
    Polecenie z arkusza

    Zaimplementuj aplikację zawierającą klasę o nazwie film z metodami get, set oraz inkrementuj. Klasa film zawiera dwa pola zawierające tytuł oraz liczbę wypożyczeń. Dostęp do obu pól ma jedynie klasa. W przypadku późniejszego rozszerzenia klasy, klasy potomne powinny również mieć dostęp do tych pól. Klasa film zawiera funkcjonalność: inicjalizację pól wartością pustą lub 0 w zależności od typu.

    Klasę nazywamy Film (wielkość liter nie gra roli, klucz to dopuszcza). Ważny szczegół: tym razem klasy potomne mają mieć dostęp do pól, więc modyfikatorem jest protected, a nie private - private widzi tylko sama klasa, protected także klasy, które po niej dziedziczą (R.2.2).

    Typy: tytuł to string, liczba wypożyczeń - int (R.1.5). Inicjalizację z arkusza robimy wprost przy deklaracji: pusty napis "" i 0.

    Typowe błędy

    private zamiast protected - klasa potomna nie miałaby dostępu do pól, a arkusz tego wymaga (R.2.2).

    konsola/Program.cs C# zmienione: 6 linii
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    }
    
    class Program
    {
        static void Main()
        {
        }
    }
  4. Krok 4: Metoda ustawiająca tytuł (setter)

    Kryteria: ,

    R.2.3 Zdefiniowano metodę ustawiającą tytuł. Metoda jako argument przyjmuje dowolny typ napisowy. Operacja przypisania argumentu do zmiennej następuje prawidłowo dla danego typu. Metoda zmienia wartość pola

    R.1.3 Użyto znaczące nazewnictwo metod

    ok. 2 min
    Polecenie z arkusza

    Metodę ustawiającą tytuł (ang. setter).

    Setter to publiczna metoda, przez którą kod spoza klasy zmienia chronione pole: przyjmuje nowy tytuł jako string i przypisuje go do pola title (R.2.3). Nie zwraca nic, więc ma typ void.

    konsola/Program.cs C# zmienione: 5 linii
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public void SetTitle(string newTitle)
        {
            title = newTitle;
        }
    }
    
    class Program
    {
        static void Main()
        {
        }
    }
  5. Krok 5: Metody pobierające tytuł i liczbę wypożyczeń (gettery)

    Kryteria:

    R.2.4 Zdefiniowano przynajmniej jedną metodę pobierającą: dla tytułu lub liczby wypożyczeń, metoda zwraca odpowiednie pole, jest typu zgodnego z polem, jest bezargumentowa.

    ok. 2 min
    Polecenie z arkusza

    Metodę pobierającą tytuł (ang. getter). Metodę pobierającą liczbę wypożyczeń (ang. getter).

    Getter to bezargumentowa metoda zwracająca wartość pola. Typ zwracany zgadza się z typem pola: string dla tytułu, int dla liczby wypożyczeń (R.2.4). Pola zostają chronione - z zewnątrz można je odczytać, ale nie podmienić bez settera.

    konsola/Program.cs C# zmienione: 10 linii
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public void SetTitle(string newTitle)
        {
            title = newTitle;
        }
    
        public string GetTitle()
        {
            return title;
        }
    
        public int GetRentalCount()
        {
            return rentalCount;
        }
    }
    
    class Program
    {
        static void Main()
        {
        }
    }
  6. Krok 6: Bezargumentowa metoda inkrementująca

    Kryteria: ,

    R.2.5 Zdefiniowano metodę inkrementującą liczbę wypożyczeń; metoda jest bezargumentowa i nie zwraca żadnej wartości

    R.1.2 Kod zapisano z wcięciami dla zagłębień bloków

    ok. 2 min
    Polecenie z arkusza

    Bezargumentową metodę realizującą inkrementację pola przechowującego liczbę wypożyczeń. Metoda nie zwraca żadnej wartości.

    Inkrementacja to zwiększenie o jeden: rentalCount++. Metoda nie ma parametrów i nie zwraca wartości (void) - dokładnie tak, jak w arkuszu (R.2.5).

    konsola/Program.cs C# zmienione: 5 linii
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public void SetTitle(string newTitle)
        {
            title = newTitle;
        }
    
        public string GetTitle()
        {
            return title;
        }
    
        public int GetRentalCount()
        {
            return rentalCount;
        }
    
        public void IncrementRentals()
        {
            rentalCount++;
        }
    }
    
    class Program
    {
        static void Main()
        {
        }
    }
  7. Etap 3: Testy w programie głównym

    Kroki 7-10 · po tym etapie masz 11 z 30 kryteriów (pkt)

    Krok 7: Obiekt filmu i jego pola na starcie

    Kryteria: ,

    R.2.7 W programie/metodzie głównej przetestowano działanie klasy. Zainicjowano obiekt, wykonano ustawienie nazwy filmu i inkrementację oraz wyświetlono wynik działania przed i po zmianach wartości pól. Wyświetlane wartości wskazują na poprawne działanie funkcjonalności klasy

    R.1.1 Kod źródłowy zapisano w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych instrukcji blokowej

    ok. 2 min
    Polecenie z arkusza

    Założenia aplikacji: Inicjalizacja obiektu i wyświetlenie zawartości jego pól.

    Tworzymy obiekt new Film() i wypisujemy oba pola przez gettery - bezpośrednio się nie da, bo są chronione. Tytuł bierzemy w cudzysłów (w napisie C# to \"), żeby pusty tytuł był na ekranie widoczny jako "", a nie jako nic.

    konsola/Program.cs C# zmienione: 2 linie
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public void SetTitle(string newTitle)
        {
            title = newTitle;
        }
    
        public string GetTitle()
        {
            return title;
        }
    
        public int GetRentalCount()
        {
            return rentalCount;
        }
    
        public void IncrementRentals()
        {
            rentalCount++;
        }
    }
    
    class Program
    {
        static void Main()
        {
            Film film = new Film();
            Console.WriteLine("Tytuł: \"" + film.GetTitle() + "\", liczba wypożyczeń: " + film.GetRentalCount());
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Tytuł: "", liczba wypożyczeń: 0
  8. Krok 8: Test metod set i get

    Kryteria:

    R.2.7 W programie/metodzie głównej przetestowano działanie klasy. Zainicjowano obiekt, wykonano ustawienie nazwy filmu i inkrementację oraz wyświetlono wynik działania przed i po zmianach wartości pól. Wyświetlane wartości wskazują na poprawne działanie funkcjonalności klasy

    ok. 2 min
    Polecenie z arkusza

    Test działania metody set, poprzez ustawienie dowolnej wartości dla pola obiektu. Test działania metody get, poprzez pobranie wartości z pola obiektu i wyświetlenie jej na ekranie.

    Setter ustawia tytuł „Vinci” (jak na obrazie z formularza), getter go odczytuje i wypisuje - widać, że oba działają (R.2.7).

    konsola/Program.cs C# zmienione: 3 linie
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public void SetTitle(string newTitle)
        {
            title = newTitle;
        }
    
        public string GetTitle()
        {
            return title;
        }
    
        public int GetRentalCount()
        {
            return rentalCount;
        }
    
        public void IncrementRentals()
        {
            rentalCount++;
        }
    }
    
    class Program
    {
        static void Main()
        {
            Film film = new Film();
            Console.WriteLine("Tytuł: \"" + film.GetTitle() + "\", liczba wypożyczeń: " + film.GetRentalCount());
    
            film.SetTitle("Vinci");
            Console.WriteLine("Tytuł po ustawieniu: " + film.GetTitle());
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Tytuł: "", liczba wypożyczeń: 0
    Tytuł po ustawieniu: Vinci
  9. Krok 9: Test inkrementacji: przed i po

    Kryteria:

    R.2.7 W programie/metodzie głównej przetestowano działanie klasy. Zainicjowano obiekt, wykonano ustawienie nazwy filmu i inkrementację oraz wyświetlono wynik działania przed i po zmianach wartości pól. Wyświetlane wartości wskazują na poprawne działanie funkcjonalności klasy

    ok. 2 min
    Polecenie z arkusza

    Test metody inkrementacji pola przechowującego liczbę wypożyczeń zrealizowany w ten sposób, że wyświetlona jest wartość pola przed i po zastosowaniu metody.

    Wypisujemy liczbę wypożyczeń, wywołujemy IncrementRentals() i wypisujemy ją ponownie: 0, potem 1 - metoda działa (R.2.7).

    konsola/Program.cs C# zmienione: 4 linie
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public void SetTitle(string newTitle)
        {
            title = newTitle;
        }
    
        public string GetTitle()
        {
            return title;
        }
    
        public int GetRentalCount()
        {
            return rentalCount;
        }
    
        public void IncrementRentals()
        {
            rentalCount++;
        }
    }
    
    class Program
    {
        static void Main()
        {
            Film film = new Film();
            Console.WriteLine("Tytuł: \"" + film.GetTitle() + "\", liczba wypożyczeń: " + film.GetRentalCount());
    
            film.SetTitle("Vinci");
            Console.WriteLine("Tytuł po ustawieniu: " + film.GetTitle());
    
            Console.WriteLine("Liczba wypożyczeń przed: " + film.GetRentalCount());
            film.IncrementRentals();
            Console.WriteLine("Liczba wypożyczeń po: " + film.GetRentalCount());
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Tytuł: "", liczba wypożyczeń: 0
    Tytuł po ustawieniu: Vinci
    Liczba wypożyczeń przed: 0
    Liczba wypożyczeń po: 1
  10. Krok 10: Folder konsola: archiwum, źródło i plik wykonywalny

    ok. 2 min
    Polecenie z arkusza

    Kod aplikacji przygotuj do nagrania na płytę. W podfolderze konsola powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, plik z kodem źródłowym programu oraz plik wykonywalny, jeżeli istnieje.

    Folder projektu pakujemy do konsola.zip, obok kopiujemy Program.cs i konsola.exe. Archiwum robimy na końcu pracy, po dopisaniu nagłówka klasy z części III.

    Wynik programu bez zmian - taki jak po kroku 9.

  11. Etap 4: Aplikacja web

    Kroki 11-19 · po tym etapie masz 21 z 30 kryteriów (pkt)

    Krok 11: Nowy projekt React w Vite

    ok. 4 min
    Polecenie z arkusza

    Wykonaj aplikację internetową typu front-end obsługującą formularz z zastosowaniem dostępnego na stanowisku egzaminacyjnym frameworka Angular lub biblioteki React.

    Wybieramy React. Projekt zakładamy w terminalu narzędziem Vite:

    npm create vite@latest web -- --template react
    cd web
    npm install
    

    Nazwa web od razu pasuje do archiwum web.zip. Vite tworzy src/main.jsx, src/App.jsx z przykładowym licznikiem i arkusz stylów src/index.css - wszystkie trzy zmienimy. npm run dev uruchamia serwer pod http://localhost:5173.

    web/src/main.jsx JSX nowy plik
    import { StrictMode } from 'react'
    import { createRoot } from 'react-dom/client'
    import './index.css'
    import App from './App.jsx'
    
    createRoot(document.getElementById('root')).render(
      <StrictMode>
        <App />
      </StrictMode>,
    )

    Wynik programu bez zmian - taki jak po kroku 9.

  12. Krok 12: Bootstrap i styl body z arkusza

    Kryteria:

    R.3.6 W pliku css aplikacji zapisano formatowanie stylem body { padding: 20px; }

    ok. 3 min
    Polecenie z arkusza

    Zastosuj bibliotekę Bootstrap do zdefiniowania stylu formularza. Strona jest formatowana stylem: body { padding: 20px; }. React.js: To use Bootstrap add: import 'bootstrap/dist/css/bootstrap.css';

    npm install bootstrap w folderze web i import z tabeli 1 w main.jsx. Własny arkusz index.css zostaje, ale jego treść z szablonu Vite (ciemne tło, wyśrodkowanie) zastępujemy jedną regułą z arkusza: body { padding: 20px; } (R.3.6). Kolejność importów ma znaczenie: index.css stoi po Bootstrapie, żeby nasza reguła wygrała z jego stylami domyślnymi dla body.

    Typowe błędy

    Import index.css przed Bootstrapem - Bootstrap ustawia własne style body i może nadpisać regułę z arkusza.

    web/src/index.css CSS nowy plik
    body {
      padding: 20px;
    }
    web/src/main.jsx JSX zmienione: 1 linia
    import { StrictMode } from 'react'
    import { createRoot } from 'react-dom/client'
    import 'bootstrap/dist/css/bootstrap.css'
    import './index.css'
    import App from './App.jsx'
    
    createRoot(document.getElementById('root')).render(
      <StrictMode>
        <App />
      </StrictMode>,
    )

    Wynik programu bez zmian - taki jak po kroku 9.

  13. Krok 13: Komponent App z formularzem

    Kryteria:

    R.3.1 Zapisano w aplikacji jeden komponent, który zawiera znaczniki formularza, pola edycyjnego, listy rozwijalnej i przycisku "Dodaj"

    ok. 2 min
    Polecenie z arkusza

    Aplikacja składa się z jednego komponentu formularza.

    Zastępujemy całą zawartość App.jsx. Komponent w React to funkcja zwracająca JSX - zapis podobny do HTML wewnątrz JavaScriptu. Jedyny komponent aplikacji zwraca znacznik form (R.3.1). Na razie pusty - pola dokładamy po kolei.

    web/src/App.jsx JSX nowy plik
    function App() {
      return (
        <form>
        </form>
      )
    }
    
    export default App
    Podgląd strony po tym kroku
  14. Krok 14: Pole Tytuł filmu z etykietą

    Kryteria: ,

    R.3.2 Pola formularza poprzedzono etykietą, która jest powiązana z polem, zastosowano klasy bootstrap form-group oraz form-control np. <div class="form-group"> <label for="tytul">Tytuł filmu</label> <input id="tytul" class="form-control" /> </div> Uwaga: w React.js atrybut className zamiast class oraz htmlFor zamiast for

    R.3.3 Zastosowano znaczące nazwy kontrolek dla atrybutu for i id. Kryterium należy uznać za spełnione zawsze wtedy, gdy nazwa nie jest przepisana z pomocy (exampleInputEmail1) lub gdy nie jest postaci input1, x, itp.

    ok. 3 min
    Polecenie z arkusza

    Formularz składa się z: pola edycyjnego i jego etykiety o treści „Tytuł filmu”. Elementy formularza są formatowane stylami biblioteki Bootstrap. Szablon HTML formularza należy zbudować sugerując się pomocą zamieszczoną w Tabeli 1. Należy zastosować znaczące nazwy dla identyfikatorów pól formularza.

    Wzór z tabeli 1: grupa form-group, w niej etykieta i pole z klasą form-control. Etykietę wiążemy z polem: atrybut for etykiety = id pola - w React piszemy htmlFor zamiast for i className zamiast class (R.3.2). Identyfikator znaczący, movieTitle, a nie przepisany z pomocy exampleInputEmail1 (R.3.3).

    Klasa mb-3 dodaje odstęp pod grupą - w Bootstrapie 5, który instaluje npm, sama form-group (z Bootstrapa 4 w tabeli 1) już go nie daje.

    web/src/App.jsx JSX zmienione: 4 linie
    function App() {
      return (
        <form>
          <div className="form-group mb-3">
            <label htmlFor="movieTitle">Tytuł filmu</label>
            <input type="text" className="form-control" id="movieTitle" />
          </div>
        </form>
      )
    }
    
    export default App
    Podgląd strony po tym kroku
  15. Krok 15: Lista rozwijalna Rodzaj z pięcioma opcjami

    Kryteria: ,

    R.3.5 Lista rozwijalna ma 5 opcji w tym pierwszą pustą, pozostałe są ponumerowane od 1 ÷ 4 za pomocą atrybutu value

    R.3.2 Pola formularza poprzedzono etykietą, która jest powiązana z polem, zastosowano klasy bootstrap form-group oraz form-control np. <div class="form-group"> <label for="tytul">Tytuł filmu</label> <input id="tytul" class="form-control" /> </div> Uwaga: w React.js atrybut className zamiast class oraz htmlFor zamiast for

    ok. 3 min
    Polecenie z arkusza

    Listy rozwijalnej i jej etykiety o treści „Rodzaj”. Lista rozwijalna ma 5 opcji: pustą, Komedia o wartości 1, Obyczajowy o wartości 2, Sensacyjny o wartości 3, Horror o wartości 4.

    Lista rozwijalna to <select>, a jej pozycje - <option>. Tekst między znacznikami widzi użytkownik, a atrybut value to wartość, którą formularz przekaże dalej: pierwsza opcja jest pusta (value=""), kolejne mają wartości 1-4 (R.3.5). Lista dostaje tę samą klasę form-control co pole tekstowe - tak każe tabela 1 i sprawdza klucz (R.3.2). W Bootstrapie 5 lista z samą klasą form-control nie ma strzałki rozwijania (obraz 1b powstał w Bootstrapie 4); poza egzaminem do list służy klasa form-select.

    web/src/App.jsx JSX zmienione: 10 linii
    function App() {
      return (
        <form>
          <div className="form-group mb-3">
            <label htmlFor="movieTitle">Tytuł filmu</label>
            <input type="text" className="form-control" id="movieTitle" />
          </div>
          <div className="form-group mb-3">
            <label htmlFor="movieGenre">Rodzaj</label>
            <select className="form-control" id="movieGenre">
              <option value=""></option>
              <option value="1">Komedia</option>
              <option value="2">Obyczajowy</option>
              <option value="3">Sensacyjny</option>
              <option value="4">Horror</option>
            </select>
          </div>
        </form>
      )
    }
    
    export default App
    Podgląd strony po tym kroku
  16. Krok 16: Przycisk Dodaj

    Kryteria: ,

    R.3.4 Przypisano dla przycisku klasy: btn btn-primary

    R.3.1 Zapisano w aplikacji jeden komponent, który zawiera znaczniki formularza, pola edycyjnego, listy rozwijalnej i przycisku "Dodaj"

    ok. 1 min
    Polecenie z arkusza

    Przycisku „Dodaj”.

    Przycisk z klasami btn btn-primary - niebieski jak na obrazie 1b (R.3.4). Typ submit: kliknięcie zatwierdza formularz. Formularz ma już wszystkie elementy z arkusza (R.3.1).

    web/src/App.jsx JSX zmienione: 1 linia
    function App() {
      return (
        <form>
          <div className="form-group mb-3">
            <label htmlFor="movieTitle">Tytuł filmu</label>
            <input type="text" className="form-control" id="movieTitle" />
          </div>
          <div className="form-group mb-3">
            <label htmlFor="movieGenre">Rodzaj</label>
            <select className="form-control" id="movieGenre">
              <option value=""></option>
              <option value="1">Komedia</option>
              <option value="2">Obyczajowy</option>
              <option value="3">Sensacyjny</option>
              <option value="4">Horror</option>
            </select>
          </div>
          <button type="submit" className="btn btn-primary">Dodaj</button>
        </form>
      )
    }
    
    export default App
    Podgląd strony po tym kroku
  17. Krok 17: Wartości pól w stanie komponentu

    Kryteria: ,

    R.3.8 Aplikacja jest interpretowana bez błędów w przeglądarce, co udokumentowano zrzutem ekranu. W stanie początkowym pole edycyjne i wyboru są puste

    R.1.4 Użyto znaczące nazewnictwo zmiennych. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli itp. Kryterium nie jest spełnione tylko wtedy, gdy nazwy zmiennych nic nie znaczą, np. x, a, tab, fun

    ok. 3 min
    Polecenie z arkusza

    Aplikacja w stanie początkowym wyświetla puste pola formularza.

    Wartości pól trzymamy w stanie komponentu: useState('') zwraca bieżącą wartość i funkcję, która ją zmienia. Pusty napis na starcie to puste pole i pierwsza, pusta opcja listy - stan początkowy z arkusza (R.3.8). Pole i lista dostają value ze stanu, a onChange zapisuje do stanu to, co wpisano albo wybrano (event.target.value - dla listy to atrybut value wybranej opcji, czyli 1-4). useState importujemy z react na górze pliku.

    web/src/App.jsx JSX zmienione: 9 linii
    import { useState } from 'react'
    
    function App() {
      const [title, setTitle] = useState('')
      const [genre, setGenre] = useState('')
    
      return (
        <form>
          <div className="form-group mb-3">
            <label htmlFor="movieTitle">Tytuł filmu</label>
            <input type="text" className="form-control" id="movieTitle"
              value={title} onChange={event => setTitle(event.target.value)} />
          </div>
          <div className="form-group mb-3">
            <label htmlFor="movieGenre">Rodzaj</label>
            <select className="form-control" id="movieGenre"
              value={genre} onChange={event => setGenre(event.target.value)}>
              <option value=""></option>
              <option value="1">Komedia</option>
              <option value="2">Obyczajowy</option>
              <option value="3">Sensacyjny</option>
              <option value="4">Horror</option>
            </select>
          </div>
          <button type="submit" className="btn btn-primary">Dodaj</button>
        </form>
      )
    }
    
    export default App
    Podgląd strony po tym kroku
  18. Krok 18: Dodaj: dane formularza w konsoli przeglądarki

    Kryteria: , ,

    R.3.7 W kodzie zdefiniowano funkcję realizującą zatwierdzenie formularza lub wybranie przycisku

    R.3.9 Po wybraniu przycisku „Dodaj” w konsoli przeglądarki jest wypisane: w Angular postaci: {tytul: ”...”, kategoria: ”...”} w React.js postaci: tytul: ...; rodzaj: ...(w miejscu trzech kropek wartości pól formularza)

    R.1.3 Użyto znaczące nazewnictwo metod

    ok. 3 min
    Polecenie z arkusza

    Po wybraniu przycisku „Dodaj” jest generowane zdarzenie, które ma za zadanie wypisanie danych z formularza w konsoli przeglądarki (w miejscu trzech kropek wartości pól formularza): w React.js postaci: tytul: ...; rodzaj: ... – obraz 1b.

    Funkcję handleSubmit podpinamy pod zdarzenie onSubmit formularza (R.3.7). event.preventDefault() zatrzymuje przeładowanie strony - bez tego przeglądarka wysłałaby formularz, a wpis w konsoli zniknąłby razem ze stroną (na obrazie 1b widać w pasku adresu ?tytul=&kategoria= - to ślad właśnie takiego przeładowania). console.log wypisuje napis dokładnie w postaci z arkusza: tytul: Vinci; rodzaj: 1 (R.3.9).

    Wpisz w podglądzie tytuł, wybierz rodzaj i kliknij „Dodaj” - wynik pojawi się w panelu konsoli u dołu (na egzaminie: F12, zakładka Console).

    Typowe błędy

    console.log(title, genre) wypisze „Vinci 1” - inną postać niż wymagana w arkuszu tytul: ...; rodzaj: ....

    web/src/App.jsx JSX zmienione: 6 linii
    import { useState } from 'react'
    
    function App() {
      const [title, setTitle] = useState('')
      const [genre, setGenre] = useState('')
    
      function handleSubmit(event) {
        event.preventDefault()
        console.log('tytul: ' + title + '; rodzaj: ' + genre)
      }
    
      return (
        <form onSubmit={handleSubmit}>
          <div className="form-group mb-3">
            <label htmlFor="movieTitle">Tytuł filmu</label>
            <input type="text" className="form-control" id="movieTitle"
              value={title} onChange={event => setTitle(event.target.value)} />
          </div>
          <div className="form-group mb-3">
            <label htmlFor="movieGenre">Rodzaj</label>
            <select className="form-control" id="movieGenre"
              value={genre} onChange={event => setGenre(event.target.value)}>
              <option value=""></option>
              <option value="1">Komedia</option>
              <option value="2">Obyczajowy</option>
              <option value="3">Sensacyjny</option>
              <option value="4">Horror</option>
            </select>
          </div>
          <button type="submit" className="btn btn-primary">Dodaj</button>
        </form>
      )
    }
    
    export default App
    Podgląd strony po tym kroku
  19. Krok 19: Zrzut web i folder web

    Kryteria: ,

    R.3.8 Aplikacja jest interpretowana bez błędów w przeglądarce, co udokumentowano zrzutem ekranu. W stanie początkowym pole edycyjne i wyboru są puste

    R.4.7 Zapisano zrzut ekranu z próby uruchomienia aplikacji web, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 4 min
    Polecenie z arkusza

    Dowolna liczba zrzutów ekranowych z aplikacji webowej nazwane web1, web2 itd. Kod aplikacji przygotuj do nagrania na płytę. W podfolderze web powinno znaleźć się archiwum całego projektu o nazwie web.zip oraz pliki z kodem źródłowym które były modyfikowane w czasie egzaminu.

    npm run dev, aplikacja w przeglądarce z otwartą konsolą (F12) i edytorem w tle. Zrzuty całego ekranu do folderu dokumentacja: stan początkowy z pustymi polami i stan po „Dodaj” z wpisem w konsoli (R.3.8, R.4.7). Arkusz w uwadze na końcu nazywa zrzuty konsola.jpg i web.jpg, a w części III konsola1, web1 - którakolwiek z tych nazw jest dobra.

    W folderze web: web.zip z projektem bez folderu node_modules (odtwarza go npm install) oraz zmienione pliki App.jsx, main.jsx i index.css.

    Podgląd strony bez zmian - taki jak po kroku 18.

  20. Etap 5: Dokumentacja

    Kroki 20-22 · po tym etapie masz 30 z 30 kryteriów (pkt)

    Krok 20: Nagłówek klasy Film według listingu 1

    Kryteria: , , , ,

    R.4.1 Zapisano dla klasy z aplikacji konsolowej nagłówek w postaci komentarza zgodny z Listingiem 1 z arkusza egzaminacyjnego, umieszczony w komentarzu wieloliniowym lub kilku jednoliniowych

    R.4.2 W komentarzu ujęto nazwę klasy

    R.4.3 W komentarzu ujęto nazwy pól wraz z opisem

    R.4.4 W komentarzu ujęto nazwy metod, co zwraca oraz opis

    R.4.5 W komentarzu ujęto numer zdającego

    ok. 5 min
    Polecenie z arkusza

    W kodzie źródłowym aplikacji konsolowej utwórz nagłówek klasy, według listingu 1. Nagłówek powinien znaleźć się w kodzie źródłowym nad klasą. W miejscu nawiasów <> należy podać nazwę klasy, nazwy pól oraz zwięzłe informacje (kilka słów) – zgodnie ze wzorcem. W miejscu informacje należy podać opis, co reprezentuje klasa. W miejscu autor należy podać numerem zdającego.

    Komentarz wieloliniowy /* ... */ nad klasą, z polami listingu 1 w tej samej kolejności (R.4.1): nazwa klasy (R.4.2), pola z opisem, co przechowują (R.4.3), metody - nazwa, co zwraca i opis (R.4.4), informacje o tym, co reprezentuje klasa, oraz autor (R.4.5). Na egzaminie w polu autor wpisujemy numer PESEL - tu stoi Bartosz Bryniarski. Komentarz nie zmienia działania programu.

    konsola/Program.cs C# zmienione: 14 linii
    /*
     ******************************************************
      nazwa klasy: Film
      pola:        title - tytuł filmu (napis, domyślnie pusty)
                   rentalCount - liczba wypożyczeń filmu (liczba całkowita, domyślnie 0)
      metody:
                   SetTitle, nic nie zwraca - ustawia tytuł filmu
                   GetTitle, zwraca napis - pobiera tytuł filmu
                   GetRentalCount, zwraca liczbę całkowitą - pobiera liczbę wypożyczeń
                   IncrementRentals, nic nie zwraca - zwiększa liczbę wypożyczeń o jeden
      informacje:  film w wirtualnej wypożyczalni wraz z licznikiem jego wypożyczeń
      autor:       Bartosz Bryniarski
     *****************************************************
     */
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public void SetTitle(string newTitle)
        {
            title = newTitle;
        }
    
        public string GetTitle()
        {
            return title;
        }
    
        public int GetRentalCount()
        {
            return rentalCount;
        }
    
        public void IncrementRentals()
        {
            rentalCount++;
        }
    }
    
    class Program
    {
        static void Main()
        {
            Film film = new Film();
            Console.WriteLine("Tytuł: \"" + film.GetTitle() + "\", liczba wypożyczeń: " + film.GetRentalCount());
    
            film.SetTitle("Vinci");
            Console.WriteLine("Tytuł po ustawieniu: " + film.GetTitle());
    
            Console.WriteLine("Liczba wypożyczeń przed: " + film.GetRentalCount());
            film.IncrementRentals();
            Console.WriteLine("Liczba wypożyczeń po: " + film.GetRentalCount());
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Tytuł: "", liczba wypożyczeń: 0
    Tytuł po ustawieniu: Vinci
    Liczba wypożyczeń przed: 0
    Liczba wypożyczeń po: 1
  21. Krok 21: Zrzut konsola

    Kryteria: , ,

    R.1.6 Podjęto próbę uruchomienia programu, co udokumentowano obrazem przedstawiającym wykonywany program lub jego kompilację

    R.2.6 Program uruchamia się w konsoli, co udokumentowano zrzutem ekranu

    R.4.6 Zapisano zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzuty ekranu dokumentujące uruchomienie aplikacji utworzonych podczas egzaminu. Zrzuty powinny obejmować cały obszar ekranu monitora z widocznym paskiem zadań. Dowolna liczba zrzutów ekranowych z aplikacji konsolowej nazwane konsola1, konsola2 itd.

    Program nie pyta o dane, więc jeden zrzut pokazuje całe jego działanie: okno konsoli z wynikiem i Visual Studio w tle - do folderu dokumentacja (R.1.6, R.2.6, R.4.6).

    Wynik programu bez zmian - taki jak po kroku 20.

  22. Krok 22: Dokument egzamin

    Kryteria:

    R.4.8 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy użytych przez zdającego środowisk, nazwy języków programowania, frameworka Angular lub bilbioteki React

    ok. 3 min
    Polecenie z arkusza

    W edytorze tekstu pakietu biurowego utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać podpisane zrzuty ekranu oraz zapisane informacje: nazwę systemu operacyjnego, na którym pracował zdający, nazwy środowisk programistycznych, z których zdający korzystał na egzaminie, nazwy języków programowania / frameworków / bibliotek użytych podczas tworzenia aplikacji, opcjonalnie komentarz do wykonanej pracy.

    W Wordzie albo Writerze dokument egzamin w folderze dokumentacja: wklejone zrzuty z podpisami, a potem system, środowiska, języki i nazwa biblioteki React (R.4.8). Plik obok to treść tekstowa dokumentu.

    egzamin.txt Tekst nowy plik
    Zrzuty ekranu: konsola - wynik programu konsolowego; web - formularz przed i po wybraniu przycisku Dodaj
    System operacyjny: Windows 11
    Środowiska programistyczne: Visual Studio 2022 (aplikacja konsolowa), Visual Studio Code (aplikacja web)
    Języki programowania: C# (aplikacja konsolowa), JavaScript (aplikacja web)
    Biblioteki: React (aplikacja web), Bootstrap (style formularza), Vite (narzędzie do budowania projektu)

    Wynik programu bez zmian - taki jak po kroku 20.

  23. Etap 6: Dobre praktyki (poza kluczem)

    Kroki 23-24 · po tym etapie masz 30 z 30 kryteriów (pkt)

    Krok 23: Konsola: setter pilnuje długości tytułu

    ok. 3 min
    Polecenie z arkusza

    Dla uproszczenia można przyjąć, że tytuł może mieć maksymalnie 20 znaków.

    Setter to dobre miejsce na pilnowanie reguł - po to pola są chronione. Wersja z egzaminu przyjmuje każdy napis, więc:

    • null zamieniamy na pusty napis (pole nigdy nie będzie null),
    • Trim() usuwa spacje z początku i końca,
    • napis dłuższy niż stała MaxTitleLength (20 - wartość z arkusza) skracamy metodą Substring.

    Test w Main pokazuje, co dzieje się z za długim tytułem. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    konsola/Program.cs C# zmienione: 13 linii
    /*
     ******************************************************
      nazwa klasy: Film
      pola:        title - tytuł filmu (napis, domyślnie pusty)
                   rentalCount - liczba wypożyczeń filmu (liczba całkowita, domyślnie 0)
      metody:
                   SetTitle, nic nie zwraca - ustawia tytuł filmu
                   GetTitle, zwraca napis - pobiera tytuł filmu
                   GetRentalCount, zwraca liczbę całkowitą - pobiera liczbę wypożyczeń
                   IncrementRentals, nic nie zwraca - zwiększa liczbę wypożyczeń o jeden
      informacje:  film w wirtualnej wypożyczalni wraz z licznikiem jego wypożyczeń
      autor:       Bartosz Bryniarski
     *****************************************************
     */
    class Film
    {
        protected string title = "";
        protected int rentalCount = 0;
    
        public const int MaxTitleLength = 20;
    
        public void SetTitle(string newTitle)
        {
            if (newTitle == null)
            {
                newTitle = "";
            }
            newTitle = newTitle.Trim();
            if (newTitle.Length > MaxTitleLength)
            {
                newTitle = newTitle.Substring(0, MaxTitleLength);
            }
            title = newTitle;
        }
    
        public string GetTitle()
        {
            return title;
        }
    
        public int GetRentalCount()
        {
            return rentalCount;
        }
    
        public void IncrementRentals()
        {
            rentalCount++;
        }
    }
    
    class Program
    {
        static void Main()
        {
            Film film = new Film();
            Console.WriteLine("Tytuł: \"" + film.GetTitle() + "\", liczba wypożyczeń: " + film.GetRentalCount());
    
            film.SetTitle("Vinci");
            Console.WriteLine("Tytuł po ustawieniu: " + film.GetTitle());
            film.SetTitle("Najdłuższy tytuł filmu na świecie");
            Console.WriteLine("Za długi tytuł: " + film.GetTitle());
    
            Console.WriteLine("Liczba wypożyczeń przed: " + film.GetRentalCount());
            film.IncrementRentals();
            Console.WriteLine("Liczba wypożyczeń po: " + film.GetRentalCount());
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Tytuł: "", liczba wypożyczeń: 0
    Tytuł po ustawieniu: Vinci
    Za długi tytuł: Najdłuższy tytuł fil
    Liczba wypożyczeń przed: 0
    Liczba wypożyczeń po: 1
  24. Krok 24: Web: opcje listy z tablicy rodzajów

    ok. 3 min
    Polecenie z arkusza

    Lista rozwijalna ma 5 opcji: pustą, Komedia o wartości 1, Obyczajowy o wartości 2, Sensacyjny o wartości 3, Horror o wartości 4.

    Cztery ręcznie wpisane opcje zastępujemy tablicą genres i metodą map: każda nazwa daje jedną opcję, a wartością jest numer pozycji w tablicy plus jeden (index + 1), więc Komedia nadal ma wartość 1, a Horror - 4. Nowy rodzaj dopisujemy w jednym miejscu, a lista i wartości dostosują się same. Pusta opcja zostaje wpisana osobno, przed pętlą. key - wymagany przez Reacta przy elementach z pętli.

    Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza (wymaga tylko pięciu opcji z wartościami 1-4, które ta wersja nadal tworzy).

    web/src/App.jsx JSX zmienione: 2 linie
    import { useState } from 'react'
    
    function App() {
      const [title, setTitle] = useState('')
      const [genre, setGenre] = useState('')
      const genres = ['Komedia', 'Obyczajowy', 'Sensacyjny', 'Horror']
    
      function handleSubmit(event) {
        event.preventDefault()
        console.log('tytul: ' + title + '; rodzaj: ' + genre)
      }
    
      return (
        <form onSubmit={handleSubmit}>
          <div className="form-group mb-3">
            <label htmlFor="movieTitle">Tytuł filmu</label>
            <input type="text" className="form-control" id="movieTitle"
              value={title} onChange={event => setTitle(event.target.value)} />
          </div>
          <div className="form-group mb-3">
            <label htmlFor="movieGenre">Rodzaj</label>
            <select className="form-control" id="movieGenre"
              value={genre} onChange={event => setGenre(event.target.value)}>
              <option value=""></option>
              {genres.map((name, index) => <option key={name} value={index + 1}>{name}</option>)}
            </select>
          </div>
          <button type="submit" className="btn btn-primary">Dodaj</button>
        </form>
      )
    }
    
    export default App
    Podgląd strony po tym kroku
  25. Etap 7: Oddanie pracy

    Krok 25 · po tym etapie masz 30 z 30 kryteriów (pkt)

    Krok 25: Nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować podfoldery dokumentacja, konsola, web. W folderze dokumentacja pliki: konsola.jpg, web.jpg, egzamin. Po nagraniu płyty sprawdź poprawność nagrania.

    Sprawdzamy zawartość przed nagraniem:

    • dokumentacja: zrzuty konsoli i aplikacji web, egzamin,
    • konsola: konsola.zip (spakowany po dopisaniu nagłówka klasy), Program.cs, konsola.exe,
    • web: web.zip (bez node_modules), App.jsx, main.jsx, index.css.

    Nagrywamy, sprawdzamy odczyt płyty, opisujemy ją numerem zdającego.

    Podgląd strony bez zmian - taki jak po kroku 24.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony). Treść arkusza i klucza oceniania pochodzi z CKE.