Przejdź do głównej treści
INF.04-01-25.06-SGCzerwiec 2025 · 32 kroki · ok. 82 min · 32 kryteria z klucza

Rozwiązanie krok po kroku: Loteria liczbowa i wzornik RGB (Python + Tkinter)

Rozwiązanie dotyczy arkusza z loterią liczbową i wzornikiem kolorów w wersji Python + Tkinter - cały egzamin w jednym języku. W konsoli program, który wczytuje liczbę losowań, buduje listę zestawów po sześć różnych liczb z zakresu 1-49, wyświetla je i zlicza wystąpienia każdej liczby, a w okienku zbudowanym biblioteką Tkinter (jest w każdej instalacji Pythona na Windows) trzy suwaki R, G, B zmieniające kolor dużego prostokąta i przycisk „Pobierz”, który zapamiętuje kolor w małym prostokącie. Do tego dokumentacja funkcji według listingu 1, zrzuty i plik 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) i podpowiadają, co wybrać na egzaminie.

Co widać w podglądzie. Program konsolowy z każdego kroku jest naprawdę uruchamiany (Python 3.12, z wpisaną liczbą 11 jak na obrazie 1 arkusza). Okno to symulacja w przeglądarce, ale jej układ nie jest zgadywany: program z kroku uruchomiłem w prawdziwym Tkinterze i odczytałem położenie, rozmiar, kolor i tekst każdej kontrolki. Suwaki i przycisk działają tak, jak funkcje z kodu kroku - scenariusz z obrazów 3-5 sprawdziłem w symulacji i w prawdziwym oknie Tk z tym samym wynikiem, a w kroku ze zrzutami jest prawdziwy zrzut okna.

Jak liczą się punkty. Klucz ma 32 kryteria (R.1.1 - R.4.9), 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.

  1. 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: konsolowa, desktopowa, dokumentacja. Po wykonaniu każdej aplikacji, jej pełny kod (cały folder projektu) spakuj do archiwum. Następnie pozostaw w podfolderze jedynie skopiowane z projektu pliki źródłowe, których treść była modyfikowana, plik wykonywalny, jeśli jest to możliwe, oraz spakowane archiwum.

    Na pulpicie zakładasz folder z numerem PESEL, a w nim konsolowa, desktopowa i dokumentacja. Arkusz nie ma załącznika - wszystko piszesz od zera. Oba projekty zakładasz w PyCharm (każdy w osobnym folderze: konsola i desktopowa), a na koniec pakujesz je i kopiujesz do podfolderów razem z plikami main.py. Python jest językiem interpretowanym, więc pliku wykonywalnego nie ma - arkusz wymaga go tylko „jeśli jest to możliwe”.

  2. Etap 2: Aplikacja konsolowa

    Kroki 2-10 · po tym etapie masz 14 z 32 kryteriów (pkt)

    Krok 2: Projekt konsola w PyCharm i funkcja main

    ok. 3 min
    Polecenie z arkusza

    Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python. W podejściu strukturalnym nie można stosować zmiennych globalnych.

    Wybierasz Pythona i podejście strukturalne (same funkcje). W PyCharm: New Project, nazwa konsola, interpreter zainstalowany na stanowisku, bez skryptu powitalnego; w projekcie tworzysz plik main.py.

    Arkusz zabrania zmiennych globalnych. W Pythonie każda zmienna utworzona poza funkcją - na „najwyższym poziomie” pliku - jest właśnie globalna. Dlatego program główny od razu zamykasz w funkcji main(), a jej wywołanie stawiasz pod warunkiem if __name__ == "__main__": (prawdziwym, gdy plik uruchomiono, a nie zaimportowano). Zmienne programu głównego będą wtedy lokalnymi zmiennymi main. Słowo pass to pusta instrukcja - ciało funkcji nie może być puste; za chwilę ją zastąpisz.

    konsola/main.py Python nowy plik
    def main():
        pass
    
    
    if __name__ == "__main__":
        main()
    Wynik programu po tym kroku
    > python main.py
  3. Krok 3: Wczytanie liczby losowań z klawiatury

    Kryteria: , ,

    R.1.5 Zastosowane typy pasujące do problemu, np. tablica lub kolekcja liczb całkowitych, dane wczytywane jako typ całkowity

    R.1.7 Program podejmuje zrozumiałą komunikację z użytkownikiem: komunikaty są znaczące, np. "ile losowań?" itp.

    R.1.4 Użyte polskie lub angielskie nazewnictwo pól lub zmiennych. Nazewnictwo jest znaczące. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli. Kryterium nie jest spełnione tylko wtedy, gdy zmienne nie istnieją lub ich nazwy nic nie znaczą, np. x, tab, tablica, foo, kolekcja

    ok. 2 min
    Polecenie z arkusza

    Program wczytuje z klawiatury ile zestawów należy wylosować. Program powinien podejmować zrozumiałą komunikację z użytkownikiem.

    Funkcja input(...) wypisuje pytanie i czeka na tekst zakończony Enterem. Zwraca zawsze napis - nawet gdy wpiszesz cyfry - dlatego otaczasz ją int(...), które zamienia tekst na liczbę całkowitą (R.1.5). Wynik trafia do zmiennej count z czytelną nazwą (R.1.4). W podglądzie wpisano 11, jak na obrazie 1 arkusza.

    Typowe błędy

    count = input(...) bez int zostawia napis „11” - przy range(count) Python zgłosi TypeError, bo pętla potrzebuje liczby.

    konsola/main.py Python zmienione: 1 linia
    def main():
        count = int(input("Ile wygenerować losowań? "))
    
    
    if __name__ == "__main__":
        main()
    Wynik programu po tym kroku
    > python main.py
    Ile wygenerować losowań? 11
  4. Krok 4: Funkcja draw_numbers i lista zestawów

    Kryteria: , ,

    R.2.1 Program składa się z programu głównego oraz co najmniej dwóch funkcji lub metod (mogą być niedokończone lub zawierać błędy). Po wyjściu z funkcji / metody losującej dane nie zostały utracone (w podejściu strukturalnym nie można stosować zmiennych globalnych)

    R.2.2 Do przechowywania danych zastosowana tablica dwuwymiarowa lub inna kolekcja o dynamicznym rozmiarze dostosowanym do ilości danych

    R.1.3 Użyte polskie lub angielskie nazewnictwo funkcji lub metod. Nazewnictwo jest znaczące

    ok. 3 min
    Polecenie z arkusza

    Do przechowywania wyników losowań należy użyć dwuwymiarowej tablicy liczb całkowitych składającej się z n wierszy i 6 kolumn (n – liczba wczytana z klawiatury) lub innej dowolnej kolekcji pasującej do problemu. W programie należy zdefiniować przynajmniej dwie funkcje: Wypełniającą tablicę lub kolekcję danymi losowań.

    Python nie ma wbudowanej tablicy dwuwymiarowej - jej odpowiednikiem jest lista list: zewnętrzna lista draws ma po jednym elemencie na losowanie, a każdy element to lista draw na sześć liczb. Arkusz dopuszcza wprost „inną kolekcję pasującą do problemu”, a lista rośnie do tylu wierszy, ile wpisał użytkownik (R.2.2).

    Listę buduje osobna funkcja draw_numbers(count) i zwraca ją przez return; main zapisuje wynik w swojej zmiennej draws. Dane nie giną po wyjściu z funkcji, a żadna zmienna nie jest globalna (R.2.1). import random na górze pliku - moduł do losowania przyda się w następnym kroku. Na razie każdy zestaw jest pusty.

    konsola/main.py Python zmienione: 12 linii
    import random
    
    
    def draw_numbers(count):
        draws = []
        for _ in range(count):
            draw = []
            draws.append(draw)
        return draws
    
    
    def main():
        count = int(input("Ile wygenerować losowań? "))
        draws = draw_numbers(count)
    
    
    if __name__ == "__main__":
        main()

    Wynik programu bez zmian - taki jak po kroku 3.

  5. Krok 5: Wypełnienie zestawów liczbami z zakresu 1-49

    Kryteria: , , ,

    R.2.3 Do losowania liczb zastosowany generator liczb pseudolosowych, losowane są liczby z przedziału od [1, 49] (+/- 1 z każdej strony przedziału)

    R.2.4 Program wypełnia tablicę lub kolekcję danymi, pętla obsługuje rzeczywistą liczbę losowań

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

    R.1.2 Kod zapisany z wcięciami dla zagnieżdżeń bloków

    ok. 3 min
    Polecenie z arkusza

    Program generuje podaną liczbę zestawów składających się z sześciu losowanych liczb całkowitych ze zbioru <1, 49>. W programie należy użyć funkcji do generowania liczb pseudolosowych.

    random.randint(1, 49) zwraca liczbę pseudolosową od 1 do 49 - w Pythonie obie granice wchodzą do zakresu (R.2.3), inaczej niż w C# (Next(1, 50)). append dokleja liczbę na koniec listy zestawu. Zewnętrzna pętla wykonuje się count razy - tyle zestawów, ile wpisał użytkownik (R.2.4), wewnętrzna sześć razy.

    Podkreślnik _ to umowna nazwa zmiennej pętli, której nie używasz - klucz dopuszcza takie nazwy pomocnicze. Wcięcie o 4 spacje wyznacza w Pythonie, co należy do której pętli, więc jest częścią składni (R.1.1, R.1.2).

    Typowe błędy

    random.randrange(1, 49) wygląda podobnie, ale górnej granicy NIE obejmuje - 49 nigdy nie padnie. Klucz toleruje przesunięcie o 1 (R.2.3), ale dobrze znać różnicę: randint(a, b) to randrange(a, b + 1).

    konsola/main.py Python zmienione: 2 linie
    import random
    
    
    def draw_numbers(count):
        draws = []
        for _ in range(count):
            draw = []
            for _ in range(6):
                draw.append(random.randint(1, 49))
            draws.append(draw)
        return draws
    
    
    def main():
        count = int(input("Ile wygenerować losowań? "))
        draws = draw_numbers(count)
    
    
    if __name__ == "__main__":
        main()

    Wynik programu bez zmian - taki jak po kroku 3.

  6. Krok 6: Funkcja print_draws: wyświetlenie wszystkich losowań

    Kryteria: , ,

    R.2.5 Program wyświetla zawartość tablicy lub kolekcji za pomocą pętli. Wyświetlone wszystkie losowania (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    R.2.1 Program składa się z programu głównego oraz co najmniej dwóch funkcji lub metod (mogą być niedokończone lub zawierać błędy). Po wyjściu z funkcji / metody losującej dane nie zostały utracone (w podejściu strukturalnym nie można stosować zmiennych globalnych)

    R.1.3 Użyte polskie lub angielskie nazewnictwo funkcji lub metod. Nazewnictwo jest znaczące

    ok. 3 min
    Polecenie z arkusza

    Zestawy są wyświetlone na ekranie. W programie należy zdefiniować przynajmniej dwie funkcje: Wyświetlającą wyniki wszystkich losowań na ekranie.

    Druga funkcja dostaje listę jako parametr i tylko wypisuje - niczego nie zwraca. Pętla po liście z enumerate(draws, start=1) daje naraz numer (od 1, bo tak liczy użytkownik) i sam zestaw.

    W print gwiazdka przed listą (*draw) rozpakowuje ją: sześć liczb trafia do print jako sześć osobnych argumentów, a ten rozdziela je spacjami - „Losowanie 1: 34 25 36 26 13 20” jak na obrazie 1. Bez gwiazdki wypisałaby się lista z nawiasami: [34, 25, 36, ...].

    W wydruku zdarza się zestaw z tą samą liczbą dwa razy - losowania jeszcze się nie sprawdzają. Naprawisz to w następnym kroku.

    konsola/main.py Python zmienione: 7 linii
    import random
    
    
    def draw_numbers(count):
        draws = []
        for _ in range(count):
            draw = []
            for _ in range(6):
                draw.append(random.randint(1, 49))
            draws.append(draw)
        return draws
    
    
    def print_draws(draws):
        for number, draw in enumerate(draws, start=1):
            print(f"Losowanie {number}:", *draw)
    
    
    def main():
        count = int(input("Ile wygenerować losowań? "))
        draws = draw_numbers(count)
        print("Zestawy wylosowanych liczb:")
        print_draws(draws)
    
    
    if __name__ == "__main__":
        main()
    Wynik programu po tym kroku
    > python main.py
    Ile wygenerować losowań? 11
    Zestawy wylosowanych liczb:
    Losowanie 1: 6 8 22 13 34 37
    Losowanie 2: 40 6 30 1 5 4
    Losowanie 3: 30 40 13 39 39 28
    Losowanie 4: 1 25 47 46 19 39
    Losowanie 5: 19 13 22 42 38 8
    Losowanie 6: 4 16 36 43 30 45
    Losowanie 7: 29 28 8 18 25 48
    Losowanie 8: 30 20 16 23 39 48
    Losowanie 9: 31 15 4 5 47 14
    Losowanie 10: 13 26 10 46 15 27
    Losowanie 11: 27 35 2 37 49 3
  7. Krok 7: Liczby w zestawie bez powtórzeń

    Kryteria: ,

    R.2.6 Program implementuje losowanie przynajmniej jednego zestawu sześciu liczb bez powtórzeń

    R.1.2 Kod zapisany z wcięciami dla zagnieżdżeń bloków

    ok. 3 min
    Polecenie z arkusza

    W jednym zestawie liczby nie mogą się powtarzać.

    Zamiast sześciu obrotów pętli for piszesz pętlę while len(draw) < 6 - kręci się, dopóki zestaw nie ma sześciu liczb. W każdym obrocie losujesz liczbę i dopisujesz ją tylko wtedy, gdy jeszcze jej nie ma: operator not in sprawdza, czy elementu nie ma na liście. Powtórzona liczba po prostu przepada, a pętla losuje ponownie (R.2.6).

    Typowe błędy

    Pętla for _ in range(6) z warunkiem if number not in draw (bez while) przy trafieniu na powtórkę zostawi zestaw z pięcioma liczbami - obrót się „zmarnuje”.

    konsola/main.py Python zmienione: 4 linie
    import random
    
    
    def draw_numbers(count):
        draws = []
        for _ in range(count):
            draw = []
            while len(draw) < 6:
                number = random.randint(1, 49)
                if number not in draw:
                    draw.append(number)
            draws.append(draw)
        return draws
    
    
    def print_draws(draws):
        for number, draw in enumerate(draws, start=1):
            print(f"Losowanie {number}:", *draw)
    
    
    def main():
        count = int(input("Ile wygenerować losowań? "))
        draws = draw_numbers(count)
        print("Zestawy wylosowanych liczb:")
        print_draws(draws)
    
    
    if __name__ == "__main__":
        main()
    Wynik programu po tym kroku
    > python main.py
    Ile wygenerować losowań? 11
    Zestawy wylosowanych liczb:
    Losowanie 1: 29 13 45 5 26 41
    Losowanie 2: 31 39 14 37 15 18
    Losowanie 3: 25 48 24 18 5 32
    Losowanie 4: 47 8 10 28 36 26
    Losowanie 5: 32 30 4 23 48 3
    Losowanie 6: 13 9 10 47 34 46
    Losowanie 7: 27 13 6 30 32 40
    Losowanie 8: 7 43 37 4 33 18
    Losowanie 9: 26 30 34 7 12 33
    Losowanie 10: 19 9 7 46 8 26
    Losowanie 11: 15 14 3 6 20 4
  8. Krok 8: Zliczanie wystąpień liczb 1-49

    Kryteria:

    R.2.7 Program zlicza wystąpienia wszystkich liczb od 1 do 49 w losowaniach, są one wyświetlane na ekranie (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie, dopuszcza się wyświetlenie tylko niezerowych wystąpień)

    ok. 3 min
    Polecenie z arkusza

    Program zlicza we wszystkich zestawach ile jest wystąpień każdej liczby od 1 do 49, co zostaje wyświetlone na ekranie.

    Liczniki trzymasz w liście [0] * 50 - pięćdziesiąt zer - i indeksem jest sama liczba: wystąpienia siódemki są w occurrences[7]. Element 0 zostaje nieużywany, za to nie trzeba niczego przeliczać. Dwie pętle przechodzą przez wszystkie zestawy i wszystkie liczby, a occurrences[number] += 1 zwiększa licznik wylosowanej liczby. Wyświetlenie dopiszesz w następnym kroku.

    konsola/main.py Python zmienione: 9 linii
    import random
    
    
    def draw_numbers(count):
        draws = []
        for _ in range(count):
            draw = []
            while len(draw) < 6:
                number = random.randint(1, 49)
                if number not in draw:
                    draw.append(number)
            draws.append(draw)
        return draws
    
    
    def print_draws(draws):
        for number, draw in enumerate(draws, start=1):
            print(f"Losowanie {number}:", *draw)
    
    
    def count_occurrences(draws):
        occurrences = [0] * 50
        for draw in draws:
            for number in draw:
                occurrences[number] += 1
        return occurrences
    
    
    def main():
        count = int(input("Ile wygenerować losowań? "))
        draws = draw_numbers(count)
        print("Zestawy wylosowanych liczb:")
        print_draws(draws)
        occurrences = count_occurrences(draws)
    
    
    if __name__ == "__main__":
        main()
    Wynik programu po tym kroku
    > python main.py
    Ile wygenerować losowań? 11
    Zestawy wylosowanych liczb:
    Losowanie 1: 10 13 6 49 9 33
    Losowanie 2: 1 28 37 19 4 47
    Losowanie 3: 38 15 4 7 36 37
    Losowanie 4: 48 26 23 46 33 40
    Losowanie 5: 23 46 20 21 43 10
    Losowanie 6: 36 19 42 6 44 15
    Losowanie 7: 5 34 20 40 46 9
    Losowanie 8: 11 29 18 32 6 7
    Losowanie 9: 27 31 36 35 17 28
    Losowanie 10: 20 17 26 32 14 8
    Losowanie 11: 31 20 6 3 22 24
  9. Krok 9: Wyświetlenie liczby wystąpień

    Kryteria: ,

    R.2.7 Program zlicza wystąpienia wszystkich liczb od 1 do 49 w losowaniach, są one wyświetlane na ekranie (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie, dopuszcza się wyświetlenie tylko niezerowych wystąpień)

    R.1.7 Program podejmuje zrozumiałą komunikację z użytkownikiem: komunikaty są znaczące, np. "ile losowań?" itp.

    ok. 2 min
    Polecenie z arkusza

    Program powinien podejmować zrozumiałą komunikację z użytkownikiem.

    range(1, 50) daje liczby od 1 do 49 - górna granica range nie wchodzi (odwrotnie niż w randint). f-napis f"Wystąpienia liczby {number}: ..." wstawia w miejsca w klamrach wartości zmiennych - forma jak na obrazie 1. Klucz dopuszcza też pokazanie tylko liczb, które padły (R.2.7). Program jest kompletny: suma wszystkich liczników to zawsze 6 × liczba losowań, tu 66.

    konsola/main.py Python zmienione: 6 linii
    import random
    
    
    def draw_numbers(count):
        draws = []
        for _ in range(count):
            draw = []
            while len(draw) < 6:
                number = random.randint(1, 49)
                if number not in draw:
                    draw.append(number)
            draws.append(draw)
        return draws
    
    
    def print_draws(draws):
        for number, draw in enumerate(draws, start=1):
            print(f"Losowanie {number}:", *draw)
    
    
    def count_occurrences(draws):
        occurrences = [0] * 50
        for draw in draws:
            for number in draw:
                occurrences[number] += 1
        return occurrences
    
    
    def print_occurrences(occurrences):
        for number in range(1, 50):
            print(f"Wystąpienia liczby {number}: {occurrences[number]}")
    
    
    def main():
        count = int(input("Ile wygenerować losowań? "))
        draws = draw_numbers(count)
        print("Zestawy wylosowanych liczb:")
        print_draws(draws)
        occurrences = count_occurrences(draws)
        print_occurrences(occurrences)
    
    
    if __name__ == "__main__":
        main()
    Wynik programu po tym kroku
    > python main.py
    Ile wygenerować losowań? 11
    Zestawy wylosowanych liczb:
    Losowanie 1: 46 27 15 36 31 22
    Losowanie 2: 44 31 9 24 35 37
    Losowanie 3: 38 24 32 10 31 3
    Losowanie 4: 36 4 32 15 44 38
    Losowanie 5: 26 18 6 1 9 2
    Losowanie 6: 8 32 9 30 46 14
    Losowanie 7: 36 37 12 40 17 49
    Losowanie 8: 35 14 1 33 37 29
    Losowanie 9: 12 32 47 1 3 11
    Losowanie 10: 43 21 27 29 3 13
    Losowanie 11: 6 15 46 2 11 31
    Wystąpienia liczby 1: 3
    Wystąpienia liczby 2: 2
    Wystąpienia liczby 3: 3
    Wystąpienia liczby 4: 1
    Wystąpienia liczby 5: 0
    Wystąpienia liczby 6: 2
    Wystąpienia liczby 7: 0
    Wystąpienia liczby 8: 1
    Wystąpienia liczby 9: 3
    Wystąpienia liczby 10: 1
    Wystąpienia liczby 11: 2
    Wystąpienia liczby 12: 2
    Wystąpienia liczby 13: 1
    Wystąpienia liczby 14: 2
    Wystąpienia liczby 15: 3
    Wystąpienia liczby 16: 0
    Wystąpienia liczby 17: 1
    Wystąpienia liczby 18: 1
    Wystąpienia liczby 19: 0
    Wystąpienia liczby 20: 0
    Wystąpienia liczby 21: 1
    Wystąpienia liczby 22: 1
    Wystąpienia liczby 23: 0
    Wystąpienia liczby 24: 2
    Wystąpienia liczby 25: 0
    Wystąpienia liczby 26: 1
    Wystąpienia liczby 27: 2
    Wystąpienia liczby 28: 0
    Wystąpienia liczby 29: 2
    Wystąpienia liczby 30: 1
    Wystąpienia liczby 31: 4
    Wystąpienia liczby 32: 4
    Wystąpienia liczby 33: 1
    Wystąpienia liczby 34: 0
    Wystąpienia liczby 35: 2
    Wystąpienia liczby 36: 3
    Wystąpienia liczby 37: 3
    Wystąpienia liczby 38: 2
    Wystąpienia liczby 39: 0
    Wystąpienia liczby 40: 1
    Wystąpienia liczby 41: 0
    Wystąpienia liczby 42: 0
    Wystąpienia liczby 43: 1
    Wystąpienia liczby 44: 2
    Wystąpienia liczby 45: 0
    Wystąpienia liczby 46: 3
    Wystąpienia liczby 47: 1
    Wystąpienia liczby 48: 0
    Wystąpienia liczby 49: 1
  10. Krok 10: Folder konsolowa: archiwum i źródło

    Kryteria:

    R.4.9 Na płycie wszystkie wykonane projekty są spakowane oraz umieszczone pliki źródłowe i pliki wykonywalne (jeśli istnieją) na zewnątrz archiwów

    ok. 3 min
    Polecenie z arkusza

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

    Najpierw dopisujesz dokumentację funkcji z części III (krok niżej) - archiwum ma zawierać kod z komentarzem. Potem pakujesz cały folder projektu konsola do konsola.zip (w Eksploratorze: prawy przycisk → Kompresuj do pliku ZIP), a obok kopiujesz main.py. Pliku wykonywalnego w Pythonie nie ma; folder .venv, jeśli PyCharm go utworzył, można przed spakowaniem usunąć - to kopia interpretera, nie twój kod.

    Wynik programu bez zmian - taki jak po kroku 9.

  11. Etap 3: Aplikacja desktopowa

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

    Krok 11: Projekt desktopowa: okno Tkinter

    ok. 3 min
    Polecenie z arkusza

    Za pomocą dostępnego na stanowisku egzaminacyjnym środowiska programistycznego wykonaj aplikację desktopową wybierania kolorów z palety RGB.

    Aplikację okienkową w Pythonie budujesz biblioteką Tkinter - jest częścią standardowej instalacji, nic nie trzeba doinstalowywać. W PyCharm zakładasz drugi projekt, desktopowa, z plikiem main.py. Trzy linie wystarczą na okno:

    • import tkinter as tk - importujesz bibliotekę pod krótką nazwą tk,
    • root = tk.Tk() - tworzysz okno główne; wszystkie kontrolki będą jego „dziećmi”,
    • root.mainloop() - pętla zdarzeń: okno czeka na kliknięcia i ruchy myszy, aż je zamkniesz. Musi być ostatnią linią programu - kod pod nią wykona się dopiero po zamknięciu okna.

    W Tkinterze nie ma projektanta okien jak w Visual Studio - cały wygląd zapisujesz w kodzie. Podgląd pokazuje puste okno z domyślnym tytułem „tk”.

    desktopowa/main.py Python nowy plik
    import tkinter as tk
    
    root = tk.Tk()
    
    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ć.

  12. Krok 12: Tytuł i rozmiar okna

    Kryteria:

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    ok. 2 min
    Polecenie z arkusza

    Opis wyglądu aplikacji: Tytuł okna „Wzornik kolorów RGB. Wykonał” dalej wstawiony numer zdającego.

    Metoda title okna ustawia napis na pasku tytułu. Na egzaminie po „Wykonał” wpisujesz numer PESEL - tu stoi autor rozwiązania, Bartosz Bryniarski. Plik zapisany w UTF-8 (domyślnie w PyCharm), więc polskie litery tytułu wyświetlają się poprawnie.

    Od razu nadajesz oknu rozmiar: geometry("600x330") - szerokość × wysokość w pikselach, z małą literą x pomiędzy. Domyślne puste okno Tkintera ma 200 × 200 pikseli i z tak długiego tytułu zostałyby na pasku dwie litery. (Gdy rozmiaru nie podasz, a w oknie są już kontrolki, Tkinter dopasuje okno do nich - przy kilku kontrolkach byłoby wąskie, a suwaki krótkie.)

    desktopowa/main.py Python zmienione: 2 linie
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    
    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ć.

  13. Krok 13: Tło okna Cornsilk

    Kryteria:

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    ok. 1 min
    Polecenie z arkusza

    Tło okna: Cornsilk (#FFF8DC).

    configure(bg="#FFF8DC") ustawia tło okna (bg to skrót od background). Tkinter zna też nazwy kolorów, więc bg="cornsilk" daje to samo - wpisujesz kod z arkusza, wtedy nie ma wątpliwości.

    desktopowa/main.py Python zmienione: 1 linia
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    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ć.

  14. Krok 14: Duży biały prostokąt

    Kryteria: ,

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    R.3.2 W stanie początkowym: - prostokąty są koloru białego, mały wyświetla wartość 255, 255, 255, - przynajmniej jeden suwak przyjmuje wartości od 0 do 255, - przynajmniej jeden suwak i odpowiadająca mu etykieta mają wartość 255

    ok. 2 min
    Polecenie z arkusza

    Duży prostokąt o białym kolorze tła.

    Prostokątem może być dowolna kontrolka z tłem (klucz, R.3.1). Bierzesz tk.Frame - pustą ramkę: pierwszy argument root mówi, w czym leży, bg="white" to białe tło, height=60 - wysokość.

    Utworzona kontrolka jest jeszcze niewidoczna - trzeba ją ułożyć w oknie. Robi to menedżer układu pack: układa kontrolki jedna pod drugą, w kolejności wywołań. fill="x" rozciąga ramkę na całą szerokość, padx=20 odsuwa ją od lewej i prawej krawędzi, a pady=(20, 0) - para wartości - daje 20 pikseli odstępu od góry i 0 od dołu. Nazwa zmiennej color_rectangle przyda się, gdy kod będzie zmieniał kolor prostokąta.

    Typowe błędy

    Kontrolka bez pack() (albo grid()) istnieje w pamięci, ale nie pokazuje się w oknie - to najczęstszy powód „pustego okna” w Tkinterze.

    desktopowa/main.py Python zmienione: 3 linie
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    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ć.

  15. Krok 15: Napis nad suwakami

    Kryteria:

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    ok. 1 min
    Polecenie z arkusza

    Napis: „Dobierz kolor suwakami i zapisz przyciskiem:”

    Napis to tk.Label z treścią w text. Etykieta ma własne tło - domyślnie szare - więc podajesz mu kolor okna, inaczej pod napisem byłby szary pasek. anchor="w" w pack przykleja etykietę do lewej krawędzi (w = west, zachód); bez tego pack stawia kontrolki na środku.

    desktopowa/main.py Python zmienione: 3 linie
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    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ć.

  16. Krok 16: Trzy suwaki 0-255 w siatce grid

    Kryteria: ,

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    R.3.2 W stanie początkowym: - prostokąty są koloru białego, mały wyświetla wartość 255, 255, 255, - przynajmniej jeden suwak przyjmuje wartości od 0 do 255, - przynajmniej jeden suwak i odpowiadająca mu etykieta mają wartość 255

    ok. 4 min
    Polecenie z arkusza

    Trzy suwaki, każdy o wartości początkowej 255 oraz zakresie wartości od 0 do 255.

    Suwak ma po lewej literę, a po prawej wartość - to tabela 3 × 3. Wstawiasz więc ramkę sliders, a w niej układasz kontrolki drugim menedżerem układu, grid: row i column (liczone od 0) wskazują komórkę. columnconfigure(1, weight=1) każe kolumnie 1 zajmować całe wolne miejsce, a sticky="we" rozciąga suwak od lewej (w) do prawej (e) krawędzi komórki. W jednej ramce nie mieszasz pack i grid - dlatego siatka siedzi w osobnej ramce.

    Suwak to tk.Scale: zakres from_=0 (z podkreśleniem, bo from jest w Pythonie słowem zarezerwowanym) i to=255, orient="horizontal" - poziomo. Wartość początkową ustawia set(255) (R.3.2). showvalue=False wyłącza liczbę rysowaną nad uchwytem - arkusz chce wartości w osobnej etykiecie po prawej. highlightthickness=0 usuwa ramkę zaznaczenia wokół suwaka.

    Wartości Scale są całkowite (krok 1), więc nie trzeba niczego zaokrąglać.

    Typowe błędy

    tk.Scale(..., from=0, ...) to błąd składni - słowo from jest zarezerwowane (from ... import). Tkinter przyjmuje ten parametr jako from_.

    desktopowa/main.py Python zmienione: 17 linii
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    
    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ć.

  17. Krok 17: Etykiety R, G, B po lewej

    Kryteria:

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    ok. 1 min
    Polecenie z arkusza

    Z lewej strony suwaków kolejno etykiety: R, G, B.

    Trzy etykiety w kolumnie 0, po jednej w każdym wierszu. Ich treści nic nie zmienia, więc nie zapisujesz ich w zmiennych - grid wywołujesz od razu na utworzonej etykiecie. (Uwaga: tk.Label(...).grid(...) zwraca None, więc zapisanie takiego wyniku do zmiennej nic by nie dało - przy kontrolkach, które kod zmienia, tworzenie i układanie piszesz w dwóch liniach.)

    desktopowa/main.py Python zmienione: 4 linie
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    
    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ć.

  18. Krok 18: Etykiety z wartością suwaków po prawej

    Kryteria: ,

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    R.3.2 W stanie początkowym: - prostokąty są koloru białego, mały wyświetla wartość 255, 255, 255, - przynajmniej jeden suwak przyjmuje wartości od 0 do 255, - przynajmniej jeden suwak i odpowiadająca mu etykieta mają wartość 255

    ok. 1 min
    Polecenie z arkusza

    Z prawej strony suwaków etykiety z aktualną wartością suwaka, początkowo ustawione na 255.

    Kolumna 2 - etykiety z tekstem 255, każda w zmiennej (red_value, green_value, blue_value), bo kod będzie zmieniał ich treść. width=4 ustala szerokość w znakach: etykieta ma zawsze miejsce na trzy cyfry, więc gdy wartość zmieni się z 255 na 7, suwaki nie „podskoczą” w bok. Na razie ruch suwaka niczego tu nie zmienia.

    desktopowa/main.py Python zmienione: 6 linii
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    red_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    red_value.grid(row=0, column=2)
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    green_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    green_value.grid(row=1, column=2)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    blue_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    blue_value.grid(row=2, column=2)
    
    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ć.

  19. Krok 19: Przycisk Pobierz w kolorze Peru

    Kryteria:

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    ok. 1 min
    Polecenie z arkusza

    Przycisk „Pobierz” koloru Peru ( #CD853F).

    tk.Button z napisem w text i tłem #CD853F. width=20 to szerokość w znakach - przycisk jest wyraźnie szerszy niż napis, jak na obrazie 2. pack bez fill stawia go na środku okna. Obsługi kliknięcia jeszcze nie ma.

    desktopowa/main.py Python zmienione: 3 linie
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    red_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    red_value.grid(row=0, column=2)
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    green_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    green_value.grid(row=1, column=2)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    blue_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    blue_value.grid(row=2, column=2)
    
    fetch_button = tk.Button(root, text="Pobierz", bg="#CD853F", width=20)
    fetch_button.pack(pady=(15, 0))
    
    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ć.

  20. Krok 20: Mały prostokąt z napisem 255, 255, 255

    Kryteria: ,

    R.3.1 W oknie zdefiniowane wszystkie kontrolki (etykiety, suwaki, przycisk) oraz ich układ jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (prostokąty mały i duży mogą być dowolną kontrolką, która daje efekt przedstawiony na obrazie 2)

    R.3.2 W stanie początkowym: - prostokąty są koloru białego, mały wyświetla wartość 255, 255, 255, - przynajmniej jeden suwak przyjmuje wartości od 0 do 255, - przynajmniej jeden suwak i odpowiadająca mu etykieta mają wartość 255

    ok. 1 min
    Polecenie z arkusza

    Etykieta z pobraną wartością suwaków, domyślnie „255, 255, 255” o kolorze tła białym (mały prostokąt).

    Mały prostokąt to etykieta z białym tłem i tekstem „255, 255, 255”, tej samej szerokości co przycisk, więc też na środku. Zmienna saved_color - kod zmieni jej kolor i tekst. Wygląd okna odpowiada obrazowi 2 (R.3.1, R.3.2).

    desktopowa/main.py Python zmienione: 3 linie
    import tkinter as tk
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    red_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    red_value.grid(row=0, column=2)
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    green_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    green_value.grid(row=1, column=2)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    blue_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    blue_value.grid(row=2, column=2)
    
    fetch_button = tk.Button(root, text="Pobierz", bg="#CD853F", width=20)
    fetch_button.pack(pady=(15, 0))
    
    saved_color = tk.Label(root, text="255, 255, 255", bg="white", width=20)
    saved_color.pack(pady=10)
    
    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ć.

  21. Krok 21: Funkcja update_color: wartości przy suwakach

    Kryteria: ,

    R.3.4 Zmiana położenia przynajmniej jednego suwaka powoduje wyświetlenie aktualnej wartości suwaka po jego prawej stronie (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    R.1.3 Użyte polskie lub angielskie nazewnictwo funkcji lub metod. Nazewnictwo jest znaczące

    ok. 4 min
    Polecenie z arkusza

    Działanie aplikacji: Zmiany położenia suwaków powodują zmianę wartości RGB po prawej stronie suwaka.

    Kod reagujący na ruch suwaka to zwykła funkcja Pythona, przekazana kontrolce w parametrze command=update_color - bez nawiasów, bo przekazujesz samą funkcję, a Tkinter wywoła ją przy każdej zmianie wartości. Jedna funkcja obsługuje wszystkie trzy suwaki, bo i tak odczytuje komplet wartości.

    Scale przy wywołaniu przekazuje nową wartość jako argument, dlatego funkcja musi mieć parametr (value) - nawet jeśli z niego nie korzysta. W środku metodą get() odczytujesz liczbę z każdego suwaka, a config(text=...) podmienia treść etykiety (R.3.4). Funkcja stoi nad root = tk.Tk(), bo musi istnieć, zanim przekażesz ją suwakom.

    Przesuń suwak w podglądzie - liczba po prawej zmienia się razem z nim. A dlaczego funkcja nie wywraca się na starcie, choć set(255) czerwonego suwaka pada, gdy zielonego jeszcze nie ma? Tkinter wywołuje command dopiero w pętli zdarzeń, czyli po zbudowaniu całego okna. (W WPF ten sam układ wymaga sprawdzenia IsLoaded.)

    Typowe błędy

    command=update_color() z nawiasami wywoła funkcję raz, w chwili tworzenia suwaka (gdy etykiet jeszcze nie ma - błąd NameError), a suwakowi przekaże jej wynik, czyli None. Druga pułapka: funkcja bez parametru def update_color(): - każdy ruch suwaka kończy się błędem TypeError w konsoli PyCharm.

    desktopowa/main.py Python zmienione: 13 linii
    import tkinter as tk
    
    
    def update_color(value):
        red = red_scale.get()
        green = green_scale.get()
        blue = blue_scale.get()
        red_value.config(text=red)
        green_value.config(text=green)
        blue_value.config(text=blue)
    
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    red_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    red_value.grid(row=0, column=2)
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    green_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    green_value.grid(row=1, column=2)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    blue_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    blue_value.grid(row=2, column=2)
    
    fetch_button = tk.Button(root, text="Pobierz", bg="#CD853F", width=20)
    fetch_button.pack(pady=(15, 0))
    
    saved_color = tk.Label(root, text="255, 255, 255", bg="white", width=20)
    saved_color.pack(pady=10)
    
    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ć.

  22. Krok 22: Kolor dużego prostokąta z suwaków

    Kryteria: ,

    R.3.5 Zmiana położenia każdego z trzech suwaków powoduje zmianę koloru dużego prostokąta. Kolor odpowiada wartościom RGB ustawionym na suwakach (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    R.1.5 Zastosowane typy pasujące do problemu, np. tablica lub kolekcja liczb całkowitych, dane wczytywane jako typ całkowity

    ok. 3 min
    Polecenie z arkusza

    Zmiany położenia suwaków powodują ustawienie koloru dużego prostokąta na wartość RGB odpowiadającą suwakom (obraz 3).

    Tkinter przyjmuje kolor jako napis #RRGGBB - trzy składowe zapisane szesnastkowo, po dwie cyfry. Składasz go f-napisem: w klamrach format :02x zamienia liczbę na zapis szesnastkowy (x) z co najmniej dwiema cyframi i zerem z przodu (02) - 66 to 42, 7 to 07, 255 to ff. Dla 66, 113, 183 powstaje #4271b7. config(bg=...) ustawia tło prostokąta (R.3.5). Przesuń dowolny suwak - prostokąt od razu zmienia kolor.

    Typowe błędy

    f"#{red:x}{green:x}{blue:x}" bez 02 dla wartości 7 daje jedną cyfrę - napis ma wtedy mniej niż 6 znaków i Tkinter zgłasza błąd unknown color name albo pokazuje zupełnie inny kolor.

    desktopowa/main.py Python zmienione: 1 linia
    import tkinter as tk
    
    
    def update_color(value):
        red = red_scale.get()
        green = green_scale.get()
        blue = blue_scale.get()
        red_value.config(text=red)
        green_value.config(text=green)
        blue_value.config(text=blue)
        color_rectangle.config(bg=f"#{red:02x}{green:02x}{blue:02x}")
    
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    red_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    red_value.grid(row=0, column=2)
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    green_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    green_value.grid(row=1, column=2)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    blue_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    blue_value.grid(row=2, column=2)
    
    fetch_button = tk.Button(root, text="Pobierz", bg="#CD853F", width=20)
    fetch_button.pack(pady=(15, 0))
    
    saved_color = tk.Label(root, text="255, 255, 255", bg="white", width=20)
    saved_color.pack(pady=10)
    
    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ć.

  23. Krok 23: Przycisk Pobierz: kolor małego prostokąta

    Kryteria: ,

    R.3.3 Zdefiniowana metoda obsługująca kliknięcie przycisku

    R.3.6 Tylko po kliknięciu przycisku zmienia się kolor małego prostokąta. Kolor odpowiada wartościom RGB ustawionym na suwakach (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 3 min
    Polecenie z arkusza

    Po wciśnięciu przycisku „Pobierz” mały prostokąt na dole okna ma ustawiony kolor oraz tekst odpowiadający aktualnemu RGB (obraz 4).

    Przycisk też dostaje funkcję w parametrze command=fetch_color (R.3.3) - przycisk wywołuje ją bez argumentów, więc tu parametru nie ma. Funkcja odczytuje suwaki tak samo jak update_color i ustawia tło małego prostokąta. Ten kod wykonuje się wyłącznie po kliknięciu - dlatego dalsze ruchy suwakami nie zmieniają już pobranego koloru (obraz 5, R.3.6). Ustaw kolor, kliknij „Pobierz”, potem przesuń suwak: duży prostokąt się zmienia, mały - nie.

    desktopowa/main.py Python zmienione: 9 linii
    import tkinter as tk
    
    
    def update_color(value):
        red = red_scale.get()
        green = green_scale.get()
        blue = blue_scale.get()
        red_value.config(text=red)
        green_value.config(text=green)
        blue_value.config(text=blue)
        color_rectangle.config(bg=f"#{red:02x}{green:02x}{blue:02x}")
    
    
    
    def fetch_color():
        red = red_scale.get()
        green = green_scale.get()
        blue = blue_scale.get()
        saved_color.config(bg=f"#{red:02x}{green:02x}{blue:02x}")
    
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    red_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    red_value.grid(row=0, column=2)
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    green_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    green_value.grid(row=1, column=2)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    blue_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    blue_value.grid(row=2, column=2)
    
    fetch_button = tk.Button(root, text="Pobierz", bg="#CD853F", width=20, command=fetch_color)
    fetch_button.pack(pady=(15, 0))
    
    saved_color = tk.Label(root, text="255, 255, 255", bg="white", width=20)
    saved_color.pack(pady=10)
    
    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ć.

  24. Krok 24: Przycisk Pobierz: tekst z wartościami RGB

    Kryteria:

    R.3.7 Po kliknięciu przycisku zmienia się tekst w małym prostokącie, odpowiada on wartościom suwaków (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 2 min
    Polecenie z arkusza

    Po wciśnięciu przycisku „Pobierz” mały prostokąt na dole okna ma ustawiony kolor oraz tekst odpowiadający aktualnemu RGB (obraz 4). Mały prostokąt nie zmienia się, jego zmianę może wywołać dopiero przyciśnięcie przycisku „Pobierz”.

    Treść etykiety składasz f-napisem z trzech liczb rozdzielonych przecinkiem i spacją - jak „66, 113, 183” na obrazie 4 (R.3.7). Tym razem bez formatu :02x, bo użytkownik ma zobaczyć liczby dziesiętne. Aplikacja jest kompletna - przejdź w podglądzie obrazy 3, 4 i 5.

    desktopowa/main.py Python zmienione: 1 linia
    import tkinter as tk
    
    
    def update_color(value):
        red = red_scale.get()
        green = green_scale.get()
        blue = blue_scale.get()
        red_value.config(text=red)
        green_value.config(text=green)
        blue_value.config(text=blue)
        color_rectangle.config(bg=f"#{red:02x}{green:02x}{blue:02x}")
    
    
    
    def fetch_color():
        red = red_scale.get()
        green = green_scale.get()
        blue = blue_scale.get()
        saved_color.config(bg=f"#{red:02x}{green:02x}{blue:02x}")
        saved_color.config(text=f"{red}, {green}, {blue}")
    
    
    root = tk.Tk()
    root.title("Wzornik kolorów RGB. Wykonał Bartosz Bryniarski")
    root.geometry("600x330")
    root.configure(bg="#FFF8DC")
    
    color_rectangle = tk.Frame(root, bg="white", height=60)
    color_rectangle.pack(fill="x", padx=20, pady=(20, 0))
    
    info_label = tk.Label(root, text="Dobierz kolor suwakami i zapisz przyciskiem:", bg="#FFF8DC")
    info_label.pack(anchor="w", padx=20, pady=(15, 5))
    
    sliders = tk.Frame(root, bg="#FFF8DC")
    sliders.pack(fill="x", padx=20)
    sliders.columnconfigure(1, weight=1)
    
    tk.Label(sliders, text="R", bg="#FFF8DC").grid(row=0, column=0)
    tk.Label(sliders, text="G", bg="#FFF8DC").grid(row=1, column=0)
    tk.Label(sliders, text="B", bg="#FFF8DC").grid(row=2, column=0)
    
    red_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    red_scale.set(255)
    red_scale.grid(row=0, column=1, sticky="we")
    red_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    red_value.grid(row=0, column=2)
    green_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    green_scale.set(255)
    green_scale.grid(row=1, column=1, sticky="we", pady=6)
    green_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    green_value.grid(row=1, column=2)
    blue_scale = tk.Scale(sliders, from_=0, to=255, orient="horizontal", showvalue=False,
                         bg="#FFF8DC", highlightthickness=0, command=update_color)
    blue_scale.set(255)
    blue_scale.grid(row=2, column=1, sticky="we")
    blue_value = tk.Label(sliders, text="255", width=4, bg="#FFF8DC")
    blue_value.grid(row=2, column=2)
    
    fetch_button = tk.Button(root, text="Pobierz", bg="#CD853F", width=20, command=fetch_color)
    fetch_button.pack(pady=(15, 0))
    
    saved_color = tk.Label(root, text="255, 255, 255", bg="white", width=20)
    saved_color.pack(pady=10)
    
    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ć.

  25. Krok 25: Folder desktopowa: archiwum i źródło

    Kryteria:

    R.4.9 Na płycie wszystkie wykonane projekty są spakowane oraz umieszczone pliki źródłowe i pliki wykonywalne (jeśli istnieją) na zewnątrz archiwów

    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, skopiowane z projektu pliki źródłowe, które były modyfikowane w czasie egzaminu (interfejs użytkownika i logika aplikacji) oraz plik wykonywalny, jeżeli istnieje.

    Pakujesz folder projektu do desktopowa.zip i kopiujesz obok main.py. W Tkinterze wygląd i logika są w jednym pliku - arkusz pisze o plikach interfejsu i logiki z myślą o środowiskach takich jak WPF (.xaml i .xaml.cs); tu jeden plik spełnia oba warunki. Pliku wykonywalnego nie ma.

    Okno aplikacji bez zmian - taki jak po kroku 24.

  26. Etap 4: Dokumentacja aplikacji

    Kroki 26-29 · po tym etapie masz 32 z 32 kryteriów (pkt)

    Krok 26: Dokumentacja funkcji draw_numbers

    Kryteria: , , , ,

    R.4.1 Dla dowolnej funkcji lub metody zapisany nagłówek w postaci komentarza zgodnego z Listingiem 1 z arkusza egzaminacyjnego (nie należy brać pod uwagę liczby gwiazdek) , komentarz może być wieloliniowy lub kilka jednoliniowych, lub Docstrings (potrójny cudzysłów) - w tym przypadku opis znajduje się pod nazwą funkcji

    R.4.2 W komentarzu umieszczona nazwa funkcji / metody oraz opisane jej działanie

    R.4.3 W komentarzu umieszczone wszystkie argumenty funkcji / metody: nazwy i krótki opis lub "brak", gdy nie ma argumentów

    R.4.4 W komentarzu umieszczona nazwa typu zwracanego i krótki opis co jest zwracane lub "brak", gdy funkcja nie zwraca wartości

    R.4.5 W komentarzu umieszczony numer zdającego

    ok. 4 min
    Polecenie z arkusza

    W kodzie źródłowym aplikacji konsolowej za pomocą komentarza utwórz nagłówek jednej dowolnej funkcji/metody, według wzoru z listingu 1. Komentarz powinien znaleźć się nad lub pod nazwą funkcji. W miejscu nawiasów <> należy podać odpowiednie opisy. W miejscu autor należy podać numer zdającego.

    W Pythonie opis funkcji zapisuje się jako docstring - napis w potrójnym cudzysłowie zaraz pod linią def. Klucz dopuszcza go wprost (R.4.1, „Docstrings (potrójny cudzysłów) - w tym przypadku opis znajduje się pod nazwą funkcji”). Wypełniasz pola z listingu 1 zgodnie z kodem: nazwa i działanie (R.4.2), parametr count z opisem (R.4.3), zwracany typ list z opisem (R.4.4) i autor (R.4.5) - na egzaminie numer PESEL, tu Bartosz Bryniarski.

    Docstring to nie tylko ozdoba: PyCharm pokazuje go w podpowiedzi po najechaniu na nazwę funkcji, a help(draw_numbers) wypisuje go w konsoli.

    Typowe błędy

    Docstring wstawiony NAD def nie jest już docstringiem, tylko luźnym napisem - Python go zignoruje. Komentarz nad funkcją pisze się wtedy znakami # w każdej linii.

    konsola/main.py Python zmienione: 7 linii
    import random
    
    
    def draw_numbers(count):
        """
        nazwa funkcji:       draw_numbers
        opis funkcji:        losuje zestawy po 6 różnych liczb z zakresu 1-49
        parametry:           count - liczba zestawów do wylosowania
        zwracany typ i opis: list - lista count list, każda z 6 wylosowanymi liczbami
        autor:               Bartosz Bryniarski
        """
        draws = []
        for _ in range(count):
            draw = []
            while len(draw) < 6:
                number = random.randint(1, 49)
                if number not in draw:
                    draw.append(number)
            draws.append(draw)
        return draws
    
    
    def print_draws(draws):
        for number, draw in enumerate(draws, start=1):
            print(f"Losowanie {number}:", *draw)
    
    
    def count_occurrences(draws):
        occurrences = [0] * 50
        for draw in draws:
            for number in draw:
                occurrences[number] += 1
        return occurrences
    
    
    def print_occurrences(occurrences):
        for number in range(1, 50):
            print(f"Wystąpienia liczby {number}: {occurrences[number]}")
    
    
    def main():
        count = int(input("Ile wygenerować losowań? "))
        draws = draw_numbers(count)
        print("Zestawy wylosowanych liczb:")
        print_draws(draws)
        occurrences = count_occurrences(draws)
        print_occurrences(occurrences)
    
    
    if __name__ == "__main__":
        main()
    Wynik programu po tym kroku
    > python main.py
    Ile wygenerować losowań? 11
    Zestawy wylosowanych liczb:
    Losowanie 1: 11 29 4 43 10 37
    Losowanie 2: 16 44 10 21 13 8
    Losowanie 3: 40 43 46 41 45 42
    Losowanie 4: 14 4 22 31 48 3
    Losowanie 5: 34 21 30 14 41 16
    Losowanie 6: 29 6 26 20 38 18
    Losowanie 7: 21 18 17 30 10 33
    Losowanie 8: 33 35 42 41 21 9
    Losowanie 9: 49 29 25 4 14 35
    Losowanie 10: 32 7 8 25 9 38
    Losowanie 11: 8 33 15 43 44 12
    Wystąpienia liczby 1: 0
    Wystąpienia liczby 2: 0
    Wystąpienia liczby 3: 1
    Wystąpienia liczby 4: 3
    Wystąpienia liczby 5: 0
    Wystąpienia liczby 6: 1
    Wystąpienia liczby 7: 1
    Wystąpienia liczby 8: 3
    Wystąpienia liczby 9: 2
    Wystąpienia liczby 10: 3
    Wystąpienia liczby 11: 1
    Wystąpienia liczby 12: 1
    Wystąpienia liczby 13: 1
    Wystąpienia liczby 14: 3
    Wystąpienia liczby 15: 1
    Wystąpienia liczby 16: 2
    Wystąpienia liczby 17: 1
    Wystąpienia liczby 18: 2
    Wystąpienia liczby 19: 0
    Wystąpienia liczby 20: 1
    Wystąpienia liczby 21: 4
    Wystąpienia liczby 22: 1
    Wystąpienia liczby 23: 0
    Wystąpienia liczby 24: 0
    Wystąpienia liczby 25: 2
    Wystąpienia liczby 26: 1
    Wystąpienia liczby 27: 0
    Wystąpienia liczby 28: 0
    Wystąpienia liczby 29: 3
    Wystąpienia liczby 30: 2
    Wystąpienia liczby 31: 1
    Wystąpienia liczby 32: 1
    Wystąpienia liczby 33: 3
    Wystąpienia liczby 34: 1
    Wystąpienia liczby 35: 2
    Wystąpienia liczby 36: 0
    Wystąpienia liczby 37: 1
    Wystąpienia liczby 38: 2
    Wystąpienia liczby 39: 0
    Wystąpienia liczby 40: 1
    Wystąpienia liczby 41: 3
    Wystąpienia liczby 42: 2
    Wystąpienia liczby 43: 3
    Wystąpienia liczby 44: 2
    Wystąpienia liczby 45: 1
    Wystąpienia liczby 46: 1
    Wystąpienia liczby 47: 0
    Wystąpienia liczby 48: 1
    Wystąpienia liczby 49: 1
  27. Krok 27: Zrzut konsola1

    Kryteria: , , ,

    R.2.8 Program uruchamia się w konsoli, co jest udokumentowane zrzutem ekranu

    R.1.6 Podjęta próba uruchomienia, co jest udokumentowane zrzutem przedstawiającym uruchomiony program lub jego kompilację

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

    R.2.5 Program wyświetla zawartość tablicy lub kolekcji za pomocą pętli. Wyświetlone wszystkie losowania (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 3 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ń. Jeżeli aplikacja uruchamia się, na zrzucie należy umieścić okno z wynikiem działania programu oraz otwarte środowisko programistyczne z projektem lub okno terminala z kompilacją projektu. Aplikacja konsolowa – dowolna liczba zrzutów nazwanych konsola1, konsola2, ...

    Uruchamiasz main.py w PyCharm (zielona strzałka albo Shift+F10), w panelu Run wpisujesz liczbę losowań i robisz zrzut całego ekranu (Print Screen) z PyCharm i paskiem zadań - konsola1.png w folderze dokumentacja. Lista wystąpień jest długa; drugi zrzut (konsola2.png) po przewinięciu panelu pokaże jej koniec. Podgląd to prawdziwy wynik programu z dokumentacją.

    Wynik programu bez zmian - taki jak po kroku 26.

  28. Krok 28: Zrzuty desktop1-desktop4

    Kryteria: ,

    R.3.8 Program uruchamia się w oknie, co jest udokumentowane zrzutem ekranu (wymagana przynajmniej jedna kontrolka w oknie)

    R.4.7 Zapisany 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 tyle zrzutów, ile interakcji podejmuje aplikacja (np. stan początkowy, po wybraniu przycisków itd.). Aplikacja desktopowa – dowolna liczba zrzutów nazwanych desktop1, desktop2, ...

    Uruchamiasz aplikację w PyCharm i robisz cztery zrzuty całego ekranu, tak jak obrazy 2-5 arkusza: desktop1.png - stan początkowy, desktop2.png - po przesunięciu suwaków, desktop3.png - po kliknięciu „Pobierz”, desktop4.png - po kolejnym przesunięciu suwaków (mały prostokąt bez zmian). Na każdym ma być okno aplikacji i PyCharm.

    Podgląd to prawdziwy zrzut obszaru okna tej aplikacji (Tkinter, Windows 11) w stanie 4: pobrany kolor 66, 113, 183, a suwaki przestawione dalej - na 188, 87, 179, jak na obrazie 5.

    Typowe błędy

    Zrzut samego okna aplikacji (Alt+Print Screen) nie spełnia R.4.7 - na zrzucie ma być widać środowisko, w którym powstała aplikacja.

    Okno aplikacji po tym kroku
    Okno aplikacji po kroku 28
  29. Krok 29: Plik egzamin

    Kryteria:

    R.4.8 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy środowisk programistycznych, nazwy języków programowania (stosowanych przez zdającego)

    ok. 2 min
    Polecenie z arkusza

    Utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać informacje o narzędziach wykorzystanych na egzaminie: Nazwę systemu operacyjnego, Nazwy środowisk programistycznych, Nazwy języków programowania. Zrzuty ekranu i dokument umieść w folderze dokumentacja.

    Plik egzamin w folderze dokumentacja: system, środowisko i język - to, czego naprawdę użyto. Tkinter to biblioteka, nie osobny język, ale warto ją wymienić obok Pythona.

    egzamin.txt Tekst nowy plik
    System operacyjny: Windows 11
    Środowisko programistyczne: PyCharm Community (aplikacja konsolowa i desktopowa)
    Języki programowania: Python (obie aplikacje), biblioteka Tkinter (aplikacja desktopowa)
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  30. Etap 5: Porównanie z wariantem C# + WPF

    Kroki 30-31 · po tym etapie masz 32 z 32 kryteriów (pkt)

    Krok 30: Konsola: lista list w Pythonie, tablica int[,] w C#

    ok. 3 min
    Polecenie z arkusza

    Do przechowywania wyników losowań należy użyć dwuwymiarowej tablicy liczb całkowitych składającej się z n wierszy i 6 kolumn (n – liczba wczytana z klawiatury) lub innej dowolnej kolekcji pasującej do problemu.

    Ten sam program w obu językach różni się w kilku miejscach, na które łatwo stracić punkt przy przesiadce:

    • kolekcja - w C# prawdziwa tablica dwuwymiarowa int[,] o stałym rozmiarze count × 6, w Pythonie lista list, która rośnie przez append (obie spełniają R.2.2),
    • zakres losowania - random.randint(1, 49) obejmuje 49, random.Next(1, 50) w C# nie obejmuje górnej granicy, stąd 50,
    • powtórki - w Pythonie wystarcza not in, w C# trzeba było napisać pętlę sprawdzającą wypełnione kolumny (IsInDraw),
    • typy - C# wymaga ich wszędzie (int[,], static void), w Pythonie typ wynika z wartości; dlatego int(input(...)) jest tu jedynym miejscem, gdzie typ trzeba zadbać ręcznie.

    Python ma też gotowe random.sample(range(1, 50), 6) - sześć różnych liczb w jednej linii. Na egzaminie lepiej pokazać własną pętlę: R.2.6 sprawdza, czy program implementuje losowanie bez powtórzeń, a gotowa funkcja może zostać uznana za obejście zadania.

    Okno aplikacji bez zmian - taki jak po kroku 29.

  31. Krok 31: Okno: Tkinter a WPF - co wybrać na egzaminie

    ok. 3 min
    Polecenie z arkusza

    Za pomocą dostępnego na stanowisku egzaminacyjnym środowiska programistycznego wykonaj aplikację desktopową wybierania kolorów z palety RGB.

    Najważniejsze różnice wobec wariantu WPF:

    • wygląd - w WPF zapisany osobno w XAML (z projektantem okien), w Tkinterze w tym samym pliku co logika, przez pack i grid; nie ma podglądu w trakcie pisania, więc częściej uruchamiasz program,
    • zdarzenia - WPF wiąże je w XAML (ValueChanged="..."), Tkinter przez parametr command= przy tworzeniu kontrolki,
    • kolory - WPF potrzebuje pędzla (new SolidColorBrush(Color.FromRgb(...))), Tkinter przyjmuje napis #RRGGBB,
    • start okna - WPF wywołuje ValueChanged już przy budowaniu okna (stąd IsLoaded), Tkinter wywołuje command dopiero w pętli zdarzeń,
    • wartości suwaka - Scale w Tkinterze daje od razu liczby całkowite, Slider w WPF - liczby zmiennoprzecinkowe (trzeba IsSnapToTickEnabled i rzutowania na byte).

    Co wybrać? Jeśli najpewniej czujesz się w Pythonie, Tkinter pozwala zrobić cały egzamin w jednym języku i jest na każdym stanowisku z Pythonem - sprawdź tylko przed egzaminem, czy w PyCharm na stanowisku import tkinter działa. WPF daje projektant okna i plik .exe, ale wymaga znajomości C# i XAML. Punkty za aplikację desktopową (R.3) są w obu technologiach te same.

    Okno aplikacji bez zmian - taki jak po kroku 29.

  32. Etap 6: Oddanie pracy

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

    Krok 32: Nagranie płyty

    Kryteria:

    R.4.9 Na płycie wszystkie wykonane projekty są spakowane oraz umieszczone pliki źródłowe i pliki wykonywalne (jeśli istnieją) na zewnątrz archiwów

    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, konsolowa. W folderze desktopowa: spakowany cały projekt aplikacji desktopowej, pliki ze źródłami interfejsu i logiki, opcjonalnie plik wykonywalny. W folderze dokumentacja: pliki ze zrzutami oraz plik egzamin. W folderze konsolowa: spakowany cały projekt aplikacji konsolowej, pliki źródłowe, opcjonalnie plik wykonywalny.

    Sprawdzasz zawartość przed nagraniem:

    • desktopowa: desktopowa.zip, main.py,
    • dokumentacja: konsola1.png, konsola2.png, desktop1.png - desktop4.png, egzamin,
    • konsolowa: konsola.zip (z dokumentacją funkcji), main.py.

    Oba pliki nazywają się main.py, ale leżą w różnych folderach, więc się nie nadpiszą. Projekty spakowane, źródła obok archiwów (R.4.9). Nagrywasz, sprawdzasz odczyt płyty, opisujesz ją numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie rezultaty.

    Okno aplikacji bez zmian - taki jak po kroku 29.

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) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.