Lekcja 9 - GUI z TkInter (notatki)

Biblioteka json
Plik json można wczytać do pythona dzięki funkcji load. Zawartość pliku .json jest zawarta pod zmienną "dane" i jest dla pythona w pełni czytelna.
import json
with open("nazwa_json.json", "r") as kwestionariusz_plik:
dane = json.load(kwestionariusz_plik)
print(dane)
print(type(dane))
Pamiętaj, że gdy plik wyjściowy pisany jest zgodnie z tablicą utf-8. Musisz dodać po trybie: encoding="utf8"
Można też zadziałać w drugą stronę tzn. zapisać obiekt pythonowy jako json. W wariancie podstawowym należy najpierw zacząć od formuły with z open, po którym następuje nazwa naszego nowego pliku. Następnie w kolejnej linijce po wcięciu korzystamy z funkcji dump, która służy do zapisania pliku. W nawiasie po niej najpierw podajesz obiekt pythonowy (który chcemy zapisać w nowym formacie), potem format (tu: plik_json), a na końcu jest opcjonalny parametr, który służy lepszemu sformatowaniu (tu wcięcia 4 spacjowe) - inaczej json zostanie zapisany ciągiem w jednej linijce.
import json
slownik = {
"Jan": "234567890"
}
with open("nowyplik.json", "w") as plik_json:
json.dump(slownik, plik_json, indent=4)
Wariant podstawowy
Gdy chcemy zakodować obiekt według tablicy utf-8, musimy skorzystać z encoding. Wymaga to jednak dodania nowego parametru przy dump: ensure_ascii=False. Można też użyć sort_keys=True, która służy automatycznemu alfabetycznemu ułożeniu danych w pliku json.
with open("nowyplik.json", "w", encoding="utf8) as plik_json:
json.dump(slownik, plik_json, indent=4, sort_keys=True, ensure_ascii=False)
Wariant kodujący plik w utf8
Dzięki zastosowaniu wymienionych wyżej opcji nie trzeba przechowywać wszystkich danych w jednym kodzie np. pytania w kwestionariuszu można przechowywać w osobnym pliku json, który zaimportowuje się do pythona:
import json
punkty = 0
gracz = input("Podaj swoje imię: ")
print(f"Witaj {gracz}!")
with open('nowy_json.json', 'r', encoding="utf8") as ankieta_plik:
ankieta = json.load(ankieta_plik)
for zestaw in ankieta:
print(zestaw[0])
numer_odp = 0
for odpowiedzi in zestaw[1]:
print(f"{numer_odp} {odpowiedzi[0]}")
numer_odp += 1
odpowiedz_gracza = int(input("Twoja odpowiedź to: "))
while odpowiedz_gracza not in range(len(zestaw[1])):
print("Zły wybór, musisz podać liczbę.")
odpowiedz = input("Twoja odpowiedź to: ")
punkty += zestaw[1][odpowiedz_gracza][1]
print(f"Twój wynik {gracz} to {punkty}")
print("\n---Wyniki---")
print(f"{gracz} zdobył {punkty}")
GUI (ang. Graffical User Interface)
GUI czyli interfejs graficzny to sposób w jaki komunikujemy się z urządzeniami tj. poprzez ikony, przyciski i inne graficzne komponenty. Jego alternatywą jest CLI (ang. command line interface) czyli komunikowanie się poprzez wydanie konkretnego pisemnego polecenia. Oba sposoby komunikacji są przydatne wszystko zależy od tego co chcemy osiągnąć i kto jest docelowym odbiorcą.
Tworzenie tzw. frameworków jest stosunkowo skomplikowane, stąd biblioteki "gotowców", dzięki którym musimy tylko pod komponenty (tj. przyciski, ikony) wprowadzić funkcjonalność.
Tych bibliotek jest sporo:
TkInter - biblioteka zaadoptowana do Pythona, wgrywana od razu. Prosta w obsłudze, ale stworzone przy jej pomocy aplikacje nie wyglądają nowocześnie. Ponadto niektóre rzeczy są w niej niekonsekwentne.
Tkinter stworzył też przejrzystego e-booka z wypisanymi wszystkimi komponentami dostępnymi w tej bibliotece. Można go otrzymać pod linkiem (konieczna rejestracja).
Qt (PySide, PyQt) - możemy korzystać poprzez podane w nawiasach biblioteki. PySide jest biblioteką stworzoną przez twórców Qt, podczas gdy druga przez firmę zewnętrzną. Bardzo dużo aplikacji jest zrobionych w Qt np. Affinity Designer. Jest trudniejsza w obsłudze niż TkInter, ale jest bogatsza i bardziej nowoczesna. Ma program do budowania interfejsów dla własnych aplikacji!!!
GTK - dostępny przez bibliotekę PyGObject, oparty jest na open sourcowych źródłach. Ma jedną wadę, że aplikacje nie będą wyglądały tak samo w innych środowiskach niż jego.
Kivy - umożliwia zrobienie interfejsu do gry na komputer, czy telefon. Bardzo uniwersalna, ale średnio-wygodna w obsłudze.
DearPyGui - ten framework umożliwia tworzenie interfejsów, które może nie wyglądają pięknie, ale są bardzo użyteczne w przypadku danych statystycznych. Bardzo dobrze korzysta z karty graficznej, natychmiast odpowiadając na akcję.
Flet - nowa biblioteka, ale bardzo ciekawa ponieważ umożliwia używanie frameworku Flutter w Pythonie, dobra przy tworzeniu graficznych interfejsów na urządzenia mobilne.
Tkinter
By wykorzystać tkinter w pythonie konieczne jest zaimportowanie go do ("import tkinter"), stworzenie okna oraz jego wystartowanie, zgodnie ze wzorem:
import tkinter as tk
#skrócenie nazwy dzięki "as tk" ułatwia odnoszenie się do tkintera w późniejszych wersach
okno = tk.Tk()
okno.title("Tytuł okna")
#stworzenie okna
okno.mainloop()
#wystartowanie okna
Label
Label - nieinteraktywny element (czyli nie przycisk), który wyświetli się w oknie. Składa się z rodzica komponentu czyli miejsca gdzie chcemy wrzucić element (okna, przycisku itd.) oraz innego parametru (np. tekstu). Proces wrzucania komponentów jest dwuetapowy najpierw deklarujemy komponent:
etykieta = tk.Label(rodzic_komponentu, inne_parametry)
Potem informujemy gdzie umieścić ten komponent:
etykieta.pack()
Pack - metoda półautomatyczna, jeden z kilku sposobów rozmieszczania komponentów.
Button
Poprzez przycisk deklarujemy co python ma wykonać po jego naciśnięciu
przycisk = tk.Button(text="Mój przycisk", command=nazwa_funkcji)
przycisk.pack()
Możemy korzystać nie tylko z wbudowanych w pythona funkcji (tj. print), ale i tworzyć własne. Tworzy się je poprzez zdefiniowanie funkcji def, po czym deklarujemy nazwę funkcji (która zazwyczaj jest czasownikiem, pisaną małymi literami i bez spacji), a w następnej linijce po wcięciu podajemy akcję, która po niej następuje:
def nazwa_funkcji():
print("witaj")
Input
Umożliwia użytkownikowi wprowadzenie jakichś danych, dzięki entry, w nawiasie po nim zwykle następuję długość jaką ma mieć pasek do wprowadzania danych:
pole_tekstowe = tk.Entry(width=80)
pole_tekstowe.pack()
Przykład
Stwórz program do generowania kodów QR (Więcej o tym jak działają w filmie). Pamiętaj, że w tym celu należy pobrać odpowiednią bibliotekę qrcode z pypi.org (wpisz w terminal: "pip install qrcode") oraz bibliotekę do generowania obrazów (wpisz w terminal: "pip install pillow").
import tkinter as tk
import qrcode
from PIL import ImageTk
def generuj_qr():
global qkod, obrazek
dane = pole_tekstowe.get()
qrkod = qrcode.make(dane)
obrazek = ImageTk.PhotoImage(qrkod)
pic_label.configure(image=obrazek)
okno = tk.Tk()
okno.title("QR Code Maker")
#stworzenie okna
etykieta = tk.Label(okno, text="Podaj linka: ")
etykieta.pack()
pole_tekstowe = tk.Entry(width=50)
#zwykle następuję po nim długość jaką ma mieć pasek do wprowadzania.
pole_tekstowe.pack()
przycisk = tk.Button(text="OK", command=generuj_qr)
#nie daje się nawiasów () po funkcji.
przycisk.pack()
pic_label = tk.Label(okno, text="")
pic_label.pack()
okno.mainloop()
#wystartowanie okna
Ciekawostka! Za pomocą kodu qr można zapisać nie tylko linka, ale i dowolne słowo / zdanie!
Zadanie domowe
Na podstawie szablonu stwórz książkę kontaktową, uwzględnij zapisywanie książki do pliku json oraz jej wczytywanie z pliku json:
from os import system, name
import json
ksiazka_tele = {}
with open("adresowa_szablon.json", "r", encoding="utf-8") as telefony:
ksiazka_tele = json.load(telefony)
while True:
# Zapytanie o wybranie operacji
operacja = input("""
Wybierz operację do wykonania:
1 - dopisanie pozycji do książki
2 - aktualizacja pozycji książki
3 - usunięcie pozycji książki
4 - wydruk imion z książki
5 - wydruk całej książki telefonicznej
6 - koniec programu
Podaj kod operacji = """
)
if not operacja:
break
# Wykonanie wybranej operacji
if operacja == "1": #nowy kontakt
print("Dodawanie nowego kontaktu")
nowe_imie = input("Podaj nazwę kontaktu: ")
if nowe_imie in ksiazka_tele:
print("Ten kontakt już istnieje. Jeśli chcesz zaktualizować wybierz 2")
else :
kontakt = input("Wprowadź numer telefonu: ")
ksiazka_tele[nowe_imie] = kontakt
elif operacja == "2": #zmiana telefonu
print("Aktualizacja kontaktu")
nowe_imie = input("Podaj nazwę kontaktu: ")
kontakt = input("Wprowadź nowy numer telefonu: ")
ksiazka_tele[nowe_imie] = kontakt
elif operacja == "3": #usunięcie kontaktu
print("Usuwanie kontaktu")
nowe_imie = input("Kontakt do usunięcia to: ")
ksiazka_tele.pop(nowe_imie)
elif operacja == "4": #wydruk imion
print("Przechowywane kontakty")
print(ksiazka_tele.keys())
elif operacja == "5": #wydruk książki
print("Książka adresowa")
for nowe_imie, kontakt in ksiazka_tele.items():
print(f"Nazwa: {nowe_imie}")
print(f"tel/mail: {kontakt}")
print("--------------------")
elif operacja == "6":
wybor = input("Zapisać nowe dane? y/n: ")
if wybor.lower() == "y":
with open("adresowa_szablon.json", "w", encoding="utf8") as plik_json:
json.dump(ksiazka_tele, plik_json, indent=4, sort_keys=True, ensure_ascii=False)
break
else:
break
else:
print("\nPodano błędny kod operacji")
# Koniec programu
print("\nKoniec programu")
C.d. Tkinera w lekcji 10.