Python - zajęcia 9

Python - zajęcia 9
Photo by David Clode / Unsplash

1) GUI i CLI

Graficzny interfejs np. gdy coś wybieramy z menu etc. Umożliwia nam korzystanie z urządzeń przy pomocy ikon, przycisków, pasków i innych graficznych elementów. Samodzielne takich komponentów zajmuje dużo czasu, więc warto korzystać z gotowców.

CLI - (Command lines interface) komunikowanie się przez pisemny interface. Minusem jest to, że nie podpowiada użytkownikowi nic i trzeba znać możliwości tej metody.

Wybierając metodę bierzemy pod uwagę co chcemy osiągnąć i kto jest docelowym odbiorcą.

2) Warianty GUI - Biblioteki etc.

a) TkInter - zestaw narzędzi dostarczony z Pythonem. Można łatwo zacząć tworzenie graficzne. Minusem jest staromodny wygląd aplikacji, które za jego pomocą tworzymy. Są poprawione wersje istnieją, ale trzeba je już doinstalować.

Przykłady opcji jakie ma:

  • lista rozwijana
  • pole do zaznaczania
  • gotowe listy rozwijane
  • suwaczki
  • klasyczne guziki

Więcej info: https://wiki.python.org/moin/Tkinter

Trzeba się zarejestrować żeby dostać PDF-a z opisem komponentów: https://tkinter.com/widget-book

b) Qt (Pyside, PyQt) - jeden z najpopularniejszych frameworków GUI, dostępny w wielu językach programowania, w tym Pythonie (za pośrednictwem bibliotek PySide i PyQt). Do bardziej zaawansowanych projektów można wykorzystać narzędzie Qt Designer, które pozwala wizualnie tworzyć interfejsy graficzne dla aplikacji. W porównaniu do Tkintera, Qt jest bardziej zaawansowane i nowoczesne, choć trudniejsze w obsłudze. Oferuje szeroki zakres funkcji oraz dedykowane narzędzie do budowy interfejsów.

c) GTK (PyGObject) - GTK to biblioteka używana m.in. przez środowisko graficzne GNOME, jedno z najpopularniejszych na systemach Linux. Umożliwia tworzenie aplikacji o estetycznym wyglądzie, choć integracja z innymi środowiskami graficznymi bywa mniej płynna. Do projektowania interfejsów GTK można korzystać z nieoficjalnych narzędzi, takich jak Cambalache.

d) Kivy - Framework wykorzystywany m.in. przy bardziej nietypowych interfejsach np. na urządzenia mobilne.

e) DearPyGUI - Zapewnia wsparcie wyświetlania z wykorzystaniem GPU, dzięki czemu w założeniu interakcja z aplikacją powinna być bardziej responsywna

f) 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.

3) Tkinter

Żeby wykorzystać tkinter w pythonie konieczne jest zaimportowanie go ("import tkinter").

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 (bo tworzymy apke okienkową)

okno.mainloop()
#wystartowanie okna

4) Label

Etykietka, czyli tekst (lub obrazek) wyświetlany w oknie. Mamy tu rodzica komponentu (miejsce gdzie chcemy wrzucić element np. okno) i innego parametru (np. tekstu). Robimy to w dwóch etapach - najpierw najpierw deklarujemy komponent, a potem informujemy jak ten komponent umieścić:

etykieta = tk.Label(rodzic_komponentu, inne_parametry)

Teraz odniesienie do naszego przykładu:

import tkinter as tk

okno = tk.Tk()
okno.title("Tytuł okna")

#Deklaracja komponentu
etykieta = tk.Label(okno, text="jakis tekst")

#Metoda rozmieszczenia
etykieta.pack()

okno.mainloop()

5) Zmiana rozdzielczości okna

okno.geometry("500x600")

6) Button

Przycisk wywołujący jakąś akcję.

przycisk = tk.Button(text="jakiś napis", command=nazwa_funkcji)
przycisk.pack()

UWAGA! Po nazwie funkcji nie ma nawiasów okrągłych. Dlaczego? Bo tu pokazujemy przyciskowi lokalizacje dla tego co robi, a nie uruchamiamy funkcje. To przycisk ją uruchamia.

import tkinter as tk

okno = tk.Tk()
okno.title("Tytuł okna")
okno.geometry("500x600")

etykieta = tk.Label(okno, text="jakis tekst")
etykieta.pack()

przycisk = tk.Button(okno, text="Wciśnij mnie")
przycisk.pack()

okno.mainloop()

Na tym etapie przycisk się wyświetla ale jeszcze nic nie robi (nic nie podpięliśmy).

7) Input

Komponent umożliwiający wpisanie wartości w pole. Żeby pobrać dane z tego pola używamy metody .get().

wprowadz = tk.Entry(okno, width=80)
wprowadz.pack()

8) Frame

Ramka, która umożliwia nam grupowanie komponentów.

import tkinter as tk

okno = tk.Tk()
okno.title("Zajęcia 9")
okno.geometry("500x600")

ramka1 = tk.Frame(okno)
etykieta = tk.Label(ramka1, text="jakis tekst")
etykieta.pack()

przycisk = tk.Button(ramka1, text="wciśnij mnie")
przycisk.pack()

wprowadz = tk.Entry(ramka1, width=30)
wprowadz.pack()

ramka1.pack()

ramka2 = tk.Frame(okno)
nowa_etykieta = tk.Label(ramka2, text="Kolejna etykieta")
nowa_etykieta.pack()

ramka2.pack()

okno.mainloop()

Frame umożliwia nam stosowanie różnych metod rozmieszczania elementów w obrębie jednego okna.

9) Rozmieszczanie

Można rozmieszczać metodą .pack() ale też .grid(). Natomiast nie można mieszać w obrębie grupy tych metod.

etykieta.pack()
etykieta.grid(row=0, column=0)

Tutaj row i column mówi o pozycji w oknie, jeśli tego nie damy też zadziała. Może być też np. side="left".

Jeśli np. 2 ramki (ramka 1 i ramka 2) maja jednego rodzica (okno) to powinny być użyte do nich metody takie same (tutaj pack()). Ale już to co jest pod nimi np. buttony etc. może mieć metodę grid (ramka 2 tak ma), trzeba jednak stosować ją konsekwentnie.

import tkinter as tk

okno = tk.Tk()
okno.title("Zajęcia 9")
okno.geometry("500x600")

ramka1 = tk.Frame(okno)
etykieta = tk.Label(ramka1, text="jakis tekst")
etykieta.pack()

przycisk = tk.Button(ramka1, text="wcisnij mnie")
przycisk.pack()

wprowadz = tk.Entry(ramka1, width=30)
wprowadz.pack()

ramka1.pack()

ramka2 = tk.Frame(okno, pady=20)
nowa_etykieta = tk.Label(ramka2, text="Kolejna etykieta")
nowa_etykieta.grid(row=0, column=0)

ramka2.pack()

okno.mainloop()

10) Pack - szczegóły

Rozmieszcza komponenty półautomatycznie w ramach rodzica zgodnie z przekazanymi parametrami. Mogą one być umieszczone poziomo lub pionowo zgodnie z wartością parametru side.

Parametry:

  • side - określa położenie elementu (top, bottom, left, right).
  • fill - określa, czy element ma być rozciągnięty w daną stronę (x, y, both).
  • padx, pady - odstępy na zewnątrz komponentu.
  • ipadx, ipady - odstępy wewnątrz komponentu.

Żeby użyć parametru piszemy np. przycisk.pack(fill="both") wtedy rozciąga w obie strony na maxa.

11) Grid

Elementy rozmieszczane są na siatce wierszy i kolumn (jak w komórkach arkusza kalkulacyjnego). W przypadku "rozciągnięcia" elementu na kilka komórek trzeba:

  • ustawić colspan / rowspan
  • ustawić kierunek wypełnienia (n, s, w, e, we, ns)

Więcej szczegółów: https://www.pythontutorial.net/tkinter/tkinter-grid/

ramka1 = tk.Frame(okno)

przycisk1 = tk.Button(okno, text="wcisnij1")
przycisk1.grid(row=0, column=0)

przycisk2 = tk.Button(okno, text="wcisnij2")
przycisk2.grid(row=0, column=1)

przycisk3 = tk.Button(okno, text="wcisnij3")
przycisk3.grid(row=0, column=2)

przycisk5 = tk.Button(okno, text="wcisnij5")
przycisk5.grid(row=1, column=0)

przycisk6 = tk.Button(okno, text="wcisnij6")
przycisk6.grid(row=1, column=0, columnspan=2, sticky="we" )

przycisk7 = tk.Button(okno, text="wcisnij7")
przycisk7.grid(row=1, column=2)

Wynik:

Rozmieszczenie przy pomocy pętli:

import tkinter as tk

okno = tk.Tk()
okno.title("Zajęcia 9")
okno.geometry("500x600")

i = 0

for j in range(6):
    for k in range(6):
        i += 1
        tk.Button(okno, text=str(i)).grid(row=j, column=k)

okno.mainloop()

Wynik:

12) Definiowanie własnych funkcji

Nazwa funkcji to powinien być czasownik. Potem nadajemy nazwę (wymyślamy nazwę) i parametry spodziewane. Na koniec dwukropek. Powinniśmy dać mu znać też, co powinien robić. To będzie ciało funkcji.
Funkcja pracuje na jakichś danych, które przekazujemy jako parametr. Zazwyczaj zwraca też użytkownikowi jakąś wartość, gdy użyjemy funkcji return.

def kwadrat(x):
    wynik = x * x
    return wynik

Tu przekazujemy wartość x, tworzymy zmienną wynik , której wartość jest powiązana z x (np. tutaj to X kwadrat).

import tkinter as tk

def powitaj():
    powitanie = f"Witaj {pole_imie.get()}"
    etykieta_powitanie.configure(text=powitanie)

okno = tk.Tk()
okno.title("Zajęcia 9")
okno.geometry("500x600")

etykieta_wprowadz = tk.Label(okno, text="Wprowadź imię:")
etykieta_wprowadz.pack()

pole_imie = tk.Entry(okno, width=30)
pole_imie.pack()

przycisk_powitaj = tk.Button(
    okno,
    text="Powitaj",
    command=powitaj,
)
przycisk_powitaj.pack()

etykieta_powitanie = tk.Label(okno, text="")
etykieta_powitanie.pack()

okno.mainloop()

Wynik:

13) Aplikacja do generowania QR code

Potrzebujemy biblioteki do QR code i pillow (import PIL) do obsługi obrazków.

Musimy zainstalować te biblioteki w terminalu - pip install qrcode i pip install pillow. Dodatkowo wpisujemy pip install "qrcode[pil]". Następnie musimy zaimportować te biblioteki.

import tkinter as tk
import qrcode
from PIL import ImageTk

def wygeneruj_qrkod():
    global obrazek
    dane_do_qr = tekst_do_qr.get()
    qrkod = qrcode.make(dane_do_qr)
    obrazek = ImageTk.PhotoImage(qrkod)
    etykieta_qrkod.configure(image=obrazek)

okno = tk.Tk()
okno.title("Generuj QR-kod")
okno.geometry("500x600")

etykieta_wprowadz = tk.Label(okno, text="Wprowadź tekst (np. linka):")
etykieta_wprowadz.pack()

tekst_do_qr = tk.Entry(okno, width=30)
tekst_do_qr.pack()

przycisk_generuj_qr = tk.Button(
    okno,
    text="Generuj QR",
    command=wygeneruj_qrkod,
)
przycisk_generuj_qr.pack()

etykieta_qrkod = tk.Label(okno, text="")
etykieta_qrkod.pack()

okno.mainloop()

Tu nie ma duzych zmian. Tworzymy okno w ktorym bedzie przycisk, nad przyciskiem znajduje sie etykieta, z prosba "Wprowadz tekst". Mamy tu tez kod odpowiedzilany za wyswietlenie tego qr codu.

To co jest nowe to zdefiniowana wyzej funkcja wygeneruj_qrkod :

    • Pobiera tekst od użytkownika z pola tekstowego (tekst_do_qr).
    • Tworzy kod QR za pomocą biblioteki qrcode. Używa do tego funkcji qrcode.make .
    • Konwertuje kod QR na obrazek w formacie zgodnym z Tkinter za pomocą ImageTk.PhotoImage.
    • Ustawia etykietę (etykieta_qrkod), aby wyświetlała wygenerowany kod QR.

14) Custom TKInter

pip install customtkinter

15) Przerabiamy pod custom TKInter

Trzeba zmienic tk na ctk wszedzie.

import tkinter as tk
import customtkinter as ctk

import qrcode
from PIL import ImageTk

def wygeneruj_qrkod():
    global obrazek
    dane_do_qr = tekst_do_qr.get()
    qrkod = qrcode.make(dane_do_qr)
    obrazek = ImageTk.PhotoImage(qrkod)
    etykieta_qrkod.configure(image=obrazek)

okno = ctk.CTk()
okno.title("Generuj QR-kod")
okno.geometry("500x600")

etykieta_wprowadz = ctk.Label(okno, text="Wprowadź tekst (np. linka):")
etykieta_wprowadz.pack()

tekst_do_qr = ctk.CTkEntry(okno, width=30)
tekst_do_qr.pack()

przycisk_generuj_qr = ctk.CTkButton(
    okno,
    text="Generuj QR",
    command=wygeneruj_qrkod,
)
przycisk_generuj_qr.pack()

etykieta_qrkod = ctk.CTkLabel(okno, text="")
etykieta_qrkod.pack()

okno.mainloop()