Programozási Kisokos
Gyakorlati példák a programozási tételek megvalósítására modern C#, PHP és JS környezetben. Válaszd ki a menüből a témakört!
Laravel PHP API Backend
0. Alapvető Terminál Parancsok (Artisan CLI)
A Laravel varázslata a beépített parancssoros eszközében, az Artisan-ban rejlik. Ezekkel a parancsokkal másodpercek alatt legenerálhatod a fájljaidat, ahelyett, hogy kézzel hoznál létre mindent.
Tipp: Miután létrehoztad a projektet, a terminálban be kell lépned a mappájába (cd projektnev), és csak utána indíthatod el a szervert!
# Új, üres Laravel projekt letöltése és telepítése
composer create-project laravel/laravel projektnev
# Beépített fejlesztői szerver indítása (Általában: localhost:8000)
php artisan serve
# KÖTELEZŐ API-hoz (Laravel 11-től kezdve):
# Alapból nincs 'api.php' fájl. Ez a parancs hozza létre!
php artisan install:api
A profik trükkje: Nem muszáj külön parancsokat beírni a Modellhez és a Controllerhez. Lásd az utolsó sort a kombinált megoldásért!
# Sima Adatbázis Modell létrehozása (Nagy kezdőbetűvel, egyes számban!)
php artisan make:model ModellNev
# Sima Controller létrehozása
php artisan make:controller ControllerNev
- Migrate: Olyan, mintha elküldenéd a tervrajzokat a MySQL-nek, hogy építse fel a táblákat. Ha nem használsz SQL export/import fájlokat, ez építi fel az adatbázisodat.
- Route:list: A legfontosabb parancs, ha valami nem működik a JS kliensed és a Laravel között. Kilistázza, hogy pontosan milyen URL-eken várja az adatokat a szervered.
# Adatbázis táblák létrehozása a Migrációs fájlok alapján
php artisan migrate
# Az összes regisztrált útvonal (URL) kilistázása a terminálba
php artisan route:list
Egy REST API felépítése Laravelben 3 fő fájl köré összpontosul: az útvonalak, az adatmodellek és a vezérlők (Controllerek) köré.
1. Útvonalak (routes/api.php)
Itt határozzuk meg, hogy a kliens (pl. a JS kódod) milyen URL-en érheti el az adatokat. Fontos: Mindenképp importálni (use) kell a Controllert a fájl tetején!
{id}vagy{p}: Ezek dinamikus paraméterek az URL-ben.[Kontrollernev::class, 'fugveny_neve']: Így kötjük össze az útvonalat a Controller megfelelő metódusával.
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
// KÖTELEZŐ: A Controller csatolása az útvonalakhoz!
use App\Http\Controllers\Kontrollernev;
// Sima GET kérés paraméter nélkül
Route::get('/utvonal', [Kontrollernev::class, 'ide jon az a nev ami alapjan meg szeretned hivni a controllerben']);
// GET kérés paraméterrel (Az {id} automatikusan átadódik a kontrollernek)
Route::get('/utvonal/{atadnikivantertek}', [Kontrollernev::class, 'controllerfugvenynev']);
2. Adatbázis Modellek
A Model az adatbázis egy konkrét tábláját reprezentálja. Ahhoz, hogy az Eloquent ORM jól működjön, pontosan be kell állítanunk pár dolgot.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class sofor extends Model
{
// 1. Csatolás a megfelelő táblához (Ha nem a pluralizált angol nevet használjuk)
protected $table = "táblanév";
// 2. Elsődleges kulcs beállítása (Ha nem simán 'id' a neve)
protected $primaryKey = "tábla elsődleges kulcsa(oszlopnév)";
// 3. KÖTELEZŐ, ha a tábládban nincs 'created_at' és 'updated_at' oszlop!
// Enélkül a Laravel hibára futna mentéskor vagy frissítéskor.
public $timestamps = false;
}
3. Controllerek és Lekérdezések
A Controller végzi el a munkát: lekéri az adatot a Modelleken keresztül, majd visszaküldi a kliensnek JSON formátumban, egy megfelelő HTTP státuszkóddal (pl. 200 OK, 404 Not Found).
Nagyon nem mindegy, hogy egy lekérdezés után hogyan vizsgálod meg, hogy lett-e eredmény! A titok a ->get() használatában rejlik:
- Ha NINCS
->get()a parancs végén (pl.::find($id)vagy->first()):
A Laravel vagy visszaad egyetlen konkrét sort (objektumot), vagy ha nincs találat, akkornullértéket ad. Itt tökéletesen működik az egyszerűif($data)ellenőrzés. - Ha VAN
->get()a parancs végén (pl.::all()vagy::where(...)->get()):
A Laravel ilyenkor egy Listát (Collection) ad vissza. Ha nincs találat, akkor egy üres listát kapunk. Mivel az üres lista is létezik (tehát nem null), a simaif($data)vizsgálat mindig IGAZ lenne! Ilyenkor a listában lévő elemeket kell megszámolni:if($data->count() > 0).
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
// KÖTELEZŐ: Az összes használt Modelt be kell húzni a Controllerbe!
use App\Models\modelnev;
public function fugvenynev(api.php bol)(Request $request)
{
// Itt jön a lekérdezés és a válasz logikája
}
// ÖSSZES ADAT LEKÉRÉSE (példa)
public function osszes_adat(api.php ben megadott function név)(Request $request)
{
$data = modelnev::all();
return response()->json($data, 200); // 200 = OK
}
// PONTOS EGYEZÉS ID ALAPJÁN (FIND)
public function adat_kereses(Request $request, $id)
{
$data = modelnev::find($id); // A $primaryKey alapján keres ezért fontos beállitani a modellben
if($data) {
return response()->json($data, 200);
} else {
// Hibaüzenet, ha nincs találat, 404-es (Not Found) kóddal
return response()->json(['message' => 'Nem található adat!'], 404);
}
}
// WHERE: PONTOS EGYEZÉS
public function pontos_kereses(Request $request, $p)
{
$data = modelnev::where('adatbázis oszlopnév (amiben keresni szeretnenk)', $p)->get();
if($data->count() > 0) {
return response()->json($data, 200);
} else {
return response()->json(['message' => 'Nem található adat!'], 404);
}
}
// WHERE: RÉSZLEGES EGYEZÉS (LIKE)
public function reszleges_egyezeses_kereses(Request $request, $p)
{
// SQL: WHERE nev LIKE '%jancsi%'
$data = modelnev::where('adatbázis oszlopnév (amiben keresni szeretnenk)', 'like', '%'.$p.'%')->get();
return response()->json($data, 200);
}
// WHERE: OPERÁTORRAL (Nagyobb, kisebb, egyenlő)
public function operatorral_kereses(Request $request, $p)
{
// SQL: WHERE ferohely >= $p + 1
$data = modelnev::where('adatbázis oszlopnév (amiben keresni szeretnenk)', '>=', $p + 1)->get();
return response()->json($data, 200);
}
Ha a táblák össze vannak kapcsolva (pl. idegen kulcsokkal), a join() paranccsal szedhetjük ki a komplex adatokat. Itt megadhatjuk azt is a select()-ben, hogy pontosan mely oszlopokra van szükségünk az összekapcsolt táblákból.
public function tobbtablas(Request $request)
{
$data = modelnev::select(
// ha abbol a modellből választunk oszlopot amiből selectelunk akkor nem kell a tablanevet kulon ki irni (de ha ki irjuk se lesz hiba)
'oszlopnev#1',
'tabla1.oszlopnev1 as tablaoszlop1', // 'as': Átnevezés a kimenetben
'tabla1.oszlopnev2 as tablaoszlop2',
'tabla2.oszlopnev1'
)
// INNER JOIN sofor ON muszak.sofor_id = sofor.sofor_id
//Az elsődleges táblában lévő masodlagos kulcs mezot kapcsoljuk ossze az osszekapcsolni kivant tablában lévő elsodleges kulcs mezovel
->join('tabla2', 'tabla1(modelnev).masodlagoskulcs ', '=', 'tabla2.id(elsodlegeskulcs)')
// INNER JOIN tabla3 ON tabla2.masik_idegen_kulcs = tabla3.elsodleges_kulcs
->join('tabla3', 'tabla2(modelnev).masodlagoskulcs ', '=', 'tabla3.id(elsodlegeskulcs)')
->get();
if($data->count() > 0) {
return response()->json($data, 200);
} else {
return response()->json(['message' => 'Nincs műszak!'], 404);
}
}
Ha egymás után láncolsz több where parancsot, a Laravel automatikusan ÉS (AND) kapcsolatot feltételez közöttük (mindkét feltételnek igaznak kell lennie).
De ha neked az is jó, ha az egyik VAGY a másik feltétel teljesül, akkor veszed elő az orWhere függvényt!
// TÖBBSZÖRÖS SZŰRÉS: VAGY (OR) KAPCSOLAT
public function vagy_kereses(Request $request)
{
$data = modelnev::where('oszlop_nev', '>', ertek)
->orWhere('oszlop_nev', 'keresettérték')
->get();
if($data->count() > 0) {
return response()->json($data, 200);
} else {
return response()->json(['message' => 'Nincs ilyen adat!'], 404);
}
}
POST-al új hozzáadása
public function neve(Request $request){
$modelnev = new modelnev();
$modelnev->keres1 = $request->keres1;
$modelnev->keres2 = $request->keres2;
$modelnev->keres3 = $request->keres3;
$modelnev->save();
return response()->json([
'message' => 'Sikeres mentés!'
], 201);
}
Ha a tábládban az elsődleges kulcs nem egy növekvő szám (pl. ID), hanem egy szöveg (pl. rendszám vagy termékkód), akkor azt külön jelezni kell a Modelben. Két dolgot kell megmondanod a Laravelnek: 1. Ez NEM növekszik automatikusan. 2. A típusa szöveg (string).
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
protected $table = "tablanev";
// 1. A kulcs oszlopának neve
protected $primaryKey = "elsodlegeskulcs_oszlop";
// 2. KÖTELEZŐ: Megmondjuk, hogy ez NEM egy automatikusan növekvő szám!
public $incrementing = false;
// 3. KÖTELEZŐ: Megmondjuk, hogy a kulcs típusa szöveg (string).
protected $keyType = 'string';
// Időbélyeg kikapcsolása (ha nincs created_at/updated_at az adatbázisban)
public $timestamps = false;
Ha a Modelben mindent jól beállítottál, a keresés ugyanúgy működik! A fő különbség az új adat létrehozásánál és a táblák összekapcsolásánál van.
// 1. KERESÉS (Find) - NINCS KÜLÖNBSÉG!
// A find() függvény most már tudja, hogy szöveget kell keresnie az 'id' helyett.
$valtozo = Modelnev::find('keresendo adat');
// Az aposztróf csak akkor kell, ha fix adatra szeretnénk mindig keresni. Ha változóra, akkor ugyanúgy meghívjuk a $valtozot, és tudunk vele keresni.
// 2. ÚJ ADAT MENTÉSE - KÜLÖNBSÉG VAN!
// Mivel a kulcs NEM növekszik magától (Auto Increment), NEKED KELL MEGADNI az értékét mentés előtt!
public function szoveges_adat_mentese(Request $request)
{
$ujAdat = new Modelnev();
// KÖTELEZŐ megadni a kulcsot, különben hibát kapsz!
$ujAdat->elsodlegeskulcs_oszlop = $request->bevitt_ertek1;
$ujAdat->masik_oszlop = $request->bevitt_ertek2;
$ujAdat->save();
return response()->json(['message' => 'Sikeres mentés!'], 201);
}
// 3. TÁBLÁK ÖSSZEKAPCSOLÁSA (Relációk a Modelben) - KÜLÖNBSÉG VAN!
// Ha egy másik tábla hivatkozik erre a szöveges kulcsra,
// a Laravel alapból 'modelnev_id'-t keresne. Neked explicit meg kell mondanod az oszlopok neveit!
class MasikModelnev extends Model {
public function kapcsolodo_adatok()
{
// belongsTo(KapcsolódóModel::class, 'idegen_kulcs_ebben_a_tablaban', 'elsodleges_kulcs_a_masik_tablaban')
return $this->belongsTo(Modelnev::class, 'idegenkulcs_oszlopnev', 'elsodlegeskulcs_oszlop');
}
}
JavaScript és API Kommunikáció
1. Adatok lekérése: XMLHttpRequest és Fetch API
const url = "alap URL";
function ajax(parameter, url, callback) {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
if(xhttp.status == 200) {
var respons = JSON.parse(xhttp.responseText);
callback(respons);
}
}
xhttp.open("GET", url + parameter);
xhttp.send();
}
const url = "alap URL";
async function fetchAdatok(parameter, url, callback) {
try {
const response = await fetch(url + parameter);
if (!response.ok) throw new Error("Hálózati hiba!");
const adatok = await response.json();
callback(adatok);
} catch (error) {
console.error("Hiba:", error);
}
}
2. A Táblázat Dinamikus Generálása (DOM)
function tablaletrehozas(adatok) {
var tabla = document.getElementById("tablazat");
tabla.innerHTML = "";
if (Array.isArray(adatok)) {
adatok.forEach(valtozonev => {
tabla.innerHTML += `
<tr>
<td>${valtozonev.id}</td>
<td>${valtozonev.oszlopnev}</td>
.
.
.
</tr>
`;
});
} else {
tabla.innerHTML = `<tr><td colspan="6">Nincs adat</td></tr>`;
}
}
3. Keresés és Kliens oldali Szűrés
var osszesadat = [];
function kereses() {
var bevitelimezoertek1 = document.getElementById("htmlbevitelimezo").value;
var bevitelimezoertek2 = document.getElementById("htmlbevitelimezo").value;
var utvonal = "/utvonal/" + keresettdolog(oszlopnev);
ajax(utvonal, url, function(adatok) {
tablaletrehozas(adatok);
osszesadat = adatok; // Mentés helyi szűréshez!
});
}
function nevker() {
var keresett = document.getElementById("szoveg").value.toLowerCase();
var talalatok = osszesadat.filter(valtozo =>
valtozo.keresettoszlopnev.toLowerCase().includes(keresett)
);
tablaletrehozas(talalatok);
}
Adatbázis Kezelés (MySQL / MariaDB)
Az adatbázis a webes és asztali alkalmazások lelke. Itt találod a táblák létrehozásához szükséges parancsokat, típusokat, és a haladó lekérdezéseket.
1. Gyakori Adattípusok (Melyiket mikor használjuk?)
INTvagyINTEGER(Egész számok): Például1,4500. Leggyakrabban ID-khez vagy darabszámokhoz használjuk.VARCHAR(hossz)(Változó hosszúságú szöveg): AVARCHAR(255)a leggyakoribb (pl. nevek, címek, e-mailek). A 255 azt jelenti, hogy maximum ennyi karakter lehet, de ha csak 5-öt írsz be, akkor csak annyi helyet foglal!CHAR(hossz)(Fix hosszúságú szöveg): Vizsgákon ritkább, de pl. egy rendszámhoz (CHAR(7)) vagy irányítószámhoz (CHAR(4)) tökéletes. Ha rövidebbet írsz, szóközökkel pótolja ki.DATE(Csak dátum): Év-Hónap-Nap formátum, pl.'2023-10-25'. Születési időhöz kötelező.DATETIME(Dátum és időpont egyben): Például'2023-10-25 14:30:00'. Regisztrációkhoz, logoláshoz használjuk.DECIMAL(összes, tizedes)(Pontos tizedestört): ADECIMAL(8, 2)azt jelenti, hogy összesen 8 számjegyből állhat, amiből 2 a tizedesvessző után van (pl. árakhoz,15000.50).BOOLEANvagyTINYINT(1)(Logikai érték): Igaz vagy Hamis. Az adatbázisban1(Igaz) vagy0(Hamis) formájában tárolódik.
2. Megszorítások (Constraints) - Szabályok a táblában
Ezek a parancsok garantálják, hogy ne kerüljön "szemét" vagy hibás adat a táblába.
PRIMARY KEY(Elsődleges kulcs): Egyedi azonosító minden sornak (pl. személyi szám, vagy egy sima ID). Ebből csak egy lehet táblánként, és nem lehet üres!AUTO_INCREMENT(Automatikus sorszámozás): Általában azINT PRIMARY KEYmellé tesszük, így az adatbázis magától adja a 1, 2, 3... értékeket.NOT NULL(Kötelező mező): Ha ezt kiírod, a rendszer hibát dob, ha valaki üresen (kitöltetlenül) akarja hagyni ezt az oszlopot.UNIQUE(Egyedi érték): Olyan, mint a Primary Key, de ebből több is lehet a táblában (pl. azemailoszlopra rakjuk, hogy ne lehessen kétszer regisztrálni ugyanazzal).DEFAULT 'érték'(Alapértelmezett érték): Ha beszúráskor (INSERT) nem adunk meg semmit, ezt írja be automatikusan (pl.DEFAULT 'aktív').CHECK (feltétel)(Bonyolultabb ellenőrzés): PéldáulCHECK (kor >= 18)- nem enged be 18 évnél fiatalabb adatot.FOREIGN KEY(Idegen kulcs): Két tábla összekapcsolására szolgál (pl. a "vásárlások" táblában a "vevo_id" egy idegen kulcs, ami a "vevők" tábla "id"-jére mutat).
3. Adatbázis és Tábla Létrehozása (CREATE)
Vizsgákon a legelső lépés. A karakterkódolás (UTF-8) megadása szinte mindig kötelező, hogy a magyar ékezetek (á, ű, ő) ne "krixkraxként" jelenjenek meg!
CREATE DATABASE adatbazisnev
DEFAULT CHARACTER SET utf8
COLLATE utf8_hungarian_ci;
-- Használatba vétel (Kiválasztás)
USE adatbazisnev;
A megszorításokat és a típusokat itt vetjük be. Figyeld meg az idegen kulcs (Foreign Key) megadásának szintaktikáját a kód alján!
CREATE TABLE tablanev (
-- Elsődleges kulcs, ami magától nő
id INT AUTO_INCREMENT PRIMARY KEY,
-- Kötelező szöveges mező
szoveg VARCHAR(255) NOT NULL,
-- szám ami nem lehet negativ
szam INT UNSIGNED ,
-- Idegen kulcs egy másik táblához
idegenkulcs INT,
FOREIGN KEY (oszlopnev) REFERENCES masiktabla(kulcs_oszlop)
);
4. Adatok Felvitele (INSERT INTO)
Az adatok beszúrása. Két dologra kell figyelni: az oszlopok neveit fel kell sorolni, majd a VALUES után ugyanabban a sorrendben megadni az értékeket. Szöveget és dátumot mindig aposztrófok (' ') közé teszünk, a számokat nem!
-- Több adat beszúrása egyszerre (vesszővel elválasztva)
INSERT INTO tablanev (oszlopnev1, oszlopnev2, oszlopnev3)
VALUES ('szovegesértékbevitel', 123, 1),
('szoveg1', szam, szam),
('szoveg#2', szam, szam),
('szoveg#3', szam, szam);
5. Dupla Select / Belső Lekérdezés (Subqueries)
Van, amikor egy kérdés megválaszolásához egy másik kérdést is fel kell tennünk az adatbázisnak. Például: "Kik keresnek többet, mint az ÁTLAG?" (Ehhez először ki kell számolni az átlagot). Ezek a belső lekérdezések, amik mindig zárójelbe kerülnek.
A belső SELECT mindössze egyetlen cellányi adatot ad vissza (pl. egy maximumot vagy átlagot). Relációs jelekkel (=, >, <) vizsgáljuk.
-- Először a zárójel belseje fut le: megkeresi a max árat (pl. 85000).
-- A külső rész pedig kiírja azt a nevet, aminek az ára egyenlő ezzel.
SELECT oszlopnev1,oszlopnev2
FROM tabla1
WHERE oszlopnev3 = (
SELECT MAX(oszlopnev3)
FROM tabla2
);
-- A belso selectben lekerdezhetjuk ugyan azon tabla masik adatait vagy akar masik tabla adatait is
A belső SELECT egy egész oszlopnyi adatot (több ID-t) ad vissza. Mivel több érték van, nem használhatunk egyenlőségjelet (=), helyette az IN kulcsszót kell használnunk!
SELECT oszlopnev
FROM tablanev
WHERE oszlopnev(legtobbszor id) IN (
SELECT oszlopnev(legtobbszor id)
FROM tablanev
WHERE keresettoszlopnev = 'keresettertek'
-- A keresett ertek ha egy valtozo vagy oszlopnev akkor nem kell aposztrof ('')
);
5. Táblák összekapcsolása (Foreign Key / References)
A „Szülő-Gyerek” kapcsolat: Képzeld el, hogy van egy kategoriak táblád (ő a Szülő) és egy termekek táblád (ő a Gyerek). Az idegen kulcs egy „láthatatlan lánc”, ami összeköti őket.
- Miért jó ez? Megakadályozza, hogy olyan kategóriába sorolj egy terméket, ami nem is létezik. Ha a kategóriák között csak 1-től 5-ig vannak számok, az adatbázis „leüti a kezed”, ha te a 99-es kategóriát akarod megadni.
- Szigorú szabály: Az összekapcsolt oszlopoknak hajszálpontosan ugyanaz legyen a típusa! Ha a szülő táblában az ID
INT UNSIGNED, akkor a gyerek táblában a rá mutató kulcs isINT UNSIGNEDkell, hogy legyen.
-- 1. A SZÜLŐ TÁBLA (Ezt hozzuk létre először)
CREATE TABLE parent_table (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
egyeb_mezo VARCHAR(50) NOT NULL
);
-- 2. A GYEREK TÁBLA (Aki hivatkozik a szülőre)
CREATE TABLE child_table (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
egyeb_mezo VARCHAR(100) NOT NULL,
-- Ez az oszlop fogja tárolni, a referencia id-ket.
parent_table_id INT UNSIGNED,
-- A KAPCSOLAT LÉTREHOZÁSA:
FOREIGN KEY (parent_table_id) REFERENCES parent_table(id)
-- "elsonek azt az oszlop mezot kell meg adni ami az aktualis tablaban levo masodlagos kulcs zarojelek kozott"
-- "A masodik ertek az meg a szulo tabla tehat ahol van az elsodleges kulcs és ott zarojelben meg kell adni a primary key oszlop nevet. (altalaban id vagy tablanev_id)"
-- Opcionális extra: ON DELETE CASCADE
-- Ez azt jelenti: "Ha torlom a parent elemet torlodik vele az osszes rá hivatkozo child elem is."
ON DELETE CASCADE
);
C# GUI (Windows Forms)
1. Az Adatbázis kapcsolat osztály
using System;
using MySql.Data.MySqlClient;
string server = "server=localhost;user=root;database=adatbazisnev;password=;" EN: diak66 uid diak66 pw XXTQ4E;
MySqlConnection kapcsolat;
MySqlCommand parancs;
MySqlDataReader dr;
public Konstruktornev(filenev)(string sql)
{
kapcsolat = new MySqlConnection(server);
kapcsolat.Open();
parancs = new MySqlCommand(sql, kapcsolat);
Dr = parancs.ExecuteReader();
}
public MySqlDataReader Dr { get => dr; set => dr = value; }
public void lezaras() { kapcsolat.Close(); }
~Adatbazis() { kapcsolat.Close(); }
2. Adatátvitel Formok között
Gyakori feladat, hogy egy adatot (például egy kijelölt sor ID-ját) át kell adnunk egyik ablakból a másikba. Íme a három legnépszerűbb megoldás:
A legegyszerűbb mód: már az ablak létrehozásakor átadjuk az adatot paraméterként.
// Küldő Form (Form1.cs)
string adat = tx_nev.Text;
Form2 f2 = new Form2(adat);
f2.Show();
// Fogadó Form (Form2.cs)
string megkapott;
public Form2(string bejovo) {
InitializeComponent();
megkapott = bejovo;
}
Ha sok formnak van szüksége ugyanarra az adatra (pl. bejelentkezett felhasználó).
// Hozz létre egy Global.cs fájlt:
public static class Global {
public static int UserId;
}
// Bárhol írható/olvasható:
Global.UserId = 5;
int id = Global.UserId;
Létrehozunk egy változót a cél-formban, amit kívülről beállítunk a megjelenítés előtt.
// Fogadó Form (Form2.cs)
public string AtvittAdat { get; set; }
// Küldő Form (Form1.cs)
Form2 f2 = new Form2();
f2.AtvittAdat = "Szia!";
f2.Show();
2. Adatok Mentése és Módosítása
private void bt_mentes_Click(object sender, EventArgs e)
{
if (tx_szovegmezo.Text.Length == 0)
{
MessageBox.Show("Kérjük, töltse ki a szöveges mezőt!", "HIBA", MessageBoxButtons.OK, MessageBoxIcon.Error);
tx_szovegmezo.Focus();
return;
}
// 2. Szám mező validálása (különálló try-catch)
try
{
int szamAdat = Convert.ToInt32(tx_szamosmezo.Text);
}
catch
{
MessageBox.Show("A szám mezőbe csak számot írhat!", "HIBA", MessageBoxButtons.OK, MessageBoxIcon.Error);
tx_szamosmezo.Text = "";
tx_szamosmezo.Focus();
return;
}
// 3. Ha ide eljutott a program, minden adat hibátlan! Jöhet a többi konverzió.
string datumAdat = formdatummezo.Value.ToString("yyyy-MM-dd");
string datumIdoAdat = formdatummezo.Value.ToString("yyyy-MM-dd HH:mm:ss");
if (rbujfelvitel.Checked)
{
string lekerdezes = "INSERT INTO tablanev (szoveges_oszlop, szamos_oszlop, datum_oszlop, datumido_oszlop, logikai_oszlop) " +
"VALUES (" +
"'" + tx_szovegmezo.Text + "', " +
szamAdat + ", " +
"'" + datumAdat + "', " +
"'" + datumIdoAdat + "', " +
logikaiAdat + ");";
Adatbazis ab = new Adatbazis(lekerdezes);
ab.Dr.Read();
MessageBox.Show("Sikeres mentés!");
}
else
{
string lekerdezes = "UPDATE tablanev SET " +
"szoveges_oszlop='" + tx_szovegmezo.Text + "', " +
"szamos_oszlop=" + szamAdat + ", " +
"datum_oszlop='" + datumAdat + "', " +
"datumido_oszlop='" + datumIdoAdat + "', " +
"logikai_oszlop=" + logikaiAdat + " " +
"WHERE id_oszlop=" + formazon;
Adatbazis ab = new Adatbazis(lekerdezes);
ab.Dr.Read();
MessageBox.Show("Sikeres módosítás!");
}
}
3. DataGridView Kezelése (Betöltés, Szűrés, Kattintás)
A DataGridView az egyik leghasznosabb vezérlő, mellyel táblázatos adatokat tudunk megjeleníteni és kezelni. Itt láthatod, hogyan töltsd fel, hogyan csinálj dinamikus szűrést TextBox alapján, és miként nyerj ki adatot rákattintással.
A Clear() használatával megelőzzük az adatok duplikálását, a Convert.ToDateTime pedig lehetővé teszi, hogy egyéni (pl. yyyy-MM-dd) formátumban fűzzük be a dátumot a gridbe.
void tablakitoltes()
{
dataGridView1.Rows.Clear();
string lekerdezes = "select * from tablanev";
Adatbazis ab = new Adatbazis(lekerdezes);
while (ab.Dr.Read())
{
DateTime DateTimeValtozo = Convert.ToDateTime(ab.Dr["DateTimeAdat"]);
dataGridView1.Rows.Add(ab.Dr["oszlopnev"], DateTimeValtozo.ToString("yyyy-MM-dd"));
}
}
Ha a felhasználó gépel a txkereses TextBox-ba, a program hozzáfűz egy WHERE feltételt a lekérdezéshez, így a Grid tartalma valós időben szűrhetővé válik.
void tablabetoltes()
{
dataGridView1.Rows.Clear();
string keresszoveg = "";
// Ha van beírva szöveg, hozzáfűzzük a szűrést
if (txkereses.TextLength > 0)
{
keresszoveg = " where KeresettOszlop like '" + txkereses.Text + "%' ";
}
string lekerdezes = "select * from táblanév " + keresszoveg;
Adatbazis ab = new Adatbázis(lekerdezes);
while (ab.Dr.Read())
{
DateTime datum = Convert.ToDateTime(ab.Dr["datumoszlop"]);
dataGridView1.Rows.Add(ab.Dr["oszlopnev1"], ab.Dr["oszlopnev2"], datum.ToString("yyyy-MM-dd"));
}
}
Amikor rákkattintasz egy cellára, az adott sor értékeit áttöltheted Labelekbe vagy TextBoxokba.
Tipp: A feltételt e.RowIndex >= 0-ra módosítottam a te kódodhoz képest, mert a 0 index a legelső adatsor! (A -1 lenne a fejléc, azt így tökéletesen kihagyjuk).
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
// Ellenőrizzük, hogy NEM a fejlécre kattintottak-e (fejléc indexe: -1)
if (e.RowIndex >= 0)
{
// A kiválasztott sor (Row) objektumának eltárolása
DataGridViewRow sor = dgadatok.Rows[e.RowIndex];
// Cellák értékének átadása a szövegmezőknek (Oszlop neve alapján)
label1.Text = sor.Cells["dataGridViewMezonev1"].Value.ToString();
label2.Text = sor.Cells["dataGridViewMezonev2"].Value.ToString();
label3.Text = sor.Cells["dataGridViewMezonev3"].Value.ToString();
label4.Text = sor.Cells["dataGridViewMezonev4"].Value.ToString();
}
}
C# CLI & LINQ Kisokos
0. Szövegformázás és Tagolás (Escape karakterek)
A konzolos kiíratásoknál gyakran van szükségünk sortörésre, behúzásra, vagy olyan speciális karakterek kiírására, amiket a C# amúgy a kód részének gondolna (pl. idézőjel). Ezeket a \ (backslash) jellel tudjuk vezérlő jellé alakítani.
\n: Új sor (Sortörés / Enter).\t: Tabulátor (Nagyobb szóköz, pl. oszlopok igazításához).\": Idézőjel kiírása egy szövegen belül (anélkül, hogy lezárná a stringet).\\: Backslash (\) kiírása (pl. fájlok elérési útjánál).
// 1. Sortörés és Tabulátor használata (tablazat szeru ki iratas)
Console.WriteLine("Oszlopnev\tOszlopnev\n1.\tTartalom1\n2.\tTartalom2");
// 2. Idézőjel a stringen belül
Console.WriteLine("Azt mondta: \"Szia, hogy vagy?\"");
// 3. Elérési út (Backslash) - Kétféleképpen:
string utvonal1 = "C:\\mappa\\fajl.kiterjesztes";
// VAGY: A @ jellel a string elején a C# figyelmen kívül hagyja a vezérlő karaktereket!
string utvonal2 = @"C:\mappa\fajl.kiterjesztes";
Osztály (Class) létrehozása beolvasáshoz
// fel kell venni a tulajdonságokat (valtozokat)
public int ID { get; set; }
public string Nev { get; set; }
// A valtozok felvétele utan generalni kell hozza propertiket
// Konstruktor
public konstruktornev(class név)(string sor)
{
var v = sor.Split(';');
ID = int.Parse(v[0]);
Nev = v[1];
}
// ToString override megjelenites
public override string ToString() => $"Név: {Nev}\nId: {ID} ";
2. Főprogram - Fájl Beolvasás és Írás (bin/Debug)
A fájlt (pl. adatok.txt) a bin/Debug/net... mappában keresi. Az első sort (fejlécet) egy külön ReadLine() paranccsal kiolvassuk a ciklus előtt, így a feldolgozás már a tiszta adatokkal kezdődik.
// Egyedi lista az objektumoknak
List<Osztalynev> osztalylista = new List<Osztalynev>();
FileStream fs = new FileStream("adatok.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs, Encoding.UTF8);
// Fejléc kihagyasa
_ = sr.ReadLine();
while (!sr.EndOfStream)
{
// Konstruktor hívása az aktuális sorral
osztalylista.Add(new Osztalynev(sr.ReadLine()));
}
// Fájlfolyamok lezárása (KÖTELEZŐ!)
sr.Close();
fs.Close();
Eredmények kimentése egy új fájlba. Fontos: a FileMode.Create felülírja a fájlt, ha már létezik. A Close() metódusokat sose felejtsd el, különben a fájl üres maradhat!
// Fájl létrehozása (szintén a bin/Debug mappába)
List<Osztalynev> osztalylista = new List<Osztalynev>();
FileStream fs = new FileStream("kimenet.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fsIras, Encoding.UTF8);
// Ha szeretnél saját fejlécet írni a fájlba
sw.WriteLine("Név;Statisztika");
foreach (var item in osztalylista)
{
// Adatok kiírása formázva (pl. pontosvesszővel elválasztva)
sw.WriteLine($"{item.Nev};{item.Tulajdonsag}");
}
// Lezárás (Enélkül nem kerülnek mentésre az adatok az SSD-re/HDD-re!)
sw.Close();
fs.Close();
2.5. Lista elemeinek elérése és bejárása
A beolvasott adatokat tartalmazó listából az elemeket az indexükkel (0-tól kezdve) érhetjük el. Az utolsó elem indexe mindig a Count - 1.
// 1. Az ELSŐ elem elérése (0. index)
Console.WriteLine($"Első adat: {osztalylista[0].Tulajdonsag}");
// 2. Az UTOLSÓ elem elérése (Count-1)
Console.WriteLine($"Utolsó adat: {osztalylista[osztalylista.Count - 1].Tulajdonsag}");
// 3. A teljes lista bejárása (Minden elem kiíratása)
foreach (var item in osztalylista)
{
// Az osztályban definiált tulajdonságok vagy a felülírt ToString() hívása
Console.WriteLine($"{item.Nev} - {item.Tulajdonsag1} - {item.Tulajdonsag2}");
}
3. Dictionary (Szótár) Használata (Gyakoriság statisztika)
A Dictionary<Kulcs, Érték> a legalkalmasabb eszköz statisztikák készítésére (pl. "Melyik kategóriából hány darab van?"). Az alábbi algoritmus végigmegy a listán, és ha a kulcs (pl. fizetési mód, típus) még nincs a szótárban, felveszi 1-es értékkel. Ha már benne van, akkor megnöveli az értékét.
// 1. Szótár létrehozása (Kulcs: a vizsgált szöveges tulajdonság, Érték: darabszám)
Dictionary<string, int> statisztika = new Dictionary<string, int>();
// 2. Lista bejárása és statisztika építése
for (int i = 0; i < lista.Count; i++)
{
// Ha a szótár MÉG NEM tartalmazza ezt a kulcsot (pl. ezt a kategóriát)
if (!statisztika.ContainsKey(lista[i].KeresettTulajdonsag))
{
// Felvesszük a szótárba, 1-es induló darabszámmal
statisztika.Add(lista[i].KeresettTulajdonsag, 1);
}
else
{
// Ha már benne van, csak megnöveljük a meglévő darabszámot
statisztika[lista[i].KeresettTulajdonsag]++;
}
}
// 3. A kész statisztika kiírása a képernyőre
foreach (var item in statisztika)
{
Console.WriteLine($"\t{item.Key}: {item.Value} db");
}
4. Metódus (Eljárás) vs. Függvény
C#-ban minden egy osztályon belül van, így technikailag mindent metódusnak hívunk. Viszont a működésük alapján (ahogy az iskolában is tanulod) két nagy csoportra osztjuk őket: Eljárásokra (nem adnak vissza adatot a hívónak) és Függvényekre (adnak vissza valamilyen eredményt).
A void kulcsszó jelzi, hogy ez a kódblokk elvégez egy feladatot (pl. kiír valamit a képernyőre, vagy beállít egy változót), de nem ad vissza értéket a hívónak. Nincs benne return (vagy csak üresen a kilépéshez).
// Létrehozás: A "void" jelzi, hogy nincs visszatérési érték
public void eljaras_neve(string parameternev)
{
Console.WriteLine("Ez csak megcsinál valamit: " + parameternev);
// NINCS return érték!
}
// Meghívás a főprogramban: Nem tudjuk változóba menteni!
eljaras_neve("teszt adat");
A void helyett egy konkrét adattípust (pl. int, string, bool) adunk meg. A kód végén kötelező a return kulcsszóval egy ilyen típusú értéket visszaadni, amit aztán a hívó fél egy változóban elmenthet.
// Létrehozás: A "void" helyett pl. "int" van megadva (attol fugg milyen vissza térési értéket szeretnenk)
public int fuggveny_neve(int bevittszamertek1, int bevittszamertek2)
{
int eredmeny = bevittszamertek1 + bevittszamertek2;
// KÖTELEZŐ visszaadni a függvény tipusanak megfelelo erteket!
return eredmeny;
}
// Meghívás a főprogramban: egy változóba MENTJÜK a választ!
int megkapott_ertek = fuggveny_neve(5, 10);
C# Programozási Tételek (Hagyományos)
Ezek az algoritmusok LINQ (beépített függvények) használata nélkül, klasszikus ciklusokkal (for, while) oldják meg az alapvető problémákat. Vizsgákon gyakran kötelező ezt a megközelítést alkalmazni!
A lista objektumainak egy adott számszerű tulajdonságát adjuk össze.
int osszeg = 0;
for (int i = 0; i < lista.Count; i++)
{
// Egy osztálypéldány konkrét tulajdonságát adjuk hozzá
osszeg += lista[i].Tulajdonsag;
}
Console.WriteLine($"Az összeg: {osszeg}");
Hány olyan objektum van, aminek a tulajdonsága megfelel a feltételnek?
int db = 0;
for (int i = 0; i < lista.Count; i++)
{
if (lista[i].Tulajdonsag == Feltétel)
{
db++;
}
}
Console.WriteLine($"Találatok száma: {db}");
Kikeresi a legnagyobb elemet. Mindig indexet tárolunk, nem magát az értéket!
int maxIndex = 0;
for (int i = 1; i < lista.Count; i++)
{
// Itt is a tulajdonságokat hasonlítjuk össze
if (lista[i].Tulajdonsag > lista[maxIndex].Tulajdonsag)
{
maxIndex = i;
}
}
Console.WriteLine($"Legnagyobb elem neve: {lista[maxIndex].Nev}");
Kikeresi a legkisebb elemet. A logika pontosan ugyanaz, csak a relációs jel fordul meg.
int minIndex = 0;
for (int i = 1; i < lista.Count; i++)
{
if (lista[i].Tulajdonsag < lista[minIndex].Tulajdonsag)
{
minIndex = i;
}
}
Console.WriteLine($"Legkisebb elem neve: {lista[minIndex].Nev}");
int i = 0;
while (i < lista.Count && !(lista[i].Tulajdonsag == Feltétel))
{
i++;
}
bool vanIlyen = (i < lista.Count);
int j = 0;
// Nincs túlfutás ellenőrzés, mert tudjuk, hogy benne van!
while (lista[j] != Feltétel)
{
j++;
}
int index = j; // Megvan a keresett elem indexe
A legteljesebb keresés. Megmondja, hogy van-e ilyen elem, és ha igen, megadja az indexét is (hol található). Addig megy a ciklus, amíg meg nem találja az elsőt!
int i = 0;
// Futunk, amíg a lista tart ÉS nem találtuk meg a keresett elemet
while (i < lista.Count && !(lista[i] == Feltétel))
{
i++;
}
bool vanIlyen = (i < lista.Count);
int index = -1; // Alapértelmezett, érvénytelen index
if (vanIlyen)
{
index = i;
Console.WriteLine($"Megtalálva a(z) {index}. indexen!");
}
else
{
Console.WriteLine("Nincs ilyen elem a listában.");
}
Amikor nem csak megszámlálni akarjuk a feltételnek megfelelő elemeket, hanem egy új listába ki is másoljuk őket, hogy később dolgozhassunk velük.
List<Osztalynev> eredmenyLista = new List<Osztalynev>();
for (int i = 0; i < lista.Count; i++)
{
// Ha az objektum tulajdonsága megfelel...
if (lista[i].Tulajdonsag == Feltétel)
{
// ...magát az objektumot adjuk hozzá az új listához
eredmenyLista.Add(lista[i]);
}
}
1. Alapvető Programozási Tételek (Matematika)
var osszegzes = lista.Sum(valtozo => valtozo.tulajdonsag);
var atlag = lista.Average(valtozo => valtozo.tulajdonsag);
var count = lista.Count(valtozo => valtozo.tulajdonsag == "keresett tulajdonsasg");
2. Keresés, Kiválasztás, Eldöntés
// FirstOrDefault: ha nem talál akkor null lesz és nem dob hibat
var elso = lista.FirstOrDefault(valtozo => valtozo.tulajdonsag == "keresett tulajdonsag");
// Single: Pontosan EGY találatot várunk.
var egy = lista.Single(valtozo => valtozo.tulajdonsag.Contains("keresett dolog(tulajdonsag)"));
3. Projekció (Kiválogatás) és Rendezés
// Láncolás (KOMPLEX): Az 5 legöregebb macska lekérése
var komplex = lista
.Where(valtozo => valtozo.tulajdonsag == "keresett tulajdonsag")
.OrderByDescending(valtozo => valtozo.tulajdonsag)
.ToList()[..5];
// a [..5] azt jelenti hogy az elso 5 elem lesz vissza adva ugyan az mint a .Take(5) itt is 5 elemet veszunk ki
4. Csoportosítás (GroupBy)
var csoport = listta
.GroupBy(valtozo => valtozo.tulajdonsag) // csoportosítás a tulajdonsag alapján
.Where(valtozo => valtozo.Count() > 1)
.OrderBy(valtozo => valtozo.Key)
.ToDictionary(valtozo => valtozo.Key, valtozo => valtozo.Count());
CSS Kisokos (Tulajdonság Szótár)
A CSS (Cascading Style Sheets) felel az oldal kinézetéért. Az alábbi listában megtalálod a leggyakrabban használt formázó tulajdonságokat és azok lehetséges értékeit.
1. Méretezés, Margók és Távolságok
.elem {
/* SZÉLESSÉG ÉS MAGASSÁG */
width: 100%; /* Fix szélesség (px, %, vw) */
max-width: 1200px; /* Sohasem lesz szélesebb ennél (reszponzív oldalaknál kötelező) */
min-width: 300px; /* Ennél sohasem lesz keskenyebb */
height: auto; /* Magasság (auto: a belső tartalom határozza meg, px, vh) */
min-height: 100vh; /* Kitölti a képernyő teljes magasságát (Viewport Height) */
/* TÁVOLSÁGOK (A 4 érték sorrendje mindig: Fent, Jobb, Lent, Bal) */
margin: 10px 20px 10px 20px; /* KÜLSŐ távolság az elemek között */
margin: 0 auto; /* Vízszintesen KÖZÉPRE igazítja a blokkot! */
margin-top: 15px; /* Csak fentre tesz külső margót */
padding: 20px; /* BELSŐ távolság (a keret és a szöveg között) minden irányba */
padding-left: 10px; /* Csak balra tesz belső margót */
/* DOBOZ SZÁMÍTÁS (Aranyat érő szabály!) */
box-sizing: border-box; /* A padding és a border befelé vastagodik, nem növeli meg az elem szélességét! */
}
2. Keretek és Árnyékok
.elem {
/* KERET (Vastagság, Stílus, Szín) */
border: 2px solid red; /* Folyamatos keret */
border: 1px dashed blue; /* Szaggatott keret */
border: 3px dotted green; /* Pöttyözött keret */
border-bottom: 1px solid #ccc;/* Csak alulra tesz vonalat */
/* SARKOK LEKEREKÍTÉSE */
border-radius: 8px; /* Enyhe lekerekítés */
border-radius: 50%; /* Teljesen kerek (kör), ha a szélesség és magasság egyezik! */
/* ÁRNYÉKOK (X eltolás, Y eltolás, Elmosódás, Méretnövelés, Szín) */
box-shadow: 2px 4px 10px 0px rgba(0,0,0,0.5); /* Doboz árnyéka (kívül) */
box-shadow: inset 0px 0px 5px black; /* Belső árnyék (inset) */
}
3. Szövegformázás és Tipográfia
.szoveg {
/* BETŰTÍPUS ÉS MÉRET */
font-family: Arial, sans-serif; /* Betűtípus (ha az első nincs, jön a második) */
font-size: 16px; /* Betűméret (px, rem, em) */
font-weight: bold; /* Vastagság: normal, bold, vagy 100-tól 900-ig számok */
font-style: italic; /* Dőlt betű (normal az alap) */
/* SZÍNEK ÉS IGAZÍTÁS */
color: #333333; /* Szövegszín (Név, Hexa, RGB, RGBA) */
text-align: center; /* Igazítás: left, right, center, justify (sorkizárt) */
line-height: 1.5; /* Sorköz (a betűméret másfélszerese) */
letter-spacing: 1px; /* Betűk közötti távolság */
/* DEKORÁCIÓ ÉS ÁTALAKÍTÁS */
text-decoration: underline; /* Aláhúzás (linkeknél 'none'-nal lehet levenni) */
text-transform: uppercase; /* MINDEN NAGYBETŰ (lowercase: kisbetű, capitalize: Kezdőbetűk) */
text-shadow: 1px 1px 2px black; /* Magának a szövegnek az árnyéka */
}
4. Hátterek (Backgrounds)
.hatter {
/* EGYSZERŰ HÁTTÉRSZÍN */
background-color: #0d6efd; /* Simán kitölti színnel */
/* HÁTTÉRKÉP BEÁLLÍTÁSAI */
background-image: url('kep.jpg'); /* Kép betöltése */
background-size: cover; /* Kitölti az egész elemet anélkül, hogy torzulna a kép */
/* (A 'contain' értéknél a kép teljes egésze látszani fog, de lehet, hogy marad üres hely) */
background-position: center; /* Középre igazítja a képet (lehet top, bottom, left, right is) */
background-repeat: no-repeat; /* Megakadályozza, hogy a kis képek csempeszerűen ismétlődjenek */
background-attachment: fixed; /* Parallax hatás: görgetéskor a kép helyben marad */
/* ÁTMENET (GRADIENS) */
background: linear-gradient(to right, red, blue); /* Pirosból kékbe tartó átmenet */
}
5. Pozíció és Megjelenés (Block vs. Flex)
A display: block lényege: Az ilyen elem (pl. div, p, h1) „önző”. Elfoglalja a rendelkezésre álló teljes szélességet (100%), és mindenképpen új sorban kezdődik. Nem enged maga mellé semmit, hacsak nem kényszerítjük rá (pl. floattal).
.container {
/* FLEXBOX: A modern elrendezés alapja */
display: flex; /* Bekapcsolja a rugalmas elrendezést */
/* IGAZÍTÁS A FLEXEN BELÜL */
justify-content: center; /* Vízszintesen középre teszi a gyerek elemeket */
align-items: center; /* Függőlegesen középre igazít */
flex-direction: row; /* Alapértelmezett: egymás mellé rakja az elemeket */
flex-wrap: wrap; /* Ha nem férnek el, új sorba törnek */
}
.block-elem {
display: block; /* Teljes szélesség, új sor (alapértelmezett a div-nél) */
}
.pozicionalas {
position: relative; /* Marad a helyén, de eltolható */
position: absolute; /* Kiszakad a folyamból, a szülőhöz igazodik */
z-index: 10; /* Rétegrend (magasabb szám van felül) */
}
6. Reszponzivitás (@media screen)
A reszponzivitás lényege, hogy a weboldal alkalmazkodik a képernyő méretéhez. Ezt a @media szabállyal érjük el, ahol meghatározzuk a „töréspontokat” (breakpoints).
| Eszköz | Mérettartomány (Szélesség) | @media szabály |
|---|---|---|
| Mobil | 0px - 767px | @media screen and (max-width: 767px) |
| Tablet | 768px - 991px | @media screen and (min-width: 768px) |
| Desktop (Monitor) | 992px felett | @media screen and (min-width: 992px) |
/* ALAPSTÍLUS (Általában Desktopra tervezünk először) */
.doboz { width: 33%; float: left; }
/* MOBIL NÉZET (Ha a képernyő kisebb, mint 768px) */
@media screen and (max-width: 767px) {
.doboz {
width: 100%; /* Mobilon ne legyenek egymás mellett, töltsék ki a szélességet */
float: none;
}
body { font-size: 14px; } /* Kisebb betűk mobilon */
}
/* TABLET NÉZET (768px és 991px között) */
@media screen and (min-width: 768px) and (max-width: 991px) {
.doboz { width: 50%; } /* Tableten ketten legyenek egymás mellett */
}
6. Gyakorlati Példák: Kép és Szöveg (Vizsgafeladatok)
Iskolai feladatokban és vizsgákon szinte mindig előkerül a képek és bekezdések egymáshoz igazítása. Íme a 3 leggyakoribb feladattípus, közvetlenül a HTML tagek (img, p) formázásával!
A trükk: A képre rárakjuk a float: left; tulajdonságot. Hogy a szöveg ne tapadjon rá teljesen a képre, teszünk a kép jobb oldalára és aljára egy kis külső margót.
img {
float: left; /* A kép balra "lebeg", a szöveg mellette folyik */
margin-right: 15px; /* Távolság a kép jobb oldalán a szövegtől */
margin-bottom: 10px; /* Távolság a kép alján a szövegtől */
}
p {
text-align: justify; /* Vizsgákon gyakori kérés: sorkizárt bekezdés */
}
A trükk: Pont a fordítottja. A képet jobbra lebegtetjük (float: right;), és most a kép BAL oldalára kérünk margót, hogy a szöveg ne lógjon bele.
img {
float: right; /* A kép jobbra kerül */
margin-left: 15px; /* Most a bal oldalra kell a távolság! */
margin-bottom: 10px; /* Alulra ugyanúgy hagyunk egy kicsit */
}
p {
text-align: justify;
}
A tipikus vizsgacsapda: A képek alapból olyanok, mint a betűk (inline elemek), így a margin: 0 auto; nem működik rajtuk! Először blokk szintűvé (dobozzá) kell alakítani a képet a display: block; segítségével, és csak utána lehet margóval középre tolni. Ilyenkor a szöveg nem futja körbe, hanem szépen alatta folytatódik.
img {
display: block; /* 1. lépés: Csináljunk dobozt a képből! (KÖTELEZŐ) */
margin-left: auto; /* 2. lépés: Bal oldali margó automatikus */
margin-right: auto; /* 3. lépés: Jobb oldali margó automatikus */
/* (Röviden írva: margin: 0 auto; - ez is tökéletes megoldás) */
margin-top: 20px; /* Távolság a felette lévő bekezdéstől */
margin-bottom: 20px; /* Távolság az alatta lévő bekezdéstől */
}
p {
text-align: center; /* Opcionális: A bekezdés is középre legyen igazítva */
}
Ha körbefuttatod a képet a float segítségével, előfordulhat, hogy a következő feladat (pl. a lábléc vagy egy új címsor) is felcsúszik a kép mellé! Ezt a clear tulajdonsággal lehet letiltani egy másik elemen (pl. a láblécen).
footer {
clear: both; /* Visszaállítja a rendet: ez az elem már garantáltan új sorba kerül, a kép alá! */
}
6. Gyakorlati Példák (Tipikus Vizsgafeladatok)
Ezek az elrendezések szinte minden webfejlesztős vizsgán (ágazati, érettségi) előkerülnek. Tisztán, csak HTML tag-ekre (class és ID nélkül) hivatkozva készítettük el őket.
img {
float: left; /* A kép balra "lebeg" */
margin-right: 15px; /* Távolság a kép jobb oldalán */
margin-bottom: 10px; /* Távolság a kép alján */
}
p {
text-align: justify; /* Sorkizárt bekezdés */
}
img {
display: block; /* Dobozzá kell alakítani a képet! */
margin: 0 auto; /* Bal-jobb margó automatikus (középre húzza) */
margin-bottom: 20px; /* Távolság az alatta lévő bekezdéstől */
}
A feladat: Van egy <header> taged, amiben van egy <h1>. A headernek egy képet kell kapnia háttérként, a szövegnek pedig középen kell lennie, jól olvashatóan.
header {
background-image: url('fejlec-hatter.jpg'); /* A kép elérési útja */
background-size: cover; /* Kitölti az egész headert torzulás nélkül */
background-position: center; /* A kép közepe látszódjon */
padding: 100px 0; /* Fent-lent nagy belső tér, hogy legyen magassága a fejlécnek! */
}
h1 {
text-align: center; /* Címsor középre zárása */
color: white; /* Legyen fehér a betű, hogy elüssön a képtől */
text-shadow: 2px 2px 5px black; /* Fekete árnyék a betűknek (KÖTELEZŐ, ha a kép színes!) */
margin: 0; /* Alapértelmezett margó levétele */
}
A feladat: A weboldal tartalma ne menjen ki a képernyő legszéléig, hanem alkosson egy középre zárt, jól olvasható "papírlap" hatású oszlopot.
body {
background-color: #f4f4f4; /* Világosszürke háttér az egész oldalnak */
}
main {
width: 80%; /* Csak a képernyő 80%-át foglalja el */
max-width: 1200px; /* De sosem lesz szélesebb 1200 pixelél (óriás monitorokon is szép marad) */
margin: 20px auto; /* 20px távolság fentről/lentről, és AUTO balról/jobbról (EZ TESZI KÖZÉPRE!) */
background-color: white; /* Legyen fehér a tartalom háttere, hogy kiemelkedjen a body szürkeségéből */
padding: 30px; /* Belső margó, hogy a szöveg ne tapadjon rá a fehér doboz szélére */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* Egy kis finom árnyék (vizsgán plusz pont járhat érte!) */
}
HTML Kisokos (Ritkább tagek és attribútumok)
A HTML nem csak bekezdésekből (p) és div-ekből áll. A szemantikus tagek és a speciális tulajdonságok (attribútumok) segítik a böngészőket, a keresőmotorokat és a vakok képernyőolvasóit is.
1. Idézetek és Különleges Szövegformázások
Ezekkel a tagekkel sokkal pontosabban írhatod le a szöveged jelentését, mintha csak sima span-eket vagy div-eket használnál.
<!-- Hosszú, blokk szintű idézet (automatikusan beljebb húzza a böngésző) -->
<blockquote cite="https://forras-weboldal.hu">
A programozás nem arról szól, amit tudsz, hanem arról, amit meg tudsz oldani.
</blockquote>
<!-- Rövid, sorközi idézet (automatikusan idézőjeleket tesz köré) -->
Azt mondta: <q>Szeretem a kávét</q>.
<!-- Mű, könyv vagy cikk címének hivatkozása (általában dőlt betűs) -->
Kedvenc könyvem a <cite>Gyűrűk Ura</cite>.
<!-- Rövidítés megadása (ha fölé viszed az egeret, kiírja a teljes nevet) -->
A <abbr title="HyperText Markup Language">HTML</abbr> nagyon hasznos.
<!-- Kiemelés (alapértelmezetten sárga filces kihúzás) -->
Kérlek, hozd el a <mark>piros mappát</mark>!
<!-- Billentyűzet-parancs jelzése a szövegben -->
A mentéshez nyomd meg a <kbd>Ctrl</kbd> + <kbd>S</kbd> gombot!
2. Interaktív és Szemantikus Tagek
Tudtad, hogy JavaScript nélkül is készíthetsz lenyíló (harmonika) menüt? Erre való a details és a summary.
<!-- Lenyíló menü (JavaScript nélkül!) -->
<details>
<summary>Kattints ide a részletekért!</summary>
<p>Ez a szöveg alapból rejtve van, és csak kattintásra nyílik le.</p>
</details>
<!-- Dátumok és idők gépek számára is értelmezhető formátumban -->
A találkozó <time datetime="2023-10-25T20:00">szerda este 8-kor</time> lesz.
<!-- Alsó index és felső index (Matekhoz vagy kémiához) -->
H<sub>2</sub>O <!-- A 2-es lent lesz (víz) -->
E = mc<sup>2</sup> <!-- A 2-es fent lesz (négyzet) -->
3. Hasznos és Egyedi Attribútumok (Tulajdonságok)
Bizonyos tagek egyedi tulajdonságokkal rendelkeznek, amikkel extra funkciókat adhatunk nekik. Illetve léteznek globális attribútumok (pl. title, hidden, data-*), amiket bármilyen tagen használhatsz.
<!-- LINKEK (A tag) SPECIÁLIS TULAJDONSÁGAI -->
<!-- target="_blank": Új lapon nyitja meg a linket -->
<a href="https://google.com" target="_blank">Kereső</a>
<!-- download: Nem megnyitja, hanem letölti a fájlt (megadhatod a letöltött fájl nevét is) -->
<a href="konyv.pdf" download="Harry_Potter.pdf">Könyv letöltése</a>
<!-- KÉPEK (IMG) SPECIÁLIS TULAJDONSÁGAI -->
<!-- loading="lazy": Csak akkor tölti be a képet, ha a felhasználó odagörget (gyorsítja az oldalt!) -->
<!-- alt="...": KÖTELEZŐ! Ha nem tölt be a kép, ezt írja ki, és a vakok felolvasója is ezt olvassa. -->
<img src="nagy-kep.jpg" alt="Egy szép hegyvidék" loading="lazy">
<!-- INPUT (ŰRLAP MEZŐK) SPECIÁLIS TULAJDONSÁGAI -->
<!-- placeholder: Halvány segítő szöveg a mezőben -->
<!-- required: Kötelező kitölteni űrlapküldés előtt -->
<!-- readonly / disabled: Csak olvasható, nem módosítható -->
<input type="text" placeholder="Írd ide a neved..." required>
<input type="email" value="titkos@email.hu" disabled>
<!-- GLOBÁLIS ATTRIBÚTUMOK (Bármin használhatóak) -->
<!-- title: Kicsi sárga tooltip jelenik meg az egér rávitelekor -->
<div title="Ez egy rejtett üzenet!">Vidd fölém az egeret!</div>
<!-- hidden: Eltünteti az elemet (olyan, mint a CSS display: none;) -->
<p hidden>Ez a bekezdés nem látszik az oldalon.</p>
<!-- data-* attribútumok: Saját, egyedi adatokat tárolhatsz a tagben JavaScript számára! -->
<button data-id="45" data-role="admin" onclick="olvasdKi()">Törlés</button>
0. Alapvető HTML Építőelemek
Minden weboldal két fő részből áll: a Fejrészből (<head>), ami a gépnek és a böngészőnek szól, valamint a Testből (<body>), amibe a tényleges, látogatók által látható tartalom kerül.
A Fejrész (Head) Titkai
Ezek a tagek nem jelennek meg magán a weboldalon. Információt adnak a keresőknek (Google), betöltik a stílusokat, és beállítják az oldalt.
<title>: A weboldal címe. Ez jelenik meg a böngésző fülén és a Google keresési találataiban.<meta charset="UTF-8">: Kötelező! Ez biztosítja, hogy az ékezetes betűk (á, é, ű) helyesen jelenjenek meg.<meta name="viewport">: Felelős azért, hogy a weboldal mobilon is jól nézzen ki, és ne kelljen nagyítani az olvasáshoz.<meta name="description">: A weboldal rövid leírása. Ezt mutatja a Google a cím alatt a keresőben.<link rel="stylesheet">: Ezzel kötheted hozzá a külső CSS fájlodat (vagy pl. a Bootstrapet) az oldalhoz.<style>: Ha nem külső fájlt használsz, ide írhatod a belső CSS kódodat.<script>: JavaScript kódok vagy külső JS fájlok betöltésére szolgál (bár ezt gyakran a<body>aljára teszik a gyorsabb betöltés miatt).
<head>
<!-- Karakterkódolás és Mobil nézet beállítása -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- FAVICON: A böngésző fülén megjelenő kis ikon -->
<link rel="icon" type="image/x-icon" href="favicon.ico">
<title>Szuper Weboldal</title>
<link rel="stylesheet" href="style.css">
</head>
A Test (Body) Építőelemei
Itt található a lényeg. Kategóriákra bontottuk a leggyakrabban használt tageket!
<h1>-<h6>: Címsorok (Heading). Ah1a főcím,h6a legkisebb.<p>: Bekezdés (Paragraph). Folyószöveghez.<br>: Sortörés (Break). Nincs lezáró párja.<hr>: Vízszintes elválasztó vonal. Nincs lezáró párja.<strong>vagy<b>: Félkövér szöveg.<em>vagy<i>: Dőlt szöveg.
<h1>Üdvözöllek!</h1>
<p>Ez egy <strong>fontos</strong> üzenet.<br>
Itt folyatódik a <em>következő</em> sorban.</p>
<hr>
<ul>: Rendezetlen (pöttyös) lista (Unordered List).<ol>: Rendezett (számozott) lista (Ordered List).<li>: Listaelem. Csakulvagyolbelsejében lehet!
<ul>
<li>Első pöttyös elem</li>
<li>Második pöttyös elem</li>
</ul>
<ol>
<li>Első számozott elem</li>
</ol>
<div>: Egy "üres" doboz. Új sort kezd (blokk szintű). Általában stílusozásra használjuk.<span>: Sorközi (inline) tároló. Nem kezd új sort, csak egy szót/kifejezést fog közre stílusozáshoz.<header>,<footer>: A weboldal (vagy egy szekció) fejléce és lábléce.<main>: Az oldal fő, egyedi tartalma ide kerül.<section>: Egy tematikus blokk (pl. "Rólunk", "Szolgáltatások").<nav>: A navigációs menü tárolója.
<header>
<nav>Főmenü helye</nav>
</header>
<main>
<section>
<div class="doboz">Tartalom <span style="color:red">piros</span> szóval.</div>
</section>
</main>
<a>: Hivatkozás (Link). Ahref=""attribútum mondja meg, hova mutasson.<img>: Kép. Azsrc=""adja meg a kép útvonalát, azalt=""a leírását. Nincs lezáró párja!<iframe>: Másik weboldal (pl. YouTube videó vagy Google Térkép) beágyazása.<video>/<audio>: Videó és hangfájl lejátszása a böngészőben.
<a href="https://google.hu">Kattints ide</a>
<img src="fenykep.kiterjesztes" alt="kep" width="300">
<video controls>
<source src="film.mp4" type="video/mp4">
</video>
<table>: Maga a táblázat tárolója.<tr>: Táblázat sora (Table Row).<th>: Fejléc cella (Table Head). Félkövér és középre zárt alapból.<td>: Sima adat cella (Table Data).
<table border="1">
<tr>
<th>Fejlecszoveg#1</th>
<th>Fejlecszoveg#2</th>
</tr>
<tr>
<td>Kitoltoszoveg#1</td>
<td>Kitoltoszoveg#2</td>
</tr>
</table>
<form>: Az űrlap tárolója.<input>: Beviteli mező (szöveg, jelszó, checkbox, rádiógomb stb. atypealapján).<label>: A mezőhöz tartozó felirat. (Rákattintva belekattint a mezőbe).<select>&<option>: Legördülő lista és az elemei.<button>: Kattintható gomb.
<form>
<label>Neved:</label>
<input type="text" placeholder="Ide írj...">
<select>
<option>Opció 1</option>
<option>Opció 2</option>
</select>
<button type="submit">Küldés</button>
</form>