INF.04-01-23.01-SGStyczeń 2023 · 33 kroki · ok. 87 min · 32 kryteria z klucza
Rozwiązanie krok po kroku: NWD i generator hasła (Python + Tkinter)
Rozwiązanie dotyczy arkusza z algorytmem Euklidesa i oknem „Dodaj pracownika” w wersji Python + Tkinter - cały egzamin w jednym języku. W konsoli funkcja wyznaczająca największy wspólny dzielnik dokładnie według schematu blokowego z arkusza (odejmowanie, nie reszta z dzielenia), a w okienku zbudowanym biblioteką Tkinter dwie ramki z kontrolkami: dane pracownika i generowanie hasła o podanej długości (z wielką literą, cyfrą i znakiem specjalnym zależnie od pól wyboru), a po „Zatwierdź” - komunikat z danymi pracownika. Do tego dokumentacja funkcji 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ą. Kod od początku jest pisany tak, jak w prawdziwych projektach; na końcu dwa kroki porównują ten wariant z rozwiązaniem w C# i WPF (druga zakładka).
Co widać w podglądzie. Program konsolowy z każdego kroku jest naprawdę uruchamiany (Python 3.12) z liczbami wpisanymi z klawiatury. Okno to symulacja w przeglądarce, ale jej układ pochodzi z prawdziwego Tkintera: program z kroku uruchomiłem i odczytałem położenie, rozmiar, kolor i tekst każdej kontrolki. Przyciski działają tak, jak metody z kodu kroku - scenariusz z obrazów 2 i 3 sprawdziłem w symulacji i w prawdziwym oknie Tk (hasło jest losowe, więc porównywany jest jego układ: na której pozycji jest wielka litera, cyfra, znak specjalny).
Jak liczą się punkty. Klucz ma 32 kryteria (R.1.1 - R.4.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 24 punkty - można stracić 8 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.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Przygotowanie
Krok 1 · po tym etapie masz 0 z 32 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, desktopowa, dokumentacja.
Na pulpicie zakładasz folder o nazwie z numerem PESEL, a w nim konsola, desktopowa i dokumentacja (w tym arkuszu folder nazywa się konsola, nie konsolowa). Arkusz nie ma archiwum z materiałami - wszystko piszesz od zera. Oba projekty zakładasz w PyCharm, a na koniec pakujesz je i kopiujesz do podfolderów razem z plikami main.py.
Etap 2: Aplikacja konsolowa
Kroki 2-9 · po tym etapie masz 12 z 32 kryteriów (pkt)
Krok 2: Projekt konsola w PyCharm i funkcja main
ok. 3 min
Polecenie z arkusza
Obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python.
Wybierasz Pythona. W PyCharm: New Project, nazwa konsola, interpreter ze stanowiska, bez skryptu powitalnego; w projekcie plik main.py. Program główny od razu zamykasz w funkcji main() wywoływanej pod warunkiem if __name__ == "__main__": - zmienne programu głównego będą lokalne, a plik da się zaimportować (np. do testów) bez uruchamiania programu. pass to pusta instrukcja - za chwilę ją zastąpisz.
konsola/main.pyPythonnowy plik
defmain():passif__name__ == "__main__": main()
Wynik programu po tym kroku
> python main.py
Krok 3: Funkcja nwd z dwoma argumentami
Kryteria: ,
R.2.1 W programie zdefiniowano funkcję, która pobiera jako argumenty dwie liczby, typem funkcji jest liczba całkowita bez znaku (dopuszcza się w języku Java ze znakiem, w Python bez typu) oraz zastosowano instrukcję return
R.1.3 Użyto znaczące nazewnictwo funkcji
ok. 2 min
Polecenie z arkusza
Szukanie NWD zaimplementowane w funkcji o dwóch argumentach i zwracanej wartości największego wspólnego dzielnika. Funkcja nie może zawierać operacji wejścia - wyjścia.
Szkielet funkcji: dwa parametry o nazwach a i b - dokładnie jak na schemacie (klucz tego wymaga, R.1.4) - i instrukcja return, która zwraca wynik (R.2.1). Funkcja tylko liczy: żadnego input ani print w środku, jak każe arkusz - wczytywanie i wypisywanie zrobi program główny.
Python nie ma typu „liczba bez znaku” - typ wynika z wartości, którą dostanie funkcja. O to, żeby trafiały do niej tylko liczby dodatnie, zadba program główny.
R.2.2 Funkcja stosuje pętlę while lub do while, która jest wykonywana tak długo jak a i b są różne
R.2.4 Funkcja zwraca wartość równą a (możliwe też za pomocą innej zmiennej równej a)
ok. 2 min
Polecenie z arkusza
Implementacja algorytmu w pełni zgodna z przedstawionym na schemacie algorytmem.
Pierwszy romb schematu („czy a ≠ b”) ze strzałką wracającą nad niego to pętla while: warunek sprawdzany przed każdym obrotem (R.2.2). != to w Pythonie „różne”. Gałąź „Nie” prowadzi do „Wyświetl a” - w tym rozwiązaniu wyjście z pętli i return a (R.2.4). Ciało pętli jest jeszcze puste (pass) - dla różnych liczb kręciłaby się bez końca, więc funkcji na razie nie wywołujesz.
konsola/main.pyPythonzmienione: 2 linie
defnwd(a, b):while a != b:passreturn adefmain():passif__name__ == "__main__": main()
R.2.3 W pętli znajduje się porównanie a i b, jeżeli a > b jest wykonywane a = a - b w przeciwnym wypadku b = b - a (warunki mogą być odwrócone)
R.1.2 Kod zapisano z wcięciami dla zagłębień bloków
ok. 3 min
Polecenie z arkusza
Implementacja algorytmu w pełni zgodna z przedstawionym na schemacie algorytmem: czy a > b - Tak: a := a-b, Nie: b := b-a.
Drugi romb to if ... else: gdy a jest większe, odejmujesz od niego b, w przeciwnym razie odejmujesz a od b (R.2.3). Każde odjęcie zmniejsza jedną z liczb, więc w końcu się zrównają - i ta wspólna wartość to NWD (48 i 18: 30, 18 → 12, 18 → 12, 6 → 6, 6). Zapis a := a - b ze schematu to w Pythonie zwykłe przypisanie a = a - b. Bloki wyznaczają wcięcia - każdy poziom zagnieżdżenia o 4 spacje dalej (R.1.2).
Typowe błędy
Algorytm z resztą z dzielenia (a % b) albo gotowe math.gcd(a, b) dają ten sam wynik, ale to INNY algorytm niż na schemacie - R.2.2 i R.2.3 wymagają pętli z porównaniem a i b i odejmowaniem.
konsola/main.pyPythonzmienione: 4 linie
defnwd(a, b):while a != b:if a > b: a = a - belse: b = b - areturn adefmain():passif__name__ == "__main__": main()
R.2.5 W programie głównym następuje wczytanie dwóch liczb z klawiatury
R.1.5 Zastosowano typy pól pasujące do problemu, typ zmiennych a i b jest naturalny - w zależności od języka programowania kwalifikator unsigned lub typ bez znaku np. uint (jeżeli nie zastosowano typu bez znaku, sprawdzono warunkiem czy obie zmienne są dodatnie) w przypadku Python zastosowano jawną konwersję do odpowiednich typów
R.1.4 Użyto nazewnictwo dwóch zmiennych algorytmu: a i b. Dla Pozostałych zmiennych (jeśli istnieją) nazewnictwo jest znaczące. 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, tab, tablica
ok. 2 min
Polecenie z arkusza
Program główny testuje działanie funkcji i zawiera operacje wejścia - wyjścia. Należy stosować nazwy zmiennych zgodne z nazwami zastosowanymi na schemacie blokowym.
input(...) wypisuje pytanie i zwraca wpisany tekst. Klucz wymaga w Pythonie jawnej konwersji do właściwego typu (R.1.5), więc tekst zamieniasz na liczbę całkowitą funkcją int(...) - bez niej a > b porównywałoby napisy („9” > „18”, bo porównanie idzie znak po znaku). Zmienne nazywasz a i b, jak na schemacie (R.2.5).
konsola/main.pyPythonzmienione: 2 linie
defnwd(a, b):while a != b:if a > b: a = a - belse: b = b - areturn adefmain(): a = int(input("Podaj liczbę a: ")) b = int(input("Podaj liczbę b: "))if__name__ == "__main__": main()
Wynik programu po tym kroku
> python main.py
Podaj liczbę a: 48
Podaj liczbę b: 18
Krok 7: Kontrola: tylko liczby dodatnie
Kryteria: ,
R.1.5 Zastosowano typy pól pasujące do problemu, typ zmiennych a i b jest naturalny - w zależności od języka programowania kwalifikator unsigned lub typ bez znaku np. uint (jeżeli nie zastosowano typu bez znaku, sprawdzono warunkiem czy obie zmienne są dodatnie) w przypadku Python zastosowano jawną konwersję do odpowiednich typów
R.1.3 Użyto znaczące nazewnictwo funkcji
ok. 3 min
Polecenie z arkusza
Liczby a i b należą do zbioru liczb całkowitych dodatnich (odpowiedni typ lub kontrola poprawności wpisanej liczby).
Python nie ma typu bez znaku, więc wybierasz drugą drogę z arkusza: kontrolę poprawności. Funkcja read_positive(prompt) wczytuje liczbę i dopóki nie jest większa od zera, pyta ponownie. To ważne nie tylko formalnie: dla a = 0 pętla w nwd kręciłaby się bez końca (b - 0 to wciąż b), a dla liczby ujemnej - też.
Podgląd to dwa prawdziwe uruchomienia: 48 i 18, a potem najpierw -4 (odrzucone) i 4 dla a, 6 dla b.
Typowe błędy
Sprawdzenie samym if (zamiast while) zapyta ponownie tylko raz - przy drugiej złej liczbie program pójdzie dalej z zerem albo liczbą ujemną.
konsola/main.pyPythonzmienione: 9 linii
defnwd(a, b):while a != b:if a > b: a = a - belse: b = b - areturn adefread_positive(prompt): number = int(input(prompt))while number <= 0: number = int(input("Liczba musi być dodatnia. " + prompt))return numberdefmain(): a = read_positive("Podaj liczbę a: ") b = read_positive("Podaj liczbę b: ")if__name__ == "__main__": main()
Wynik programu po tym kroku
> python main.py
Podaj liczbę a: 48
Podaj liczbę b: 18
> python main.py
Podaj liczbę a: -4
Liczba musi być dodatnia. Podaj liczbę a: 4
Podaj liczbę b: 6
Krok 8: Program główny: wynik w konsoli
Kryteria: , ,
R.2.6 W konsoli wyświetlona jest obliczona wartość
R.1.6 Program podejmuje komunikację z użytkownikiem, np. monit o wprowadzenie danych jest znaczący albo wyświetlenie danych opatrzone znaczącym komunikatem
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
Program główny testuje działanie funkcji i zawiera operacje wejścia - wyjścia. Program powinien być zapisany czytelnie, z zachowaniem zasad czystego formatowania kodu.
Wywołujesz nwd(a, b) i wypisujesz wynik z komunikatem (R.2.6, R.1.6). f-napis wstawia w klamry wartości zmiennych i wynik funkcji: „NWD(48, 18) = 6”. Funkcja dostaje kopie wartości - zmiany a i b wewnątrz nwd nie psują zmiennych w main, dlatego w komunikacie widać liczby wpisane przez użytkownika, a nie te z końca pętli.
Podgląd: 48 i 18 dają 6, a 17 i 5 (liczby względnie pierwsze) - 1.
konsola/main.pyPythonzmienione: 1 linia
defnwd(a, b):while a != b:if a > b: a = a - belse: b = b - areturn adefread_positive(prompt): number = int(input(prompt))while number <= 0: number = int(input("Liczba musi być dodatnia. " + prompt))return numberdefmain(): a = read_positive("Podaj liczbę a: ") b = read_positive("Podaj liczbę b: ")print(f"NWD({a}, {b}) = {nwd(a, b)}")if__name__ == "__main__": main()
Wynik programu po tym kroku
> python main.py
Podaj liczbę a: 48
Podaj liczbę b: 18
NWD(48, 18) = 6
> python main.py
Podaj liczbę a: 17
Podaj liczbę b: 5
NWD(17, 5) = 1
Krok 9: Folder konsola: archiwum i źródło
ok. 2 min
Polecenie z arkusza
Kod aplikacji przygotuj do nagrania na płytę. W folderze konsola powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, plik z kodem źródłowym programu oraz plik uruchomieniowy, jeżeli istnieje.
Folder projektu pakujesz do konsola.zip, obok kopiujesz main.py. Python nie tworzy pliku uruchomieniowego, więc go nie ma. Archiwum robisz na końcu pracy, po dopisaniu dokumentacji funkcji z części III.
Kroki 10-26 · po tym etapie masz 22 z 32 kryteriów (pkt)
Krok 10: Projekt desktopowa: okno w klasie EmployeeWindow
ok. 3 min
Polecenie z arkusza
Za pomocą dostępnego na stanowisku egzaminacyjnym środowiska programistycznego wykonaj aplikację desktopową do wprowadzania danych pracownika z możliwością generowania hasła.
Okno budujesz biblioteką Tkinter (jest w standardowej instalacji Pythona). W PyCharm drugi projekt, desktopowa, z plikiem main.py.
Tym razem kontrolki i dane okna trzymasz w klasieEmployeeWindow. Powód podaje sam arkusz: hasło wygenerowane jednym przyciskiem ma być widoczne w obsłudze drugiego. Pole obiektu (self.password) widzą wszystkie metody klasy - bez zmiennych globalnych i słowa global. Konstruktor __init__(self, root) dostaje okno główne i (w kolejnych krokach) zbuduje w nim kontrolki.
Na dole pliku: root = tk.Tk() tworzy okno główne, EmployeeWindow(root) - obiekt tej klasy, a root.mainloop() uruchamia pętlę zdarzeń, która czeka na kliknięcia aż do zamknięcia okna.
desktopowa/main.pyPythonnowy plik
import tkinter as tkclassEmployeeWindow:def__init__(self, root):passroot = tk.Tk()app = EmployeeWindow(root)root.mainloop()
Okno aplikacji po tym kroku
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 11: Tytuł i rozmiar okna
Kryteria:
R.3.1 Nadano dla okna aplikacji nazwę "Dodaj pracownika" wraz z numerem zdającego oraz umieszczono w nim dwie grupy „Dane Pracownika” oraz „Generowanie hasła”
ok. 2 min
Polecenie z arkusza
Okno o nazwie „Dodaj pracownika”. W nazwie okna należy wstawić także numer zdającego.
title ustawia napis na pasku okna - na egzaminie po „Dodaj pracownika” wpisujesz numer PESEL, tu stoi autor rozwiązania, Bartosz Bryniarski. geometry("650x300") nadaje rozmiar zbliżony do obrazu 1 (szerokość × wysokość w pikselach) - domyślne puste okno ma 200 × 200 i tytuł by się w nim nie zmieścił.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 12: Tło okna LightSteelBlue
Kryteria:
R.3.3 Nadano dla okna tło koloru LightSteelBlue (#B0C4DE) oraz dla przycisków tło koloru SteelBlue (#4682B4) i biały kolor czcionki
ok. 1 min
Polecenie z arkusza
Okno ma tło koloru LightSteelBlue (#B0C4DE).
Kolor tła wpiszesz jeszcze w kilkunastu kontrolkach - w Tkinterze każda etykieta, ramka i pole wyboru ma własne tło (domyślnie szare), więc musi dostać kolor okna. Zapisujesz go raz, w stałejBACKGROUND na górze pliku (wielkie litery to w Pythonie umowny zapis stałej), i używasz tej nazwy. configure(bg=BACKGROUND) ustawia tło okna (R.3.3).
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 13: Układ: dwie grupy obok siebie
Kryteria:
R.3.1 Nadano dla okna aplikacji nazwę "Dodaj pracownika" wraz z numerem zdającego oraz umieszczono w nim dwie grupy „Dane Pracownika” oraz „Generowanie hasła”
ok. 3 min
Polecenie z arkusza
Kontrolki rozmieszczone zgodnie z obrazem 1. Kontrolki w grupie „Dane Pracownika”. Kontrolki w grupie „Generowanie hasła”.
Grupa z podpisem i ramką to w Tkinterze tk.LabelFrame (odpowiednik GroupBox) - podpis w text, a padx/pady to wewnętrzny odstęp kontrolek od ramki.
Obie grupy układasz menedżerem grid - siatką wierszy i kolumn liczonych od 0: pierwsza w kolumnie 0, druga w kolumnie 1. columnconfigure(..., weight=1) dla obu kolumn dzieli szerokość okna po równo, rowconfigure(0, weight=1) oddaje wierszowi 0 wolną wysokość, a sticky="nsew" rozciąga ramkę na całą komórkę (n, s, e, w - strony świata). Zewnętrzne odstępy padx/pady w grid odsuwają ramki od krawędzi okna i od siebie (R.3.1).
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 14: Etykieta Imię i pole edycyjne
Kryteria:
R.3.2 Okno zawiera wszystkie kontrolki widoczne na Obrazie 1 arkusza egzaminacyjnego, przycisk zatwierdzenia jest dłuższy niż przycisk do generowania hasła
ok. 3 min
Polecenie z arkusza
Kontrolki w grupie „Dane Pracownika”: pole edycyjne poprzedzone etykietą o treści „Imię”.
Wewnątrz ramki własna siatka: etykieta tk.Label w kolumnie 0, pole edycyjne tk.Entry w kolumnie 1. Pierwszy argument kontrolki to jej rodzic - employee_frame, nie root - więc wiersze i kolumny liczą się wewnątrz ramki. sticky="w" przykleja etykietę do lewej, width=22 to szerokość pola w znakach.
Pole zapisujesz w polu obiektu self.first_name_entry - jego treść odczytasz w metodzie przycisku „Zatwierdź”. Etykiety nic nie zmienia, więc nie zapisujesz jej nigdzie.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 15: Etykieta Nazwisko i pole edycyjne
Kryteria:
R.3.2 Okno zawiera wszystkie kontrolki widoczne na Obrazie 1 arkusza egzaminacyjnego, przycisk zatwierdzenia jest dłuższy niż przycisk do generowania hasła
ok. 1 min
Polecenie z arkusza
Pole edycyjne poprzedzone etykietą o treści „Nazwisko”.
To samo w wierszu 1, z polem self.last_name_entry.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 16: Lista rozwijana Stanowisko
Kryteria: ,
R.3.2 Okno zawiera wszystkie kontrolki widoczne na Obrazie 1 arkusza egzaminacyjnego, przycisk zatwierdzenia jest dłuższy niż przycisk do generowania hasła
R.3.4 Zdefiniowano cztery elementy dla listy rozwijalnej: Kierownik, Starszy programista, Młodszy programista, Tester
ok. 3 min
Polecenie z arkusza
Lista rozwijalna podpisana „Stanowisko” z elementami: Kierownik, Starszy programista, Młodszy programista, Tester.
Lista rozwijana jest w module ttk (nowsze kontrolki Tkintera w stylu systemu) - importujesz go from tkinter import ttk. ttk.Combobox dostaje pozycje w parametrze values jako listę napisów (R.3.4). state="readonly" pozwala tylko wybierać z listy - bez tego w polu dałoby się wpisać dowolny tekst. Na obrazie 1 nic nie jest wybrane, więc nie ustawiasz pozycji początkowej. Rozwiń listę w podglądzie.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 17: Etykieta Ile znaków? i pole edycyjne
Kryteria:
R.3.2 Okno zawiera wszystkie kontrolki widoczne na Obrazie 1 arkusza egzaminacyjnego, przycisk zatwierdzenia jest dłuższy niż przycisk do generowania hasła
ok. 1 min
Polecenie z arkusza
Kontrolki w grupie „Generowanie hasła”: pole edycyjne poprzedzone etykietą o treści „Ile znaków?”.
Druga ramka ma własną siatkę - numeracja wierszy zaczyna się w niej znowu od 0. Pole self.length_entry odczyta metoda generowania hasła.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 18: Trzy pola wyboru, pierwsze zaznaczone
Kryteria: ,
R.3.2 Okno zawiera wszystkie kontrolki widoczne na Obrazie 1 arkusza egzaminacyjnego, przycisk zatwierdzenia jest dłuższy niż przycisk do generowania hasła
R.3.10 Aplikacja kompiluje się i uruchamia, co udokumentowano zrzutem ekranu, jej układ po uruchomieniu jest zgodny z obrazem 1 w arkuszu egzaminacyjnym. Zaznaczone jest pierwsze pole wyboru
ok. 3 min
Polecenie z arkusza
Trzy pola wyboru podpisane: „Małe i wielkie litery”, „Cyfry”, „Znaki specjalne”. Pierwsze pole jest domyślnie zaznaczone.
Pole wyboru to tk.Checkbutton. Jego stan Tkinter trzyma w osobnej zmiennej kontrolki - tk.BooleanVar - podanej w parametrze variable: zaznaczenie ustawia ją na True, odznaczenie na False, a odczytasz ją metodą get(). BooleanVar(value=True) sprawia, że pierwsze pole jest zaznaczone od startu (R.3.10).
columnspan=2 - pole wyboru zajmuje obie kolumny siatki (jest szersze niż etykieta „Ile znaków?”). activebackground to tło pod kursorem myszy - bez niego pole po najechaniu robiłoby się szare.
Typowe błędy
tk.BooleanVar(True) bez nazwy parametru nie zaznacza pola - pierwszym parametrem pozycyjnym jest okno-rodzic, nie wartość. Pisz value=True.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 19: Przycisk Generuj hasło
Kryteria: ,
R.3.2 Okno zawiera wszystkie kontrolki widoczne na Obrazie 1 arkusza egzaminacyjnego, przycisk zatwierdzenia jest dłuższy niż przycisk do generowania hasła
R.3.3 Nadano dla okna tło koloru LightSteelBlue (#B0C4DE) oraz dla przycisków tło koloru SteelBlue (#4682B4) i biały kolor czcionki
ok. 2 min
Polecenie z arkusza
Przycisk o treści „Generuj hasło”. Przyciski mają tło koloru SteelBlue (#4682B4) i biały kolor czcionki.
tk.Button z napisem w text, tłem bg i kolorem tekstu fg (foreground) - biały (R.3.3). Kolor przycisków też trafia do stałej BUTTON_COLOR, bo użyjesz go dwa razy. Obsługi kliknięcia jeszcze nie ma.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 20: Przycisk Zatwierdź pod grupami
Kryteria: ,
R.3.2 Okno zawiera wszystkie kontrolki widoczne na Obrazie 1 arkusza egzaminacyjnego, przycisk zatwierdzenia jest dłuższy niż przycisk do generowania hasła
R.3.3 Nadano dla okna tło koloru LightSteelBlue (#B0C4DE) oraz dla przycisków tło koloru SteelBlue (#4682B4) i biały kolor czcionki
ok. 2 min
Polecenie z arkusza
Na dole okna znajduje się przycisk „Zatwierdź”, jest on wyraźnie dłuższy niż przycisk do generowania hasła.
Przycisk w wierszu 1 siatki okna, rozciągnięty na obie kolumny (columnspan=2) - dzięki temu stoi na środku. width=30 to szerokość w znakach: ponad dwa razy więcej niż „Generuj hasło”, którego szerokość wynika z napisu (R.3.2). Wygląd okna jest kompletny - porównaj z obrazem 1.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 21: Pole password i metoda obsługi przycisku
Kryteria: ,
R.3.5 Po wciśnięciu przynajmniej jednego przycisku wywoływana jest funkcja
R.3.8 Hasło oraz zestawy znaków są przechowywane w zmiennych typu napisowego, hasło jest widoczne dla obu metod obsługujących kliknięcia przycisków
ok. 3 min
Polecenie z arkusza
Hasło oraz zestawy znaków są przechowywane w zmiennych typu napisowego.
self.password = "" - pole obiektu z pustym napisem; ustawi je metoda generowania, a odczyta metoda „Zatwierdź” (R.3.8),
def generate_password(self) - metoda klasy; self to obiekt okna, przez niego metoda sięga do kontrolek i pól,
command=self.generate_password w przycisku - bez nawiasów: przekazujesz metodę, a Tkinter wywoła ją przy kliknięciu (R.3.5).
Metoda jest jeszcze pusta - kliknięcie niczego nie robi.
Typowe błędy
command=self.generate_password() z nawiasami wywoła metodę raz, przy budowaniu okna, a przyciskowi przekaże jej wynik (None) - kliknięcie nie będzie nic robić.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 22: Hasło z małych liter i okno komunikatu
Kryteria: ,
R.3.6 Po wybraniu przycisku "Generuj hasło" wyświetla się komunikat z wygenerowanym hasłem, liczba znaków hasła jest zgodna z liczbą podaną w polu edycyjnym. Generowanie hasła należy sprawdzić dwa razy (hasła muszą być różne)
R.3.7 Znaki do hasła są wybierane przy wykorzystaniu generatora liczb pseudolosowych z zestawu znaków, który zawsze obejmuje małe litery a..z oraz gdy wybrano pierwszy checkbox wielkie litery A..Z i gdy wybrano drugi checkbox cyfry: 0..9 oraz gdy wybrano trzeci checkbox znaki specjalne ze zbioru !@#$%^&*()_+-=
ok. 3 min
Polecenie z arkusza
Generowane jest hasło o liczbie znaków określonej w polu edycyjnym. Poszczególne znaki hasła są wybierane losowo z zestawu małych liter. Hasło jest wypisywane jako komunikat zgodnie z obrazem 2 po wybraniu przycisku „Generuj hasło”.
self.length_entry.get() zwraca tekst z pola, a int(...) zamienia go na liczbę znaków,
self.password = "" - każde kliknięcie zaczyna nowe hasło,
random.choice(LOWERCASE) losuje jeden znak z napisu (generator liczb pseudolosowych, R.3.7), a += dokleja go do hasła,
messagebox.showinfo(tytuł, treść) z modułu tkinter.messagebox pokazuje okno komunikatu z hasłem i przyciskiem OK, jak na obrazie 2 (R.3.6).
Wpisz w podglądzie 5 i kliknij „Generuj hasło” dwa razy - dwa różne hasła z pięciu małych liter.
Typowe błędy
Puste pole „Ile znaków?” daje int("") - błąd ValueError. Tkinter nie zamyka wtedy okna, tylko wypisuje błąd w konsoli PyCharm, a kliknięcie „nic nie robi”. Arkusz zwalnia z tego sprawdzania, ale przy testowaniu pamiętaj, żeby wpisać liczbę.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 23: Wielka litera, gdy zaznaczono pierwsze pole
Kryteria:
R.3.7 Znaki do hasła są wybierane przy wykorzystaniu generatora liczb pseudolosowych z zestawu znaków, który zawsze obejmuje małe litery a..z oraz gdy wybrano pierwszy checkbox wielkie litery A..Z i gdy wybrano drugi checkbox cyfry: 0..9 oraz gdy wybrano trzeci checkbox znaki specjalne ze zbioru !@#$%^&*()_+-=
ok. 3 min
Polecenie z arkusza
Jeżeli zaznaczono checkbox „Małe i wielkie litery”, jeden ze znaków jest losowany z zestawu wielkich liter. Za zestaw liter przyjmuje się wszystkie litery z klawiatury małe i wielkie alfabetu łacińskiego.
Arkusz upraszcza zadanie: można przyjąć, że określony znak losujesz z innego zestawu. W tym rozwiązaniu pierwszy znak (i == 0) jest wielką literą, gdy pole wyboru jest zaznaczone - stan odczytujesz ze zmiennej kontrolki: self.letters_var.get() zwraca True albo False (R.3.7).
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 24: Cyfra i znak specjalny
Kryteria: ,
R.3.7 Znaki do hasła są wybierane przy wykorzystaniu generatora liczb pseudolosowych z zestawu znaków, który zawsze obejmuje małe litery a..z oraz gdy wybrano pierwszy checkbox wielkie litery A..Z i gdy wybrano drugi checkbox cyfry: 0..9 oraz gdy wybrano trzeci checkbox znaki specjalne ze zbioru !@#$%^&*()_+-=
R.3.8 Hasło oraz zestawy znaków są przechowywane w zmiennych typu napisowego, hasło jest widoczne dla obu metod obsługujących kliknięcia przycisków
ok. 3 min
Polecenie z arkusza
Jeżeli zaznaczono checkbox „Cyfry”, jeden ze znaków hasła jest losowany z zestawu cyfr. Jeżeli zaznaczono checkbox „Znaki specjalne”, jeden ze znaków hasła jest losowany z zestawu znaków specjalnych. Dla uproszczenia zadania można przyjąć zawsze określony znak (np. pierwszy), który jest losowany z cyfr. Za zestaw znaków specjalnych przyjmuje się znaki !@#$%^&*()_+-=.
Drugi znak (i == 1) to cyfra, trzeci (i == 2) - znak specjalny, każdy tylko przy zaznaczonym polu; pozostałe są małymi literami. Łańcuch if ... elif ... else gwarantuje, że na każdej pozycji losujesz dokładnie raz. Zestawy znaków to stałe napisowe na górze pliku (R.3.8).
Zaznacz w podglądzie „Cyfry”, wpisz 5 i wygeneruj hasło - wynik w rodzaju „Mb7ri”, jak na obrazie 2.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 25: Zatwierdź: dane pracownika w komunikacie
Kryteria: , ,
R.3.5 Po wciśnięciu przynajmniej jednego przycisku wywoływana jest funkcja
R.3.8 Hasło oraz zestawy znaków są przechowywane w zmiennych typu napisowego, hasło jest widoczne dla obu metod obsługujących kliknięcia przycisków
R.3.9 Po wybraniu przycisku „Zatwierdź” wyświetla się komunikat w nowym oknie w którym ujęte są: imię, nazwisko, wartość wybrana z listy rozwijalnej oraz wygenerowane wcześniej hasło
ok. 3 min
Polecenie z arkusza
Działanie aplikacji po wybraniu przycisku „Zatwierdź”: wyświetlany jest komunikat z wypełnionymi danymi pracownika oraz wygenerowanym wcześniej hasłem, zgodnie z obrazem 3.
Druga metoda odczytuje tekst pól (get() pola Entry), wybraną pozycję listy (get() listy Combobox zwraca jej tekst) i pole self.password - to samo, które ustawiła metoda generowania. f-napis składa komunikat jak na obrazie 3. Przycisk wiąże z nią command=self.confirm (R.3.9).
Przejdź w podglądzie scenariusz z obrazu 3: Zofia, Kowalska, Tester, 5 znaków z cyframi, „Generuj hasło”, potem „Zatwierdź” - w komunikacie jest to samo hasło.
Typowe błędy
Hasło w zmiennej lokalnej metody (password = "" zamiast self.password = "") znika po jej zakończeniu - metoda confirm go nie zobaczy (błąd NameError) albo pokaże puste pole z konstruktora.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 26: Folder desktopowa: archiwum i źródło
ok. 2 min
Polecenie z arkusza
Kod aplikacji przygotuj do nagrania na płytę. W folderze desktopowa powinno znaleźć się archiwum całego projektu o nazwie desktopowa.zip, pliki źródłowe, które były modyfikowane (interfejs użytkownika i logika aplikacji) oraz plik uruchomieniowy, jeżeli to możliwe.
Pakujesz folder projektu do desktopowa.zip, obok kopiujesz main.py - w Tkinterze interfejs i logika są w tym samym pliku. Pliku uruchomieniowego nie ma.
Kroki 27-30 · po tym etapie masz 32 z 32 kryteriów (pkt)
Krok 27: Dokumentacja funkcji nwd
Kryteria: , , , ,
R.4.1 Dla funkcji wyznaczającej NWD z aplikacji konsolowej zapisano nagłówek w postaci komentarza zgodny z Listingiem 1 z arkusza egzaminacyjnego (nie należy brać pod uwagę liczby gwiazdek), komentarz może być wieloliniowy lub kilku jednoliniowy
R.4.2 W komentarzu ujęto nazwę funkcji oraz opisano jej działanie, np. "funkcja wyznacza NWD metodą Euklidesa"
R.4.3 W komentarzu ujęto wszystkie argumenty funkcji: nazwy i krótki opis
R.4.4 W komentarzu ujęto nazwę typu zwracanego i krótki opis co jest zwracane
R.4.5 W komentarzu ujęto numer zdającego
ok. 4 min
Polecenie z arkusza
W kodzie źródłowym aplikacji konsolowej utwórz nagłówek funkcji wyznaczającej NWD, według wzoru. Nagłówek powinien znaleźć się nad definicją funkcji. W miejscu nawiasów <> należy podać odpowiednie opisy. W miejscu autor należy podać numer zdającego.
W Pythonie opis funkcji to docstring - napis w potrójnym cudzysłowie zaraz pod linią def; gwiazdki z listingu 1 przepisujesz do środka. Arkusz każe umieścić nagłówek „nad definicją”, a klucz (R.4.1) przyjmuje „komentarz wieloliniowy lub kilka jednoliniowych”. Docstring jest w Pythonie właśnie wieloliniowym komentarzem dokumentującym - ale jeśli chcesz trzymać się słowa „nad”, ten sam tekst możesz napisać liniami zaczynanymi od # nad def nwd.
Pola wypełniasz zgodnie z kodem: nazwa i działanie (R.4.2), oba parametry z opisem (R.4.3), zwracany typ int z opisem (R.4.4), autor (R.4.5) - na egzaminie numer PESEL, tu Bartosz Bryniarski.
konsola/main.pyPythonzmienione: 11 linii
defnwd(a, b):""" ****************************************************** nazwa funkcji: nwd opis funkcji: wyznacza największy wspólny dzielnik dwóch liczb algorytmem Euklidesa (odejmuje mniejszą liczbę od większej, aż obie będą równe) parametry: a - pierwsza liczba całkowita dodatnia b - druga liczba całkowita dodatnia zwracany typ i opis: int - największy wspólny dzielnik liczb a i b autor: Bartosz Bryniarski ****************************************************** """while a != b:if a > b: a = a - belse: b = b - areturn adefread_positive(prompt): number = int(input(prompt))while number <= 0: number = int(input("Liczba musi być dodatnia. " + prompt))return numberdefmain(): a = read_positive("Podaj liczbę a: ") b = read_positive("Podaj liczbę b: ")print(f"NWD({a}, {b}) = {nwd(a, b)}")if__name__ == "__main__": main()
Wynik programu po tym kroku
> python main.py
Podaj liczbę a: 48
Podaj liczbę b: 18
NWD(48, 18) = 6
Krok 28: Zrzuty konsola1 i konsola2
Kryteria: , ,
R.1.7 Podjęto próbę skompilowania kodu, co udokumentowano obrazem przedstawiającym uruchomiony program lub jego kompilację
R.2.7 Program kompiluje się i uruchamia w konsoli, co udokumentowano zrzutem ekranu
R.4.6 Zapisano przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja
ok. 3 min
Polecenie z arkusza
Wykonaj zrzuty ekranu dokumentujące uruchomienie aplikacji. Zrzuty powinny obejmować cały obszar ekranu monitora z widocznym paskiem zadań. Aplikacja konsolowa – zrzuty nazwane: konsola1, konsola2, ...
Dwa uruchomienia w PyCharm z różnymi liczbami i zrzut całego ekranu z oknem PyCharm, panelem Run i paskiem zadań: konsola1.png (48 i 18 → 6), konsola2.png (17 i 5 → 1). Zrzuty idą do folderu dokumentacja.
Wynik programu po tym kroku
> python main.py
Podaj liczbę a: 48
Podaj liczbę b: 18
NWD(48, 18) = 6
> python main.py
Podaj liczbę a: 17
Podaj liczbę b: 5
NWD(17, 5) = 1
Krok 29: Zrzuty desktop1 - desktop3
Kryteria: ,
R.3.10 Aplikacja kompiluje się i uruchamia, co udokumentowano zrzutem ekranu, jej układ po uruchomieniu jest zgodny z obrazem 1 w arkuszu egzaminacyjnym. Zaznaczone jest pierwsze pole wyboru
R.4.7 Zapisano przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji desktopowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja
ok. 4 min
Polecenie z arkusza
Wykonać należy co najmniej tyle zrzutów, ile interakcji podejmuje aplikacja (np. stan początkowy, po wypisaniu hasła, po wyświetleniu danych itd.). Aplikacja desktopowa – zrzuty nazwane: desktop1, desktop2, ...
Uruchamiasz aplikację w PyCharm i robisz zrzuty całego ekranu z PyCharm w tle:
desktop1.png - stan początkowy (obraz 1, R.3.10),
desktop2.png - komunikat z wygenerowanym hasłem (obraz 2) - klucz sprawdza generowanie dwa razy, więc warto dorobić drugi zrzut z innym hasłem,
desktop3.png - komunikat po „Zatwierdź” (obraz 3).
Podgląd to prawdziwy zrzut obszaru okna tej aplikacji (Tkinter, Windows 11) z danymi z obrazu 3, tuż przed kliknięciem „Generuj hasło”.
Okno aplikacji po tym kroku
Krok 30: Dokument egzamin z podpisanymi zrzutami
Kryteria:
R.4.8 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy środowisk, nazwy języków programowania
ok. 4 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, nazwy środowisk programistycznych, nazwy języków programowania, opcjonalnie komentarz do wykonanej pracy.
W Wordzie albo Writerze dokument egzamin w folderze dokumentacja: trzy informacje o narzędziach i - w tym arkuszu - także wklejone zrzuty z podpisami (np. „konsola1 - NWD(48, 18)”). W plikach kroku jest tekst tej części jako plik tekstowy.
egzamin.txtTekstnowy plik
System operacyjny: Windows 11Środowisko programistyczne: PyCharm Community (aplikacja konsolowa i desktopowa)Języki programowania: Python (obie aplikacje), biblioteka Tkinter (aplikacja desktopowa)Zrzuty: konsola1, konsola2, desktop1, desktop2, desktop3 - wklejone poniżej z podpisami.
Okno aplikacji po tym kroku
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Etap 5: Porównanie z wariantem C# + WPF
Kroki 31-32 · po tym etapie masz 32 z 32 kryteriów (pkt)
Krok 31: Konsola: kontrola liczb w Pythonie, typ uint w C#
ok. 2 min
Polecenie z arkusza
Liczby a i b należą do zbioru liczb całkowitych dodatnich (odpowiedni typ lub kontrola poprawności wpisanej liczby).
Algorytm jest w obu językach identyczny - pętla while, if/else, odejmowanie - bo tego wymaga schemat. Różnica jest w typach:
C# ma typ bez znakuuint: liczba ujemna nie przejdzie przez uint.Parse, więc klucz uznaje sam typ za „odpowiedni” (ale zero wciąż przechodzi - dlatego wariant C# poprawia to w dobrych praktykach),
Python takiego typu nie ma, a klucz wymaga od niego jawnej konwersji (int(...)) - więc zakres sprawdzasz samodzielnie funkcją read_positive, od razu odrzucając także zero.
W Pythonie nie piszesz typów przy parametrach, więc w dokumentacji funkcji typ zwracany (int) trzeba wpisać z głowy - musi zgadzać się z tym, co funkcja naprawdę zwraca.
Krok 32: Okno: Tkinter a WPF - odpowiedniki kontrolek
ok. 3 min
Polecenie z arkusza
Za pomocą dostępnego na stanowisku egzaminacyjnym środowiska programistycznego wykonaj aplikację desktopową do wprowadzania danych pracownika z możliwością generowania hasła.
Te same kontrolki pod innymi nazwami:
GroupBox w WPF → LabelFrame, TextBox → Entry, ComboBox → ttk.Combobox, CheckBox → Checkbutton ze zmienną BooleanVar, MessageBox.Show(...) → messagebox.showinfo(...),
pole klasy okna private string password → self.password - w obu wariantach hasło żyje w obiekcie okna, żeby widziały je obie metody przycisków.
Największa różnica to tło: w WPF etykiety i pola wyboru są przezroczyste i widać pod nimi tło okna, w Tkinterze każda kontrolka maluje własne tło - stąd bg=BACKGROUND przy każdej z nich. Na egzaminie wybierz to, co znasz lepiej: punkty za aplikację desktopową (R.3) są w obu technologiach te same.
Krok 33 · po tym etapie masz 32 z 32 kryteriów (pkt)
Krok 33: Nagranie płyty
ok. 5 min
Polecenie z arkusza
UWAGA: Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować podfoldery desktopowa, dokumentacja, konsola. W folderze dokumentacja: pliki ze zrzutami oraz plik egzamin. W folderze konsola: spakowany cały projekt aplikacji konsolowej, źródło, opcjonalnie plik uruchomieniowy. W folderze desktopowa: spakowany cały projekt aplikacji desktopowej, pliki ze źródłami interfejsu i logiki, opcjonalnie plik uruchomieniowy.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
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: Bartosz Bryniarski. 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) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.