Grafikus C# – Windows Forms tanfolyam › 4.4 lecke

Windows Forms · 4.4 · önálló gyakorlás

Önálló feladat IV.: Számológép grafikus felülettel

A számológép első ránézésre egyszerű, valójában kitűnő gyakorlófeladat: sok gomb, közös eseménykezelők, a program állapotának kezelése (mit nyomtál előbb, melyik művelet vár), hibakezelés (nullával osztás) és a számok pontossága. Ebben a feladatban a leírás, a pontozás és a támpontok a tieid, a teljes megoldást a végén lenyitható részben találod.

  • 120 perc
  • önálló munka
  • 100 pontos feladat
Diáklány C# programot készít laptopon

A feladat végére

  • közös eseménykezelőt használsz sok gombhoz (sender, Button típusátalakítás);
  • a program állapotát mezőkben tárolod (előző szám, művelet, új szám kezdése);
  • kezeled a hibákat (nullával osztás, túl hosszú szám, érvénytelen bevitel);
  • a billentyűzetet is támogatod (KeyPreview, KeyPress, KeyDown);
  • a számok kijelzését formázod, és tudod, miért pontatlan a double;
  • tesztlistával és önértékeléssel ellenőrzöd a munkád.

Mielőtt elkezded

Ehhez a feladathoz az 1. fejezet leckéire támaszkodsz, különösen az 1.3 (számolás, TryParse), 1.4 (közös eseménykezelő), 1.10 (visszajelzések) és 1.13 (kalkulátor) leckékre. Készíts új, tiszta projektet.

1.13 Adatbekérő és kalkulátor →

A feladat leírása

Készíts Számológép nevű Windows Forms alkalmazást. Az ablak felső részén egy kijelző (Label) mutatja az aktuális számot, alatta gombok sorakoznak: számjegyek (0–9), tizedesjel, négy művelet (+, -, ×, ÷), egyenlőség, C (mindent töröl), ⌫ (az utolsó számjegyet törli) és ± (előjelváltás). Egy kis lista (ListBox) mutatja az előzményeket (12 + 8 = 20). A számológép úgy viselkedik, ahogy egy egyszerű zsebszámológép: a műveleteket láncolni lehet (2 + 3 × 4 = a számológépeken balról jobbra halad: 20).

📷 Képernyőkép helye

Mit tegyél ide: egy rajzolt terv a számológépről: felül a kijelző, alatta a gombok rácsban (4 sor, 4 oszlop), a jobb oldalon az előzménylista.Javasolt fájlnév: winforms-4-4-terv.webp · Alt szöveg: A számológép elrendezési terve

Követelmények és pontozás

RészKövetelményPont
Alapműködés (40)A 0–9 gombok és a tizedesjel a kijelzőre írnak; a kezdő 0 nem marad előtte (05 helyett 5); a tizedesjelet egy szám csak egyszer kaphatja.15
Négy művelet és az egyenlőség helyes eredményt ad (12 + 8 = → 20).15
Az eredmény kijelzése formázott: nincs felesleges nulla, és a 0,1 + 0,2 eredménye 0,3.10
Kezelés (30)A C mindent töröl, a ⌫ az utolsó számjegyet, a ± az előjelet váltja.10
Láncolt műveletek: 2 + 3 × 4 = → 20 (balról jobbra), és az egyenlőség után az eredménnyel lehet tovább számolni.10
Nullával osztás: érthető hibaüzenet a kijelzőn, a program nem omlik össze, a következő gombnyomás újrakezdi.10
Haladó (30)Közös eseménykezelő a számjegy- és a műveletgombokhoz (egyetlen metódus mind a tíz számjegygombra).10
Billentyűzet-támogatás: számjegyek, műveletek (+ - * /), Enter, Backspace, Esc.10
Előzménylista: minden kiszámolt művelet bekerül (legújabb felül), a lista egy elemére duplán kattintva az eredmény a kijelzőre kerül.10

Összesen: 100 pont.

Tervezd meg előbb az állapotot!

A számológép nehézsége nem a gombok sokaságában van, hanem abban, hogy a program emlékszik: mi az előző szám, melyik művelet vár, és a következő számjegy új számot kezd-e. Gondold végig papíron, hogy a 2 + 3 = sorban a négy gombnyomás után mi áll a három mezőben, mielőtt kódolnál.

Időbeosztás (120 perc)

PercMit csinálj?
0–15Tervezd meg az ablakot és az állapotmezőket (papíron). Írd fel a gombok neveit (előtagos névvel).
15–35Építsd fel a felületet: kijelző, 10 számgomb, tizedesjel, négy művelet, egyenlőség, C, ⌫, ±, előzménylista. Használj TableLayoutPanel-t vagy kézi igazítást, a gombok legyenek egyforma méretűek.
35–55A számjegy- és tizedesgombok: egy közös eseménykezelő, a kezdő nulla és a tizedesjel szabálya.
55–80A műveletek és az egyenlőség: állapotmezők, láncolás, formázott kijelzés, nullával osztás.
80–95C, ⌫, ± és az előzménylista.
95–110Billentyűzet-támogatás: ugyanazokat a metódusokat hívd, mint a gombok.
110–120Tesztlista végigpróbálása és javítás.

Támpontok (kész megoldás nélkül)

Mit tárolj mezőben?
MezőTípusSzerepe
elozodoubleA művelet bal oldali száma (az előző beírt szám vagy részeredmény).
muveletstringA várakozó művelet jele (+, -, ×, ÷), vagy üres, ha nincs.
ujSzamKezdesboolIgaz, ha a következő számjegy új számot kezd (művelet vagy egyenlőség után).
hibaboolIgaz, ha a kijelzőn hibaüzenet áll: a következő gomb újrakezdi a számolást.
Közös eseménykezelő a számgombokra

Jelöld ki mind a tíz számgombot a tervezőben, és a Click eseményüknél válaszd ugyanazt a metódust. A metóduson belül a sender paraméter a megnyomott gomb: Button gomb = (Button)sender;, a számjegyet a gomb.Text adja.

Felesleges nulla és a tizedesjel

Ha a kijelző 0 és nem tizedesjelet írsz, a 0 helyére kerül a számjegy. A tizedesjelet csak akkor írhatod, ha a kijelzett szám még nem tartalmaz (Text.Contains(...)). A tizedesjel karaktere a gép nyelvi beállításától függ: CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.

Műveletgomb: láncolás

Ha már van várakozó művelet és a felhasználó közben új számot írt be, előbb ki kell számolni a részeredményt (elozo és az új szám), és az lesz az új elozo. Egyébként az aktuális szám az elozo. Utána tárold el az új műveletet, és állítsd be: a következő számjegy új számot kezd.

A számok pontossága és a formázás

A double bináris számként tárolja a tizedes törteket, ezért a 0,1 + 0,2 eredménye 0,30000000000000004 is lehet. Kijelzéskor kerekíts (Math.Round(szam, 10)), és formázd úgy, hogy a felesleges nullák eltűnjenek (ToString("0.##########")). A pontos megoldás a decimal típus (lásd a Gyakorlótárat).

Billentyűzet

A Form KeyPreview tulajdonsága legyen True. A karaktereket (e.KeyChar) a KeyPress, a vezérlőbillentyűket (Enter, Backspace, Esc) a KeyDown esemény adja. Mindkét esetben a gombok kódját is hívó, közös metódusokat használd (például SzamBeiras("7")), ne ismételd meg a logikát. Vigyázz: a fókuszban lévő gombot a szóköz és az Enter megnyomja; állítsd az eseményt kezeltre (e.Handled = true, illetve e.SuppressKeyPress = true).

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.

Megoldás: a felület és a nevek
Vezérlő(Name)Beállítás
FormForm1KeyPreview: True; Text: Számológép; FormBorderStyle: FixedSingle; MaximizeBox: False
LabellblKijelzoText: 0; AutoSize: False; TextAlign: MiddleRight; nagy betű (Font), BorderStyle: Fixed3D
Button ×10btn0 … btn9Text: 0 … 9; mind a SzamGomb_Click metódust hívja
ButtonbtnTizedesText: a tizedesjel (,)
Button ×4btnPlusz, btnMinusz, btnSzor, btnOsztText: +, -, ×, ÷; mind a MuveletGomb_Click metódust hívja
ButtonbtnEgyenlo, btnC, btnTorles, btnElojelText: =, C, ⌫, ±
ListBoxlstElozmenyaz előzményekhez
Megoldás: Form1.cs (teljes kód)
Form1.csC#
using System;
using System.Globalization;
using System.Windows.Forms;

namespace Szamologep
{
public partial class Form1 : Form
{
private double elozo = 0;
private string muvelet = "";
private bool ujSzamKezdes = true;
private bool hiba = false;

private readonly string tizedesjel = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
btnTizedes.Text = tizedesjel;
lblKijelzo.Text = "0";
}

// ---- segédmetódusok ----

private double Aktualis()
{
double szam;

if (double.TryParse(lblKijelzo.Text, NumberStyles.Float, CultureInfo.CurrentCulture, out szam))
{
return szam;
}

return 0;
}

private string Formaz(double szam)
{
return Math.Round(szam, 10).ToString("0.##########", CultureInfo.CurrentCulture);
}

private void Hibaja(string uzenet)
{
lblKijelzo.Text = uzenet;
hiba = true;
elozo = 0;
muvelet = "";
ujSzamKezdes = true;
}

private void Mindent_Torol()
{
lblKijelzo.Text = "0";
elozo = 0;
muvelet = "";
ujSzamKezdes = true;
hiba = false;
}

private double Szamol(double a, double b, string m, out bool siker)
{
siker = true;

if (m == "+")
{
return a + b;
}

if (m == "-")
{
return a - b;
}

if (m == "×")
{
return a * b;
}

if (m == "÷")
{
if (b == 0)
{
siker = false;
return 0;
}

return a / b;
}

return b; // nincs várakozó művelet: az új szám az eredmény
}

// ---- közös műveletek (gombok és billentyűzet is ezeket hívja) ----

private void SzamBeiras(string jegy)
{
if (hiba)
{
Mindent_Torol();
}

if (ujSzamKezdes || lblKijelzo.Text == "0")
{
lblKijelzo.Text = jegy;
}
else if (lblKijelzo.Text.Replace("-", "").Length < 15)
{
lblKijelzo.Text = lblKijelzo.Text + jegy;
}

ujSzamKezdes = false;
}

private void TizedesBeiras()
{
if (hiba)
{
Mindent_Torol();
}

if (ujSzamKezdes)
{
lblKijelzo.Text = "0" + tizedesjel;
ujSzamKezdes = false;
}
else if (!lblKijelzo.Text.Contains(tizedesjel))
{
lblKijelzo.Text = lblKijelzo.Text + tizedesjel;
}
}

private void MuveletValaszt(string uj)
{
if (hiba)
{
return;
}

double akt = Aktualis();

if (muvelet != "" && !ujSzamKezdes)
{
bool siker;
double eredmeny = Szamol(elozo, akt, muvelet, out siker);

if (!siker)
{
Hibaja("Nullával nem lehet osztani");
return;
}

elozo = eredmeny;
lblKijelzo.Text = Formaz(eredmeny);
}
else
{
elozo = akt;
}

muvelet = uj;
ujSzamKezdes = true;
}

private void Egyenlo()
{
if (hiba || muvelet == "")
{
return;
}

double akt = Aktualis();
bool siker;
double eredmeny = Szamol(elozo, akt, muvelet, out siker);

if (!siker)
{
Hibaja("Nullával nem lehet osztani");
return;
}

lstElozmeny.Items.Insert(0, $"{Formaz(elozo)} {muvelet} {Formaz(akt)} = {Formaz(eredmeny)}");

lblKijelzo.Text = Formaz(eredmeny);
elozo = eredmeny;
muvelet = "";
ujSzamKezdes = true;
}

private void UtolsoTorlese()
{
if (hiba)
{
Mindent_Torol();
return;
}

if (ujSzamKezdes)
{
return;
}

string szoveg = lblKijelzo.Text;

if (szoveg.Length <= 1 || (szoveg.Length == 2 && szoveg.StartsWith("-")))
{
lblKijelzo.Text = "0";
ujSzamKezdes = true;
}
else
{
lblKijelzo.Text = szoveg.Substring(0, szoveg.Length - 1);
}
}

private void ElojelValt()
{
if (hiba || lblKijelzo.Text == "0")
{
return;
}

if (lblKijelzo.Text.StartsWith("-"))
{
lblKijelzo.Text = lblKijelzo.Text.Substring(1);
}
else
{
lblKijelzo.Text = "-" + lblKijelzo.Text;
}
}

// ---- gombok ----

private void SzamGomb_Click(object sender, EventArgs e)
{
Button gomb = (Button)sender;
SzamBeiras(gomb.Text);
}

private void MuveletGomb_Click(object sender, EventArgs e)
{
Button gomb = (Button)sender;
MuveletValaszt(gomb.Text);
}

private void btnTizedes_Click(object sender, EventArgs e) { TizedesBeiras(); }
private void btnEgyenlo_Click(object sender, EventArgs e) { Egyenlo(); }
private void btnC_Click(object sender, EventArgs e) { Mindent_Torol(); }
private void btnTorles_Click(object sender, EventArgs e) { UtolsoTorlese(); }
private void btnElojel_Click(object sender, EventArgs e) { ElojelValt(); }

// ---- billentyűzet ----

private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsDigit(e.KeyChar))
{
SzamBeiras(e.KeyChar.ToString());
e.Handled = true;
}
else if (e.KeyChar == ',' || e.KeyChar == '.')
{
TizedesBeiras();
e.Handled = true;
}
else if (e.KeyChar == '+')
{
MuveletValaszt("+");
e.Handled = true;
}
else if (e.KeyChar == '-')
{
MuveletValaszt("-");
e.Handled = true;
}
else if (e.KeyChar == '*')
{
MuveletValaszt("×");
e.Handled = true;
}
else if (e.KeyChar == '/')
{
MuveletValaszt("÷");
e.Handled = true;
}
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
Egyenlo();
e.SuppressKeyPress = true;
e.Handled = true;
}
else if (e.KeyCode == Keys.Back)
{
UtolsoTorlese();
e.SuppressKeyPress = true;
e.Handled = true;
}
else if (e.KeyCode == Keys.Escape)
{
Mindent_Torol();
e.SuppressKeyPress = true;
e.Handled = true;
}
}

// ---- előzmény ----

private void lstElozmeny_DoubleClick(object sender, EventArgs e)
{
if (lstElozmeny.SelectedItem == null)
{
return;
}

string sor = lstElozmeny.SelectedItem.ToString();
int egyenlo = sor.LastIndexOf('=');

if (egyenlo >= 0)
{
lblKijelzo.Text = sor.Substring(egyenlo + 1).Trim();
ujSzamKezdes = true;
muvelet = "";
hiba = false;
}
}
}
}
Megoldás: miért így épül fel?

A számológép egy állapotgép: a viselkedés attól függ, mi történt előtte (elozo, muvelet, ujSzamKezdes, hiba). A gombok és a billentyűzet ugyanazokat a metódusokat hívják (SzamBeiras, MuveletValaszt, Egyenlo), így a logika egyszer van megírva. A kijelzés formázása (Formaz) megoldja a double pontatlanságát. A hibát (Hibaja) egy jelző jegyzi meg, és a következő gombnyomás újrakezdi a számolást. A szabály: a MuveletValaszt a láncolást is kezeli, ezért a 2 + 3 × 4 balról jobbra számolódik (20).

Tesztlista

#Teszt (gombnyomások)Várt kijelző
10 55 (nincs kezdő nulla)
23 , 1 4 , 5 (kétszeri tizedesjel)3,145 (a második tizedesjel nem kerül be)
312 + 8 =20
40,1 + 0,2 =0,3
52 + 3 × 4 =20 (balról jobbra)
67 - 10 =-3
71 ÷ 4 =0,25
85 ÷ 0 =Hibaüzenet, nem omlik össze; következő gombnyomás újrakezd
99 = (nincs művelet)9, nem történik semmi
102 + 3 = majd × 4 =20 (az eredménnyel tovább számol)
111 2 3 ⌫12
125 ± majd ±-5, majd 5
13C egy számítás közben0, minden állapot törölve
14Billentyűzet: 7 * 6 Enter42
15Előzmények: két számítás után a lista tetején a legutóbbiDupla kattintás az eredményt a kijelzőre teszi
16Nagyon hosszú szám (több mint 15 számjegy)A kijelző nem csordul túl

Gyakori hibák és önértékelés

Ezeken szoktak elcsúszni

Gondold végig, nálad előfordul-e valamelyik.

1. A számjegyek hozzáfűződnek az előző eredményhez

Egy művelet után az új számjegy az előző szám mellé kerül (2 + 3 = után a 7 megnyomására 57 lesz).

Ok és javítás

Hiányzik az ujSzamKezdes jelző: művelet vagy egyenlőség után a következő számjegynek a kijelzőt felül kell írnia, nem hozzáfűznie.

2. A 0,1 + 0,2 eredménye 0,30000000000000004

A kijelzőn hosszú tizedes tört látszik.

Ok és javítás

A double bináris tárolása pontatlan a tizedes törteknél. Kerekítsd az eredményt kijelzés előtt (Math.Round(szam, 10)), és formázd (ToString("0.##########")), vagy használj decimal típust.

3. Nullával osztásnál összeomlik a program

int eredmeny = a / b;   // DivideByZeroException (egész számoknál)
Hiba és javítás

Az egész számok osztása nullával kivételt dob. A double osztás nullával nem kivétel, hanem végtelent ad (∞): ez sem jó eredmény. A helyes megoldás: osztás előtt ellenőrizd, hogy a nevező nem nulla, és ha az, jelezz hibát.

4. A tizedesjel nem működik

Magyar nyelvű Windowson a program 3.5 szöveget nem alakítja számmá.

Ok és javítás

A double.TryParse a gép nyelvi beállítása szerint értelmez: magyar környezetben a tizedesjel a vessző. A tizedesjel gombja is ezt a karaktert írja (NumberDecimalSeparator), így a kijelzett szöveg mindig értelmezhető.

5. A számjegyek gombja lemarad

A 7-es gombra kattintva nem történik semmi.

Ok és javítás

A btn7 Click eseménye nincs a közös SzamGomb_Click metódushoz kötve. Jelöld ki a gombot, és az Events nézetben a Click sornál válaszd ki a közös metódust a listából.

6. Az Enter gomb duplán működik

A billentyűzeten az Enter megnyomására a fókuszban lévő gomb is megnyomódik, és a számítás kétszer fut.

Ok és javítás

Az Enter a fókuszban lévő gombot is működteti. A KeyDown eseményben állítsd be a e.SuppressKeyPress = true; sort, hogy a billentyű ne jusson el a gombhoz.

Az értékeléshez ellenőrizd az alábbi szempontokat is:

MűködésA tesztlista mind a 16 pontja teljesül.
SzerkezetA gombok és a billentyűzet közös metódusokat használnak; nincs kétszer megírt logika.
HibakezelésNullával osztás, hosszú szám és hibás állapot után is használható a program.
Kód és nevekBeszédes nevek, rövid eseménykezelők, a segédmetódusok szétválasztva.

Bővítési ötletek, ha kész vagy

Ha maradt időd, próbáld ki:

  • Százalék és gyökvonás: egy % és egy √ gomb (negatív számnál hibaüzenettel).
  • Memória: M+, M-, MR, MC gombok egy memoria mezővel.
  • Pontos számolás: a double helyett decimal típus (a Gyakorlótárban).
  • Téma: sötét és világos kinézet menüből (1.7 lecke).
  • Vágólap: az eredmény másolása a vágólapra (2.13 lecke).

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. A feladatokhoz a kész számológép szükséges. Csak a próbálkozás után nyisd le a megoldást.

Alap szint

1. Négyzetgyök gomb

Egy btnGyok gomb a kijelzett szám négyzetgyökét írja a kijelzőre. Negatív számnál hibaüzenet jelenjen meg.

Megoldás megnyitása

A Math.Sqrt negatív számra NaN eredményt ad, ezért előbb ellenőrizünk. Az eredmény után az új szám kezdődik (ujSzamKezdes).

Form1.csC#
private void btnGyok_Click(object sender, EventArgs e)
{
if (hiba)
{
return;
}

double akt = Aktualis();

if (akt < 0)
{
Hibaja("Érvénytelen bevitel");
return;
}

lblKijelzo.Text = Formaz(Math.Sqrt(akt));
ujSzamKezdes = true;
}

2. Reciprok gomb

Egy btnReciprok (1/x) gomb az 1 osztva a kijelzett számmal értéket számolja ki. Nullánál hibaüzenet.

Megoldás megnyitása

Ugyanaz a minta, mint a gyökvonásnál: előbb a nullát zárjuk ki, utána számolunk.

Form1.csC#
private void btnReciprok_Click(object sender, EventArgs e)
{
if (hiba)
{
return;
}

double akt = Aktualis();

if (akt == 0)
{
Hibaja("Nullával nem lehet osztani");
return;
}

lblKijelzo.Text = Formaz(1 / akt);
ujSzamKezdes = true;
}

Közepes szint

3. Memória gombok

Készíts négy gombot: M+ (a kijelzett szám hozzáadása a memóriához), M- (kivonás), MR (a memória kijelzése) és MC (a memória törlése). Egy lblMemoria mutassa, hogy van-e érték a memóriában.

Megoldás megnyitása

A memória egy új mező. Az MR a memória értékét a kijelzőre írja, és új számot kezd.

Form1.csC#
private double memoria = 0;
private bool vanMemoria = false;

private void MemoriaFrissit()
{
lblMemoria.Text = vanMemoria ? "M" : "";
}

private void btnMPlusz_Click(object sender, EventArgs e)
{
memoria = memoria + Aktualis();
vanMemoria = true;
ujSzamKezdes = true;
MemoriaFrissit();
}

private void btnMMinusz_Click(object sender, EventArgs e)
{
memoria = memoria - Aktualis();
vanMemoria = true;
ujSzamKezdes = true;
MemoriaFrissit();
}

private void btnMR_Click(object sender, EventArgs e)
{
if (vanMemoria)
{
lblKijelzo.Text = Formaz(memoria);
ujSzamKezdes = true;
}
}

private void btnMC_Click(object sender, EventArgs e)
{
memoria = 0;
vanMemoria = false;
MemoriaFrissit();
}

4. Százalék gomb

A % gomb a zsebszámológépek szokása szerint működjön: 200 + 10 % a 200 tíz százalékát (20-at) adja hozzá, tehát az eredmény 220. Hogyan oldod meg?

Megoldás megnyitása

Ha + vagy - művelet vár, a százalék az elozo szám százalékát jelenti (elozo * akt / 100). Szorzásnál és osztásnál egyszerűen a szám századrésze (akt / 100). Utána az egyenlőség a megszokott módon számol.

Form1.csC#
private void btnSzazalek_Click(object sender, EventArgs e)
{
if (hiba)
{
return;
}

double akt = Aktualis();

if (muvelet == "+" || muvelet == "-")
{
akt = elozo * akt / 100;
}
else
{
akt = akt / 100;
}

lblKijelzo.Text = Formaz(akt);
ujSzamKezdes = false; // az érték a következő műveletben számít
}

Kihívás szint

5. Pontos számolás decimal típussal

Írd át a számológépet úgy, hogy a double helyett decimal típust használjon, és a 0,1 + 0,2 pontosan 0,3 legyen kerekítés nélkül. Mi a decimal hátránya?

Megoldás megnyitása

A decimal a tizedes számokat tízes számrendszerben tárolja, ezért a pénzügyi és hétköznapi számításoknál pontos. Hátránya, hogy lassabb és kisebb a tartománya (kb. 28–29 számjegy), és a Math.Sqrt és más Math függvények nem működnek rajta (double-re kell alakítani). A változtatások: elozo és a segédmetódusok típusa decimal, a TryParse is decimal változatot hív, és az osztás előtt ellenőrizzük a nullát (a decimal osztás nullával kivételt dob).

Form1.cs (részletek)C#
private decimal elozo = 0;

private decimal Aktualis()
{
decimal szam;

if (decimal.TryParse(lblKijelzo.Text, NumberStyles.Number, CultureInfo.CurrentCulture, out szam))
{
return szam;
}

return 0;
}

private string Formaz(decimal szam)
{
return szam.ToString("0.##########################", CultureInfo.CurrentCulture);
}

private decimal Szamol(decimal a, decimal b, string m, out bool siker)
{
siker = true;

if (m == "+") { return a + b; }
if (m == "-") { return a - b; }
if (m == "×") { return a * b; }

if (m == "÷")
{
if (b == 0)
{
siker = false;
return 0;
}

return a / b;
}

return b;
}

6. Tesztelés táblázattal

Állíts össze egy 10 soros tesztterv-táblázatot a számológép saját hibáinak felderítésére. Legyenek benne szélsőséges esetek is (nagy számok, nulla, negatív számok, tizedesek). Milyen eredményeket vársz?

Megoldás megnyitása
#GombnyomásokVárt kijelzőMit ellenőriz?
10 ÷ 5 =0Nulla osztása
25 ÷ 0 =HibaüzenetNullával osztás
30 , 0 0 1 + 0 , 0 0 2 =0,003Kis tizedes számok
49 9 9 9 9 9 9 9 × 9 9 9 9 9 9 9 9 =9,9999998E+15 vagy hasonlóNagy számok, kijelzés
5- 5 + 3 = (műveleti jellel kezdve)-2 vagy 3 (a programod döntése)Szokatlan bevitel kezelése
61 ÷ 3 =0,3333333333Végtelen tizedes tört
72 = = (kétszer egyenlőség)2Ismételt egyenlőség
85 ± ± ±-5Háromszori előjelváltás
95 + + 3 =8Ismételt műveletgomb
101 2 ⌫ ⌫ ⌫ ⌫0Túl sok törlés

Az 5. és a 9. sor eredménye a te tervezési döntésed: a szokatlan bevitelnél a program dönti el, mit tesz, de nem omolhat össze. A tesztterv célja az, hogy ezt a döntést tudatosan meghozd, és leírd.

Gyors önellenőrzés

Válaszolj fejben, és csak utána nyisd le a választ.

1. Mi az állapotgép, és mi az állapota a számológépnek?

Olyan program, amelynek viselkedése attól függ, mi történt korábban. A számológép állapota: az előző szám, a várakozó művelet, hogy új számot kezdünk-e, és hogy hiba van-e.

2. Hogyan használhatsz egyetlen eseménykezelőt tíz gombra?

A tervezőben mindegyik gomb Click eseményéhez ugyanazt a metódust választod. A sender a megnyomott gombot adja, amelyet Button típusra alakítunk.

3. Miért pontatlan a double a tizedes törteknél?

Mert bináris számrendszerben tárolja a számokat, és például a 0,1 nem írható le véges sok bináris számjeggyel. A decimal tízes számrendszerben tárol, ezért pontos.

4. Mire való a KeyPreview?

Ha True, a Form előbb megkapja a billentyűeseményeket, mint a rajta lévő vezérlők, így az ablak szintjén kezelheted a billentyűzetet.

5. Mi a különbség a KeyPress és a KeyDown között?

A KeyPress a beírt karaktert adja (e.KeyChar), a KeyDown a billentyűt (e.KeyCode), így a vezérlőbillentyűket (Enter, Esc) is látja.

6. Miért kell a gombok és a billentyűzet kódját közös metódusokba tenni?

Hogy a logika egyszer legyen megírva, és a két bevitel azonosan viselkedjen. Egy javítás mindkettőn érvényesül.

Mit tudsz már?

  • Önállóan felépítesz egy sok gombos alkalmazást közös eseménykezelőkkel.
  • A program állapotát mezőkben tartod nyilván.
  • Kezeled a hibákat és a pontatlan számolás problémáját.
  • A billentyűzetet is támogatod, a gombokkal közös kóddal.
  • Tesztterv alapján ellenőrzöd a saját munkád.

Következő feladat: egyszerű rajzolóalkalmazás

A számológép kész. A következő önálló feladatban rajzfelületet építesz egérrel és a Graphics osztály segítségével.