Grafikus C# – Windows Forms tanfolyam › 4.3 lecke Windows Forms · 4.3 · önálló gyakorlás A harmadik önálló feladatban az ablakos programot és az adatbázist összekapcsolod. Egy bejelentkező és regisztrációs alkalmazást építesz SQLite adatbázissal, biztonságos, paraméterezett lekérdezésekkel és hibakezeléssel. A leírást, a pontozást és támpontokat kapsz, kész megoldást nem.Önálló feladat III.: Belépés és regisztráció SQLite-tal

A feladat végére
- önállóan összekötöd az ablakos programot és az SQLite adatbázist;
- külön
DBosztályba teszed az adatbázis-műveleteket; - paraméterezett lekérdezéssel építed fel a bejelentkezést és a regisztrációt;
- kezeled a hibás bevitelt, az azonos nevű felhasználót, a hiányzó fájlt és táblát;
- a listában nem mutatod meg a jelszót;
- tesztlistával és önértékeléssel ellenőrzöd a munkádat.
Mielőtt elkezded
Ehhez a feladathoz a 3. fejezet leckéire támaszkodsz. A feladat közben használhatod a leckéket és a jegyzeteidet, de a programot önállóan állítsd össze.
A feladat leírása
Készíts egy Felhasználókezelő nevű Windows Forms alkalmazást SQLite adatbázissal:
- Az adatbázis neve
belepes.db, a tábla nevebelepesi_adatok, oszlopai:id(egész szám, elsődleges kulcs, automatikus),felhnev(szöveg, kötelező, egyedi) ésjelszo(szöveg, kötelező). - Az ablak bal oldalán a bejelentkezés: felhasználónév és jelszó mező (a jelszó rejtve), Belépés gomb, hibajelzés.
- Az ablak jobb oldalán a regisztráció: felhasználónév, jelszó és a jelszó megerősítése, Regisztráció gomb.
- Alul egy
DataGridViewa regisztrált felhasználók nevét listázza (a jelszót nem). - Minden SQL parancs paraméterezett, és az adatbázis-hívások hibakezeltek.
Mit tegyél ide: egy példa tervrajz vagy mintaablak: bal oldalt a Belépés csoport, jobb oldalt a Regisztráció csoport, alul a felhasználók táblázata és az üzenet-felirat.Javasolt fájlnév: winforms-4-3-minta.webp · Alt szöveg: A Felhasználókezelő alkalmazás mintaablaka belépéssel, regisztrációval és listával
Követelmények és pontozás
| Rész | Követelmény | Pont |
|---|---|---|
| Belépés (40) | A felhasználónév és a jelszó ellenőrzése paraméterezett SELECT COUNT(*) lekérdezéssel; sikeres és sikertelen belépésre eltérő üzenet. | 20 |
| Üres mezők kezelése a lekérdezés előtt; a jelszó mező rejtett. | 10 | |
A hibaüzenet nem árulja el, hogy a név vagy a jelszó hibás-e. Az adatbázis-hívás külön DB osztályban van. | 10 | |
| Regisztráció (40) | Új felhasználó felvétele paraméterezett INSERT utasítással (ExecuteNonQuery). | 15 |
| Azonos nevű felhasználó megakadályozása érthető üzenettel; a jelszó legalább 6 karakter, és a két jelszómező egyezik. | 15 | |
A felhasználók listája a DataGridView-ban, jelszó nélkül; sikeres regisztráció után frissül. | 10 | |
| Hibakezelés (20) | Hiányzó adatbázisfájl, nem létező tábla és zárolt adatbázis esetén látható, érthető hibaüzenet (try–catch), a program nem omlik össze. | 12 |
A .db fájl a program mellé másolódik (Copy if newer), és using blokkok zárják a kapcsolatot. | 8 |
Összesen: 100 pont. A belépés 40, a regisztráció 40, a hibakezelés 20 pontot ér.
Csak gyakorló adatot használj!
A feladat tesztadatbázisában kitalált neveket és jelszavakat tárolj. Soha ne írj bele igazi jelszót. A nyílt szövegű jelszótárolás a tanulás eszköze: valódi alkalmazásban a jelszót nem tárolják nyíltan.
Időbeosztás (120 perc)
| Perc | Mit csinálj? |
|---|---|
| 0–15 | A DB Browserben hozd létre a belepes.db adatbázist és a táblát; vegyél fel két próbafelhasználót; írd ki a változtatásokat (Ctrl+S). |
| 15–30 | Új Windows Forms projekt, a System.Data.SQLite NuGet csomag telepítése, a belepes.db bemásolása (Copy if newer). |
| 30–45 | A DB osztály a kapcsolattal, és egy kapcsolat-teszt (a sorok számának lekérdezése). |
| 45–65 | Az ablak felépítése; a felhasználónév és a jelszó beolvasása, a paraméterezett COUNT(*) lekérdezés a DB osztályban. |
| 65–85 | A belépés sikeres és hibás ága; az üres mezők kezelése. |
| 85–105 | Regisztráció: ellenőrzések, INSERT, azonos nevek, a lista frissítése. |
| 105–120 | A tesztlista végigpróbálása, a hibás esetek (hiányzó fájl, hiányzó tábla, zárolt adatbázis) kipróbálása. |
Támpontok (kész megoldás nélkül)
Mit hova tegyél?
| Feladat | Hol és mivel? | Lecke |
|---|---|---|
| Adatbázis és tábla | DB Browser, CREATE TABLE, PRIMARY KEY, UNIQUE, Write Changes | 3.1 |
| Kapcsolat | DB.UjKapcsolat(), using, File.Exists | 3.2 |
| Belépés | DB.BelepesJo(nev, jelszo), @nev, @jelszo, ExecuteScalar | 3.3 |
| Regisztráció | DB.Regisztral(nev, jelszo), ExecuteNonQuery | 3.4 |
| Lista | DataTable, SQLiteDataAdapter.Fill, DataSource | 3.4 |
A felület és az adatbázis szétválasztása
Az ablak kódja csak a bevitelt ellenőrzi, és a visszaadott értéket (bool, DataTable) használja fel. Az SQL szövegek és a kapcsolat a DB osztályban legyenek. Így egy helyen javítható minden adatbázis-hiba.
A jelszó megerősítése
A két jelszómező összehasonlításához használd a != operátort (nem egyenlő). Az ellenőrzést az adatbázis-hívás előtt végezd el.
Hibák, amelyeket külön ki kell próbálnod
Nevezd át ideiglenesen a bin\Debug mappában a .db fájlt (hiányzó fájl), írj át egy tábla nevet az SQL-ben (hiányzó tábla), és hagyd nyitva a DB Browserben ki nem írt változtatással az adatbázist (zárolt adatbázis). A programnak mindhárom esetben érthető hibaüzenetet kell mutatnia.
A lista frissítése
A DataGridView nem frissül magától. A listát egy külön Frissit() metódus tölti, amelyet az ablak betöltésekor és minden sikeres regisztráció után meghívsz.
Mintamegoldás
Előbb oldd meg önállóan!
A mintamegoldás csak az ellenőrzésre való, és nem az egyetlen helyes megoldás. Előbb próbálkozz saját kóddal, és csak elakadásnál vagy a végén nyisd meg. Ha egy rész nem megy, a hozzá tartozó lecke (3.1–3.4) részletesen elmagyarázza.
Megoldás: az adatbázis létrehozása (SQL)
CREATE TABLE belepesi_adatok (
id INTEGER PRIMARY KEY AUTOINCREMENT,
felhnev TEXT NOT NULL UNIQUE,
jelszo TEXT NOT NULL
);
INSERT INTO belepesi_adatok (felhnev, jelszo) VALUES ('tanulo', 'teszt123');
INSERT INTO belepesi_adatok (felhnev, jelszo) VALUES ('kata', 'almafa');Megoldás: DB.cs (teljes kód)
using System;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Windows.Forms;
internal static class DB
{
private static readonly string AdatbazisUt = Path.Combine(Application.StartupPath, "belepes.db");
public static SQLiteConnection UjKapcsolat()
{
if (!File.Exists(AdatbazisUt))
{
throw new FileNotFoundException("Nem található az adatbázis: " + AdatbazisUt);
}
return new SQLiteConnection("Data Source=" + AdatbazisUt + ";Version=3;");
}
public static bool BelepesJo(string nev, string jelszo)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
string sql = "SELECT COUNT(*) FROM belepesi_adatok WHERE felhnev = @nev AND jelszo = @jelszo";
using (SQLiteCommand parancs = new SQLiteCommand(sql, kapcsolat))
{
parancs.Parameters.AddWithValue("@nev", nev);
parancs.Parameters.AddWithValue("@jelszo", jelszo);
return Convert.ToInt32(parancs.ExecuteScalar()) > 0;
}
}
}
public static bool Regisztral(string nev, string jelszo)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
using (SQLiteCommand ellenor = new SQLiteCommand("SELECT COUNT(*) FROM belepesi_adatok WHERE felhnev = @nev", kapcsolat))
{
ellenor.Parameters.AddWithValue("@nev", nev);
if (Convert.ToInt32(ellenor.ExecuteScalar()) > 0)
{
return false;
}
}
using (SQLiteCommand beszur = new SQLiteCommand("INSERT INTO belepesi_adatok (felhnev, jelszo) VALUES (@nev, @jelszo)", kapcsolat))
{
beszur.Parameters.AddWithValue("@nev", nev);
beszur.Parameters.AddWithValue("@jelszo", jelszo);
beszur.ExecuteNonQuery();
}
return true;
}
}
public static DataTable Felhasznalok()
{
DataTable tabla = new DataTable();
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();
using (SQLiteDataAdapter adapter = new SQLiteDataAdapter("SELECT id, felhnev FROM belepesi_adatok ORDER BY felhnev", kapcsolat))
{
adapter.Fill(tabla);
}
}
return tabla;
}
}Megoldás: Form1.cs (teljes kód)
Az ablak vezérlői: txtFelhasznalo, txtJelszo, btnBelep (belépés); txtRegNev, txtRegJelszo, txtRegJelszo2, btnRegisztral (regisztráció); dgvFelhasznalok; lblUzenet. A jelszó mezők UseSystemPasswordChar értéke True.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Felhasznalokezelo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Uzenet(string szoveg, bool hiba)
{
lblUzenet.Text = szoveg;
lblUzenet.ForeColor = hiba ? Color.Firebrick : Color.SeaGreen;
}
private void Frissit()
{
try
{
dgvFelhasznalok.DataSource = DB.Felhasznalok();
dgvFelhasznalok.Columns["id"].HeaderText = "Azonosító";
dgvFelhasznalok.Columns["felhnev"].HeaderText = "Felhasználónév";
}
catch (Exception ex)
{
MessageBox.Show("Nem sikerült betölteni a listát: " + ex.Message);
}
}
private void Form1_Load(object sender, EventArgs e)
{
Frissit();
}
private void btnBelep_Click(object sender, EventArgs e)
{
string nev = txtFelhasznalo.Text.Trim();
string jelszo = txtJelszo.Text;
if (nev.Length == 0 || jelszo.Length == 0)
{
Uzenet("Mindkét mezőt töltsd ki!", true);
return;
}
try
{
if (DB.BelepesJo(nev, jelszo))
{
Uzenet($"Sikeres belépés, {nev}!", false);
}
else
{
Uzenet("Hibás felhasználónév vagy jelszó.", true);
}
}
catch (Exception ex)
{
MessageBox.Show("Adatbázis-hiba: " + ex.Message);
}
}
private void btnRegisztral_Click(object sender, EventArgs e)
{
string nev = txtRegNev.Text.Trim();
string jelszo = txtRegJelszo.Text;
if (nev.Length == 0)
{
Uzenet("Add meg a felhasználónevet!", true);
return;
}
if (jelszo.Length < 6)
{
Uzenet("A jelszó legalább 6 karakter legyen!", true);
return;
}
if (jelszo != txtRegJelszo2.Text)
{
Uzenet("A két jelszó nem egyezik!", true);
return;
}
try
{
if (DB.Regisztral(nev, jelszo))
{
Uzenet("Sikeres regisztráció.", false);
txtRegNev.Clear();
txtRegJelszo.Clear();
txtRegJelszo2.Clear();
Frissit();
}
else
{
Uzenet("Ez a felhasználónév már foglalt.", true);
}
}
catch (Exception ex)
{
MessageBox.Show("Adatbázis-hiba: " + ex.Message);
}
}
}
}Megoldás: miért így épül fel?
Minden SQL parancs paraméterezett, ezért az aposztrófos nevek is biztonságosan működnek. Az adatbázis-hívások a DB osztályban vannak, az ablak csak a visszaadott értékekkel dolgozik. A Regisztral előbb ellenőrzi a nevet, a UNIQUE beállítás pedig védőháló. A listához csak az id és a felhnev oszlopot kérjük le. Az üres, rövid és eltérő jelszavakat az ablak a return utasítással még az adatbázis-hívás előtt kiszűri, a váratlan hibákat pedig a try–catch kapja el.
Tesztlista
| # | Teszt | Várt eredmény |
|---|---|---|
| 1 | Belépés helyes adatokkal | Sikeres belépés üzenet. |
| 2 | Belépés rossz jelszóval | Hibás adat üzenet, amely nem árulja el, melyik rossz. |
| 3 | Belépés ismeretlen névvel | Ugyanaz a hibaüzenet, mint a rossz jelszónál. |
| 4 | Belépés üres mezőkkel | Figyelmeztetés, nincs adatbázis-hívás. |
| 5 | A jelszó mező tartalma | Pontok látszanak, nem a valódi szöveg. |
| 6 | Regisztráció új névvel | Sikeres regisztráció, az új név megjelenik a listában. |
| 7 | Regisztráció ugyanazzal a névvel | Érthető üzenet, a névből egy sor marad. |
| 8 | Regisztráció rövid jelszóval | Figyelmeztetés a hosszról. |
| 9 | Regisztráció eltérő jelszavakkal | Figyelmeztetés az egyezésről. |
| 10 | Aposztrófos név (például O'Hara) | Hiba nélkül működik. |
| 11 | A lista oszlopai | Nincs benne jelszó. |
| 12 | Hiányzó .db fájl | Érthető hibaüzenet, nem omlik össze. |
| 13 | Nem létező tábla az SQL-ben | Érthető hibaüzenet. |
| 14 | A program újraindítása | A korábban regisztrált felhasználók megvannak. |
Gyakori hibák és önértékelés
Ezeken szoktak elcsúszni
Gondold végig, nálad előfordul-e valamelyik.
1. Összefűzött SQL
string sql = "SELECT COUNT(*) FROM belepesi_adatok WHERE felhnev = '" + nev + "'";Hiba és javítás
Biztonsági hiba (SQL-befecskendezés, 3.3 lecke), és az aposztrófos név hibát okoz. Használj paramétert: WHERE felhnev = @nev, és Parameters.AddWithValue.
2. Új üres adatbázis
A program A program egy másik, üres no such table hibát jelez, pedig a DB Browserben megvan a tábla.Ok és javítás
.db fájlt nyitott meg. Ellenőrizd a Copy to Output Directory beállítást és a kapcsolati szöveg útvonalát (Application.StartupPath). A File.Exists ellenőrzés a hiányzó fájlt előre jelzi.
3. Kimaradt az Open()
using (SQLiteConnection kapcsolat = DB.UjKapcsolat())
{
// kapcsolat.Open(); hiányzik
int db = Convert.ToInt32(parancs.ExecuteScalar());
}Hiba és javítás
Futás közbeni hiba (InvalidOperationException): a kapcsolat nincs megnyitva. A parancs végrehajtása előtt hívd a kapcsolat.Open(); metódust.
4. A jelszó is a listában
A táblázatban látszik a jelszó oszlop is. A lekérdezés Ok és javítás
SELECT * alakú. A listához csak a szükséges oszlopokat kérd: SELECT id, felhnev FROM belepesi_adatok.
5. database is locked
A program zárolt adatbázis miatt hibát jelez. A DB Browserben ki nem írt változtatás van, vagy a C# programban nincs lezárva egy kapcsolat. Írd ki a változtatásokat (Ok és javítás
Ctrl+S), és használd mindenhol a using blokkot.
6. A lista nem frissül
A regisztráció sikeres, de a táblázat a régi állapotot mutatja. A sikeres regisztráció után nem hívod meg a Ok és javítás
Frissit() metódust, amely újra lekérdezi az adatokat.
Az értékeléshez ellenőrizd az alábbi szempontokat is:
DB osztályban van, az ablak csak a visszaadott értékeket használja.Bővítési ötletek, ha kész vagy
Ha maradt időd, fejleszd tovább a programot:
- Próbálkozások korlátozása: három sikertelen belépés után tiltsd le a gombot (3.3 lecke feladata).
- Keresés a listában: egy mezővel szűrd a felhasználókat névrészletre (3.4 lecke feladata).
- Törlés: egy kijelölt felhasználó törlése a
DELETEutasítással, megerősítő kérdéssel. - Jelszómódosítás: az
UPDATEutasítással, a régi jelszó ellenőrzése után. - Jelszó hash-elése: tanulmányozd, hogyan tárolják a jelszavakat valódi programokban.
Mit tudsz már?
- Önállóan összekötöd az ablakos programot és az SQLite adatbázist.
- Paraméterezett lekérdezéssel építed fel a belépést és a regisztrációt.
- Kezeled a hibás bevitelt és az adatbázis-hibákat.
- A listában nem mutatod a jelszót.
- Tesztlistával értékeled a saját munkádat.
Következő feladat: számológép
A három önálló feladaton túl vagy. A következő önálló feladatban számológépet építesz grafikus felülettel: közös eseménykezelők, állapotkezelés és hibakezelés.



