InfoBook.ro ← Harta anului
Modul 11 · Interfețe grafice (Tkinter)
Modul 11 · Conținut 3.4

De la consolă la fereastră

Consola neagră a fost utilă — dar utilizatorii adevărați vor butoane, casete și ferestre. Tkinter e biblioteca standard Python pentru interfețe grafice, iar tot ce știi despre obiecte (Modulul 10!) intră azi în joc.

🎯 Obiectiv 1Construiești ferestre cu Label, Entry, Button și le așezi cu pack, grid și place.
🎯 Obiectiv 2Legi evenimente (command=), citești caseta cu .get() și tratezi erorile cu messagebox.
🎯 Obiectiv 3Duci totul într-un PROIECT propriu, evaluat pe etape — de la idee la aplicație.
1

Anatomia unei ferestre Tkinter

Fereastra (Tk) e pânza; pe ea așezi widget-uri: etichete (Label), casete (Entry), butoane (Button). Apasă pe orice widget din fereastra de mai jos!

Aplicația mea — Tk()
Scrie numele tău:
Salută-mă
ⓘ Salut
Bună, Maria!
👆 apasă pe bară, etichetă, casetă, buton sau mesaj
Legătura cu Modulul 10: Tk(), Label(...), Entry(...), Button(...) sunt toate instanțieri de clase predefinite — fereastra și widget-urile sunt OBIECTE, iar .pack() și .get() sunt metodele lor. POO în acțiune!
⚠ Atenție — fragmentele de mai sus sunt IZOLATE! Fiecare arată un singur widget. Dacă le lipești pur și simplu, primești NameError: name 'salut' is not defined, pentru că command=salut cere ca funcția să fie definită ÎNAINTE. Iată programul COMPLET, în ordinea corectă — copiază-l pe ACESTA:
1import tkinter as tk
2from tkinter import messagebox
3 
4fereastra = tk.Tk()
5fereastra.title("Aplicația mea")
6fereastra.geometry("320x230") # fereastră cu spațiu
7 
8eticheta = tk.Label(fereastra, text="Scrie numele tău:",
9 font=("Arial", 12))
10eticheta.pack(pady=(24, 6)) # spațiu sus, apoi jos
11 
12caseta = tk.Entry(fereastra, font=("Arial", 12), width=22)
13caseta.pack(pady=6, ipady=4) # ipady = casetă mai înaltă
14 
15def salut(): # definită ÎNAINTE de buton
16 nume = caseta.get() # citirea, LA CLIC
17 messagebox.showinfo("Salut", "Bună, " + nume + "!")
18 
19buton = tk.Button(fereastra, text="Salută-mă",
20 font=("Arial", 11), command=salut)
21buton.pack(pady=16, ipadx=10, ipady=4) # buton mai mare
22 
23fereastra.mainloop() # la FINAL
Ordinea care contează: întâi fereastra și widget-urile → apoi def salut() (cu .get() și messagebox ÎNĂUNTRU) → apoi butonul care o leagă → la final mainloop().
🪟 Rețeta ferestrei „aerisite" — folosește-o la TOATE proiectele:
  • fereastra.geometry("320x230") — dă ferestrei o mărime decentă (lățime × înălțime), altfel se strânge cât widget-urile;
  • .pack(pady=10, padx=20) — spațiu ÎN JURUL widget-ului (sus-jos / stânga-dreapta); pady=(24, 6) = 24 sus, 6 jos;
  • .pack(ipady=4, ipadx=8) — spațiu ÎN INTERIOR: casete și butoane mai înalte/late, mai ușor de apăsat;
  • font=("Arial", 12) și width=22 — text mai mare și casete mai lungi.

Familia de widget-uri — pe scurt

Cele patru pe care le folosești mereu — plus două pe care e bine să le cunoști, exact cum le enumeră programa.

1tk.Label(...) # text static
2tk.Entry(...) # o linie de introdus
3tk.Button(...) # buton apăsabil
4tk.Frame(...) # cutie care grupează
5tk.Text(...) # casetă pe MAI MULTE linii
6tk.Canvas(...) # pânză de DESEN
7 
8# messagebox = pop-up, nu widget
Când le folosești: Text = un „Entry mare", pentru paragrafe (o notiță, un mesaj lung) — citit cu .get("1.0", "end"). Canvas = suprafață pe care DESENEZI cu cod: linii, dreptunghiuri, cercuri — perfect pentru un grafic, o hartă sau un mic joc. Le vei folosi în proiecte mai ambițioase.
2

Așezarea widget-urilor: pack · grid · place

Un widget creat nu apare până nu-l AȘEZI. Sunt trei manageri de aranjare — aceleași 3 widget-uri, trei feluri de a le pune. Comută:

Layout — Tk()
Regula practică: pack pentru liste simple, unul sub altul (90% din cazuri); grid pentru formulare aliniate pe rânduri și coloane (etichetă lângă casetă); place doar când vrei poziții fixe exacte. Nu amesteca pack și grid în aceeași fereastră — Tkinter se blochează!

place în detaliu: sistemul de coordonate și mărimea ferestrei

Fereastra e o grilă de pixeli — mici pătrățele luminoase. Colțul din stânga-sus e (0, 0). De acolo, x crește spre DREAPTA, iar y crește în JOS (atenție: y merge în jos, nu ca la matematică!). widget.place(x=150, y=80) pune widget-ul cu colțul lui la 150 pixeli dreapta și 80 pixeli jos.

(0, 0) x → y ↓ buton place(x=150, y=80)
Mărimea ferestrei: implicit, fereastra se strânge cât să încapă widget-urile. O faci mai mare cu fereastra.geometry("400x300") — 400 pixeli LĂȚIME × 300 ÎNĂLȚIME. Poți adăuga și poziția pe ecran: "400x300+200+100" (400×300, la 200px dreapta și 100px jos de colțul ecranului).

🎮 trage cursoarele — butonul se mută în fereastra de 240×150:

geometry("240x150") — Tk()
Salut
x = 60
y = 40
›buton.place(x=60, y=40)
Program complet cu place și fereastră mărită:
1import tkinter as tk
2fereastra = tk.Tk()
3fereastra.geometry("300x200") # 300 lat × 200 înalt
4buton = tk.Button(fereastra, text="aici!")
5buton.place(x=120, y=90) # fix la (120, 90)
6fereastra.mainloop()
3

Evenimente, messagebox și lambda

O interfață grafică nu rulează de sus în jos — așteaptă evenimente (clic!) și reacționează cu funcția legată prin command=. Testează live, apoi învață și lambda, de care ai nevoie la calculator:

📋 program COMPLET și AERISIT — copiază-l pe tot, rulează direct:

1import tkinter as tk
2from tkinter import messagebox
3 
4fereastra = tk.Tk()
5fereastra.title("Salut")
6fereastra.geometry("300x180")
7 
8caseta = tk.Entry(fereastra, font=("Arial", 12), width=20)
9caseta.pack(pady=(28, 10), ipady=4)
10 
11def salut(): # funcția-reacție
12 messagebox.showinfo("Salut", "Bună, " + caseta.get())
13 
14buton = tk.Button(fereastra, text="Salută-mă",
15 font=("Arial", 11), command=salut) # FĂRĂ ()
16buton.pack(pady=10, ipadx=10, ipady=4)
17 
18fereastra.mainloop()
Capcana command: scrii command=salut (FĂRĂ paranteze!). Cu salut() funcția ar rula imediat, nu la clic. Și nu uita import tkinter as tk pe prima linie — altfel: NameError: name 'tk' is not defined.

▶ demo funcțional — aplicația chiar merge:

Salut — Tk()
Scrie numele tău:
Salută-mă
ⓘ Salut
OK
scrie ceva și apasă butonul — exact ca aplicația reală 👆

λ lambda — funcția scrisă pe un singur rând

Ai văzut mai sus că command= cere numele unei funcții, fără paranteze. Dar ce faci când vrei ca butonul să cheme funcția cu un argument? Aici intră în scenă lambda — o vei folosi imediat, la calculatorul din secțiunea următoare.

1. Ce este, de fapt

O funcție obișnuită are nume, def și return. Un lambda e aceeași idee, comprimată pe un rând: lambda parametri: rezultat. Nu are nume și nu scrii return — rezultatul e chiar expresia de după două puncte.

funcția clasică

1def dublu(x):
2 return x * 2
3 
4print(dublu(5)) # 10

exact același lucru, cu lambda

1dublu = lambda x: x * 2
2 
3 
4print(dublu(5)) # 10
Când folosești fiecare: pentru o funcție adevărată, cu mai multe instrucțiuni, folosești def — e mai clar. lambda e pentru funcții mărunte, de o singură linie, de care ai nevoie pe loc și cărora nu merită să le dai nume.

2. De ce ai nevoie de ea la butoane

Vrei un buton care adună 5. Prima idee ar fi command=aduna(5) — dar e greșită: cu paranteze, Python execută funcția imediat, la pornirea programului, și îi dă lui command rezultatul (un număr), nu o funcție. Butonul rămâne mort.

✘ greșit

1tk.Button(f, text="+5",
2 command=aduna(5))
3# ruleaza ACUM, nu la clic

✔ corect, cu lambda

1tk.Button(f, text="+5",
2 command=lambda: aduna(5))
3# o functie noua, fara argumente,
4# care cheama aduna(5) la CLIC
Ideea-cheie: lambda: aduna(5) nu adună nimic acum — construiește o funcție nouă, fără parametri, care abia când e apelată îl cheamă pe aduna cu 5. Exact ce-i trebuie lui command.

3. Capcana din buclă — de ce scriem lambda o=s:

Când creezi butoane într-o buclă (cum vom face la calculator, pentru + − × ÷), apare o surpriză: toate lambda-urile se uită la aceeași variabilă a buclei, iar la final ea are ultima valoare.

✘ fără o=s — toate butoanele fac același lucru

1for s in ["+", "-", "*"]:
2 f.append(lambda: s)
3 
4# rezultat: ['*', '*', '*']

✔ cu o=s — fiecare își îngheață valoarea

1for s in ["+", "-", "*"]:
2 f.append(lambda o=s: o)
3 
4# rezultat: ['+', '-', '*']
Explicația: o=s înseamnă „parametrul o are valoarea implicită s", iar valoarea implicită se calculează în momentul creării lambda-ului. Așa, fiecare buton își păstrează propriul semn. Fără o=s, toate ar citi variabila abia la clic — când bucla s-a terminat demult și s e ultimul element.
4

Calculatorul grafic — versiunea „ca lumea"

Codul de manual e scurt, dar dacă îl rulezi cu litere sau împarți la 0… crapă. Iată versiunea REZISTENTĂ: cu etichete, validare și mesaje de eroare. Click pe orice linie pentru explicație.

👆 apasă pe orice linie din cod pentru explicație

▶ aplicația, funcțională — încearcă și cu litere sau ÷ 0:

Calculator — Tk()
Primul număr:
Al doilea număr:
+
−
×
÷
Rezultat:
—
⛔ Eroare
OK
Ce s-a îmbunătățit față de codul de manual: etichete deasupra fiecărei casete, butoanele grupate cu un Frame, rezultatul arată toată expresia (12 + 4 = 16), iar erorile (text în loc de număr, împărțire la 0) sunt prinse cu try/except și messagebox.showerror — aplicația nu mai crapă niciodată.
5

Verificare rapidă

Cinci întrebări despre lumea ferestrelor.

6

Fișa de sinteză

Tkinter pe scurt.

Fereastra: fereastra = tk.Tk() — un obiect! La final, fereastra.mainloop() pornește bucla de evenimente.
Widget-uri: Label (text), Entry (o linie), Button (buton), Frame (grupează), Text (mai multe linii), Canvas (desen) — toate primesc fereastra ca părinte.
Așezarea: .pack() unul sub altul · .grid(row=, column=) pe tabel · .place(x=, y=) la coordonate fixe.
Fereastră aerisită: geometry("320x230") pentru mărime · pady/padx = spațiu în jur · ipady/ipadx = widget mai mare · font=("Arial", 12).
Evenimente: Button(..., command=functie) — FĂRĂ paranteze; funcția rulează la clic.
lambda = funcție pe un rând (lambda x: x * 2). O folosești când butonul trebuie să cheme o funcție cu argument: command=lambda: aduna(5). În buclă: lambda o=s:, ca fiecare buton să-și păstreze valoarea.
Citirea din casetă: caseta.get() dă un STRING → int(caseta.get()) pentru numere (ca la fișiere!).
messagebox.showinfo(titlu, mesaj) — pop-up simplu de informare; există și showerror, showwarning.
Exersează pe pbinfo.ro — rezolvă-le întâi pe consolă, apoi îmbracă-le în interfață:
#1258 · ușoară

scadere2

Diferența a două numere — primul buton al calculatorului tău.

Rezolvă pe pbinfo.ro →
#105 · ușoară

max2

Maximul a două numere — pentru un buton „Cine e mai mare?".

Rezolvă pe pbinfo.ro →
#3978 · medie

sabc

Sume pe intervale — bun pentru mai multe casete de intrare.

Rezolvă pe pbinfo.ro →
#469 · ușoară

Interval2

x aparține intervalului [a,b]? — perfect pentru un quiz cu buton de verificare.

Rezolvă pe pbinfo.ro →
7

🚀 Proiect final — aplicația ta cu interfață

Aici pui totul în practică. Alege UNA din cele trei teme (sau propune-ți una) și construiește o aplicație Tkinter completă, pe etape.

● ușor

🎱 Magic 8-Ball / zaruri

  • buton „Întreabă" → random.choice dintr-o listă de răspunsuri
  • afișezi răspunsul într-un Label mare
  • variantă: „Aruncă zarul" → număr 1–6
  • pui o întrebare, primești un verdict amuzant
● ușor

🔐 Generator de parole

  • o casetă pentru lungime + buton „Generează"
  • random alege litere, cifre, simboluri
  • parola apare într-un Label
  • bonus: buton „Copiază" (clipboard_append)
●● mediu

❓ Quiz cu scor

  • întrebări despre muzică, filme, jocuri (o listă)
  • buton „Verifică" → messagebox „Corect!/Greșit!"
  • ții scorul într-o variabilă și îl afișezi
  • buton „Următoarea" trece la altă întrebare
●● mediu

✊✋✌ Piatră-foarfece-hârtie

  • 3 butoane; calculatorul alege aleator
  • compari și afișezi „Ai câștigat/pierdut/egal"
  • ții scorul: tu vs calculator
  • bonus: primul la 5 puncte câștigă
●●● provocare

⚡ Joc de reacție

  • butonul devine verde după un timp ALEATOR
  • apeși cât mai repede → măsori timpul de reacție
  • folosești fereastra.after(ms, funcție) și time
  • ții cel mai bun scor (record personal)
●●● provocare

🎨 Tablă de desen (Canvas)

  • desenezi cu mouse-ul pe un Canvas
  • butoane de culoare + „Șterge tot"
  • legi evenimentul de mișcare a mouse-ului (bind)
  • bonus: salvezi desenul / alegi grosimea liniei
Alte idei rapide: 🐍 „Ghicește numărul" (programul alege 1–100, tu ghicești, îți spune mai mare/mai mic) · 🍕 calculator de bacșiș/împărțit nota · ⏱ cronometru sau numărătoare inversă · 🌡 convertor de unități (°C↔°F, km↔mile) · 📊 sondaj cu butoane care numără voturile. Alege ce te distrează — dacă îți place tema, o duci până la capăt.

Etapele proiectului — livrează pe rând

  1. Schița pe hârtie. Desenează fereastra: ce widget-uri, unde. Decide layout-ul (pack sau grid).
  2. Interfața „moartă". Creează fereastra și toate widget-urile, așezate corect — încă fără să facă nimic. Rulează și verifică aspectul.
  3. Un buton viu. Scrie prima funcție-reacție și l-o legi prin command=. Testează-l singur.
  4. Restul logicii. Completează toate reacțiile: citire cu .get(), calcul, afișare cu .config() sau messagebox.
  5. Rezistența la erori. Adaugă try/except și mesaje de eroare — aplicația nu trebuie să crape la date greșite.
  6. Finisaje. Titlu de fereastră, spațiere (padx/pady), texte clare. Testează cu un coleg care n-a mai văzut-o.
Livrabile: fișierul .py care rulează, plus 2–3 capturi de ecran ale aplicației în funcțiune. Cod curat: funcții cu nume clare, fără repetiții (folosește bucla pentru butoane, ca la calculator).

Barem de evaluare — 100 de puncte

CriteriuPunctaj
Fereastra pornește și afișează widget-urile corect (layout curat)25 p
Butoanele reacționează — evenimentele funcționează25 p
Citirea din casete și logica dau rezultate corecte25 p
Tratarea erorilor (date greșite, ÷ 0) cu messagebox15 p
Cod curat, fără repetiții + aspect îngrijit10 p
Recapitulare a tot anul: proiectul tău atinge decizii (M02), funcții (M05), fișiere (M10), obiecte (M11) și interfețe (M12). E dovada că poți construi un program REAL, de la zero.
← anteriorModul 10a · Tipul struct (C++) urmează →Modul 12 · Recapitulare finală