Grafikus C# – Windows Forms tanfolyam › 11.2 lecke

Windows Forms · 11.2 lecke · állapotjelzés

ProgressBar és állapotjelzés

Ha egy művelet több másodpercig tart, a felhasználónak tudnia kell: a program dolgozik, hol tart, és mikor lesz kész. Folyamatjelző nélkül az üres ablak összeomlásnak látszik, és a felhasználó újra kattint vagy bezárja a programot. A ProgressBar egyszerű vezérlő, a jó állapotjelzés viszont tervezést kíván: mikor határozott és mikor határozatlan a folyamat, hogyan számolsz százalékot és becsült hátralévő időt, mit mondasz szövegben (az akadálymentesség miatt is), és hogyan adsz vissza irányítást (megszakítás). Ebben a leckében a jelzést időzítővel darabolt munkával gyakoroljuk: így a felület szál közben is él. A valódi háttérmunka a 11.5–11.6 leckékben jön.

  • kb. 90 perc
  • közepes szint
  • folyamatjelzés
Diák C# programozást gyakorol egy tanulósarokban

A lecke végére

  • beállítod a ProgressBar tulajdonságait (Minimum, Maximum, Value, Step, PerformStep, Style);
  • megkülönbözteted a határozott (százalékos) és a határozatlan (Marquee) folyamatot, és tudod, mikor melyik való;
  • számolsz százalékot és becsült hátralévő időt (és tudod, mikor ne mutasd);
  • akadálymentes állapotjelzést adsz (szöveg, AccessibleName, nem csak szín);
  • a hosszú munkát időzítővel kis darabokra osztod, így a felület közben is él;
  • elkerülöd a tipikus hibákat (Value a tartományon kívül, hazudó jelző, hiányzó befejezés).

Mielőtt elkezded

Ehhez a leckéhez a 11.1 lecke (Timer, Stopwatch) és a 6.9 lecke (hozzáférhetőség) szükséges. A ProgressBar az 1.12 leckében már szerepelt.

11.1 Timer →

A ProgressBar beállításai

Tulajdonság / metódusJelentés
Minimum, MaximumA tartomány (alapból 0–100). A Maximum lehet a feldolgozandó elemek száma.
ValueAz aktuális érték: Minimum és Maximum között kell lennie, különben ArgumentOutOfRangeException.
Step és PerformStep()A Step értékével növeli a Value értékét (alapból 10).
Increment(n)A Value értékét n-nel növeli.
StyleBlocks (blokkos), Continuous (folytonos), Marquee (végigfutó sáv: határozatlan folyamat). Modern Windows-témában a rendszer saját kinézetét használja.
MarqueeAnimationSpeedA Marquee animációjának sebessége (ezredmásodperc; 0 = áll).
Form1.csC#
// határozott folyamat: elemek száma a Maximum, minden feldolgozott elem után a Value nő
pb.Minimum = 0;
pb.Maximum = fajlok.Length;
pb.Value = 0;
pb.Style = ProgressBarStyle.Continuous;

pb.Value = feldolgozott; // vagy pb.Increment(1);

// határozatlan folyamat: nem tudjuk, mennyi van hátra
pb.Style = ProgressBarStyle.Marquee;
pb.MarqueeAnimationSpeed = 30; // 0 = az animáció áll

// biztonságos érték (a tartományon kívüli érték kivételt dob)
private void Beallit(ProgressBar p, int ertek)
{
p.Value = Math.Max(p.Minimum, Math.Min(p.Maximum, ertek));
}

// ToolStripProgressBar az állapotsorban: ugyanezek a tulajdonságok
tspb.Maximum = 100;
tspb.Value = 40;
TartományA Maximum lehet a tényleges elemszám (1250 fájl), nem kell százalékra átszámolni: a vezérlő maga rajzolja az arányt. A százalékot a kiírt szöveghez számold.
Value kivételA Value beállítása a tartományon kívül ArgumentOutOfRangeException kivételt dob. Ha az érték lehet a határon kívül (kerekítés, 0 elem), szorítsd a tartományba (Math.Min, Math.Max), és ne oszd nullával a Maximum beállításakor (0 elemnél Maximum = 1).
MarqueeA Marquee stílus végigfutó sávot mutat: „dolgozom, de nem tudom, mennyi van hátra”. A Value ilyenkor nem számít. Visszaváltáskor Style = Continuous, és a Value beállítása.
Animáció késéseA modern Windows a Value változását rövid animációval mutatja: a jelző kicsit lemarad az értéktől. Ez a vezérlő viselkedése; a hamis gyorsítás (az érték előbb be- majd visszaállítása) hacknek számít, és nem megbízható. Az állapot-szöveg (lblSzazalek) mindig a valódi értéket mutassa.

Jósolj!

Egy mappában 0 fájl van, és a kód pb.Maximum = fajlok.Length; pb.Value = 1; módon dolgozik. Mi történik?

Jóslat ellenőrzése

ArgumentOutOfRangeException: a Maximum 0, a Value = 1 a tartományon kívül van. Üres bemenetnél ne indíts folyamatjelzést (Nincs feldolgozandó fájl üzenet), vagy szorítsd a tartományba.

Határozott és határozatlan folyamat

Határozott (százalékos)

Ismered az összes munkát: 500 fájl, 40 MB letöltés. A jelző tényleges arányt mutat, és becsülhető a hátralévő idő. Mindig ezt válaszd, ha lehetséges.

Határozatlan (Marquee)

Nem tudod előre a mennyiséget: ismeretlen méretű hálózati kérés, keresés, amely közben derül ki a találatok száma. A Marquee azt mondja: „dolgozom”, de nem ígér időt.

Gyakori jó megoldás a kétfázisú folyamat: az első fázis (az elemek megszámlálása) határozatlan, a második (feldolgozás) már határozott, mert ismert az összes. Ne hazudj a jelzővel: egy 0%-ról 90%-ra gyorsan futó, majd percekig álló jelző rosszabb a Marquee-nél.

Form1.csC#
// 1. fázis: számlálás (határozatlan)
private void FazisSzamlalas()
{
pb.Style = ProgressBarStyle.Marquee;
lblAllapot.Text = "Fájlok keresése...";
}

// 2. fázis: feldolgozás (határozott): az összes már ismert
private void FazisFeldolgozas(int osszes)
{
pb.Style = ProgressBarStyle.Continuous;
pb.Minimum = 0;
pb.Maximum = Math.Max(1, osszes);
pb.Value = 0;
lblAllapot.Text = "Feldolgozás...";
}

// befejezés: a jelző mutassa, hogy VÉGE (ne maradjon félúton vagy futó Marquee)
private void FazisKesz(string uzenet)
{
pb.Style = ProgressBarStyle.Continuous;
pb.Value = pb.Maximum;
lblAllapot.Text = uzenet;
}

Jósolj!

Egy program a Marquee sávot a művelet befejezése után is futni hagyja (nem állítja át). Mit gondol a felhasználó?

Jóslat ellenőrzése

Hogy a program még mindig dolgozik, vagy lefagyott: a végigfutó sáv „dolgozom” jelzés. Befejezéskor a jelzőt meg kell állítani (MarqueeAnimationSpeed = 0, Style = Continuous), és szövegesen jelezni: Kész.

Százalék és becsült hátralévő idő

Form1.cs (using System.Diagnostics;)C#
private Stopwatch ora = Stopwatch.StartNew();

private void Jelent(int kesz, int osszes, string mostani)
{
pb.Value = Math.Min(pb.Maximum, kesz);

double arany = osszes == 0 ? 1 : (double)kesz / osszes;
string szoveg = "" + kesz + " / " + osszes + " (" + arany.ToString("P0") + ")";

// a becslés csak akkor megbízható, ha már van elég mintánk (legalább 5%, legalább 3 másodperc)
if (arany >= 0.05 && ora.Elapsed.TotalSeconds >= 3 && kesz < osszes)
{
TimeSpan hatra = TimeSpan.FromSeconds(ora.Elapsed.TotalSeconds / arany - ora.Elapsed.TotalSeconds);

szoveg += ", még kb. " + Hatralevo(hatra);
}

lblSzazalek.Text = szoveg;
lblMostani.Text = mostani; // mit csinál éppen (fájlnév)
}

// emberi szöveg: "2 perc", "45 mp"; nem hamis pontosság ("2:13:07.4")
private string Hatralevo(TimeSpan t)
{
if (t.TotalSeconds < 5) { return "néhány másodperc"; }
if (t.TotalSeconds < 90) { return Math.Round(t.TotalSeconds / 5) * 5 + " mp"; }
if (t.TotalMinutes < 90) { return Math.Round(t.TotalMinutes) + " perc"; }

return Math.Round(t.TotalHours, 1) + " óra";
}
A becslés képleteHa a munka arany része készült el eltelt idő alatt, a teljes idő eltelt / arany, a hátralévő: ez mínusz az eltelt. A képlet azonos sebességet feltételez; változó méretű elemeknél (kis és nagy fájlok) pontatlan.
Mikor ne mutasd?Az elején (az első 5% és az első pár másodperc) a becslés ugrál és hamis. Inkább ne mutass semmit, mint egy 3 órás, majd 4 perces számot. Egy mozgóátlag (az utolsó 10 másodperc sebessége) kiegyenlíti az ingadozást.
KerekítésAz „1 perc 37,4 másodperc” hamis pontosságot sugall. A Hatralevo metódus a becsléshez illő nagyságrendre kerekít (kb. 2 perc).
Mit csinál éppenA számok mellett a jelenlegi elem (fájlnév) a legjobb bizonyíték arra, hogy a program él. A hosszú útvonalat rövidítsd (TextRenderer PathEllipsis jelzővel, vagy a Path.GetFileName).

Jósolj!

1000 elemből az első 10 villámgyors (0,1 mp), a többi lassú (1 mp). Az első 10 után a becslés mekkora hátralévő időt ad?

Jóslat ellenőrzése

A 10 elem 1 mp alatt készült: a becslés 100 másodperc (1,7 perc) a valódi ~1000 mp helyett. A becslés az elején hamis lehet: ezért várunk a megjelenítéssel (az 5% és az első másodpercek), és a sebességet mozgóátlaggal számoljuk.

Tájékoztatás, akadálymentesség, darabolt munka

A jelző egyedül kevés: a felhasználónak szöveg is kell (mi történik, hol tart), a képernyőolvasónak is. A ProgressBar állapotát a képernyőolvasó általában felolvassa, de a jelentést (fájlok másolása) a címke és az AccessibleName adja:

Form1.csC#
pb.AccessibleName = "Fájlok feldolgozása";          // a képernyőolvasó ezt mondja a jelző elé
pb.AccessibleDescription = "A feldolgozás előrehaladása százalékban";

// munka közben: a felület jelezze az állapotot és tiltsa le, ami nem használható
private void Fut(bool fut)
{
btnIndit.Enabled = !fut; // ne lehessen kétszer elindítani
btnMegse.Enabled = fut;
txtMappa.Enabled = !fut;
this.UseWaitCursor = fut; // várakozó kurzor az egész ablakon
}

// darabolt munka időzítővel: egy Tick-ben legfeljebb ~25 ms munka, utána a felület lélegzik
private void tmrMunka_Tick(object sender, EventArgs e)
{
Stopwatch keret = Stopwatch.StartNew();

while (kovetkezo < elemek.Count && keret.ElapsedMilliseconds < 25)
{
Feldolgoz(elemek[kovetkezo]); // egy elem (gyors!)
kovetkezo++;
}

Jelent(kovetkezo, elemek.Count, kovetkezo < elemek.Count ? elemek[kovetkezo] : "");

if (kovetkezo >= elemek.Count)
{
tmrMunka.Stop();
Fut(false);
FazisKesz("Kész: " + elemek.Count + " elem feldolgozva.");
}
}
Szöveg a jelző mellettA ProgressBar nem ír ki százalékot, és a szín/hossz nem mindenkinek érthető. A 12 / 40 (30%), még kb. 1 perc szöveg mindenkinek informatív. Befejezéskor is szöveg: Kész.
AccessibleNameA képernyőolvasó a jelzőt „állapotjelző, 40%”-ként olvashatja; az AccessibleName megmondja, mi halad. Sok egymás utáni frissítés zavarja a képernyőolvasót: a szöveg változása legyen ritkább (másodpercenként).
Állapot-gépFutás közben a gombok állapota (Indít tiltott, Mégse engedélyezett) mutatja, mit tehet a felhasználó. A UseWaitCursor az egér mutatóját is átállítja.
Darabolt munkaA Tick-ben végzett munka időkerete (itt 25 ms) azt biztosítja, hogy a felület szál minden tizedmásodpercben lélegezzen: az ablak mozgatható, a gombok kattinthatók. Ez a háttérszál nélküli megoldás korlátja: a munka darabokra bontható és gyors elemekből áll. Nagy, oszthatatlan feladathoz háttérszál kell (11.5 lecke).

Jósolj!

A Tick-ben egy ciklus az összes 500 elemet feldolgozza (nincs időkeret), és minden elem után frissíti a ProgressBar értékét. Mit lát a felhasználó közben?

Jóslat ellenőrzése

A felület lefagy, és a jelző csak a végén ugrik 100%-ra: a ciklus alatt a felület szál nem rajzol és nem dolgoz fel üzeneteket. A frissítések látni kívánt hatása csak akkor van, ha a felület szál közben visszatér az üzenetkezeléshez (időkeret, vagy háttérszál).

📷 Képernyőkép helye

Mit tegyél ide: a folyamatjelző-labor: a Marquee számlálás, majd a százalékos feldolgozás fájlnévvel, becsléssel és Mégse gombbal.Javasolt fájlnév: winforms-11-2-folyamatjelzo.webp · Alt szöveg: A folyamatjelző-labor program

Hibakeresés: te vagy a hibadetektív

Mi a baj, és hogyan javítod?

Gondold végig az okot, és csak utána nyisd le a megoldást.

1. ArgumentOutOfRangeException a Value beállításakor

pb.Value = szazalek;   // 100,4 → 100-ra kerekítve 101 is lehet
Hiba és javítás

A Value nem lépheti át a Maximum értéket. Szorítsd a tartományba: Math.Min(pb.Maximum, ertek).

2. A jelző 100%-on áll, de a munka tart

A jelző előbb eléri a végét, mint a munka.

Ok és javítás

A Maximum nem egyezik a tényleges munkával (például a számlálás után új elemek kerültek a listába). Az összes ismeretében állítsd a Maximum értéket, és a fázisváltáskor nullázd a Value értékét.

3. A Marquee sáv a művelet után is fut

pb.Style = ProgressBarStyle.Marquee;
// ... a művelet vége után: nincs visszaállítás
Hiba és javítás

Befejezéskor állítsd a Style = Continuous és a MarqueeAnimationSpeed = 0 értéket, és írd ki: Kész.

4. A felület nem frissül a ciklus közben

for (int i = 0; i < 500; i++)
{
Feldolgoz(i);
pb.Value = i; // a felület szála foglalt: a rajz nem frissül
}
Hiba és javítás

A felület szál nem jut rajzoláshoz. Darabold a munkát időzítővel (időkeret), vagy tedd háttérszálra (11.5 lecke); az Application.DoEvents() csak vészmegoldás.

5. Az ugráló hátralévő idő

A becsült idő 3 óra, majd 4 perc, majd 40 perc.

Ok és javítás

A becslés az elején, kevés mintából számolódik, és a sebesség ingadozik. Várj az 5% / 3 másodperc küszöbig, és mozgóátlaggal számolj; ne mutass hamis pontosságot.

6. A felhasználó kétszer indítja el a műveletet

A második kattintás két párhuzamos feldolgozást indít.

Ok és javítás

A gombok állapota nem követi a futást. Futás alatt Indít tiltott, Mégse engedélyezett (Fut(true)), és a vége után visszaáll.

Mini projekt: folyamatjelző-labor

Készíts programot, amely egy szimulált fájlfeldolgozást mutat jó állapotjelzéssel (a „munkát” időzítő darabolja):

  1. Felület: nudDb (elemek száma, 10–2000), chkVaratlan (Néhány elem lassú), cmbStilus (Folytonos, Blokkos), Indítás, Szünet / Folytatás, Mégse; pb (a ProgressBar), lblSzazalek, lblMostani (a jelenlegi elem), lblAllapot; lstNaplo; állapotsor: tspb (ToolStripProgressBar) és tsslUzenet.
  2. 1. fázis (határozatlan): az Elemek keresése (1–2 másodperc, időzítővel szimulálva): Marquee sáv, szöveg (Elemek keresése...); a végén az összes ismert.
  3. 2. fázis (határozott): a feldolgozás: elemenként 5–40 ms véletlen idő (a lassú jelölővel néhány elem 300 ms); egy Tick legfeljebb 25 ms munkát végez (Stopwatch időkeret); a pb és a tspb együtt frissül.
  4. Jelentés: 128 / 500 (26%), még kb. 40 mp (a becslés 5% és 3 másodperc után, az utolsó 5 másodperc mozgóátlagából); a jelenlegi elem neve; a naplóba minden 50. elem.
  5. Szünet és megszakítás: a Szünet megállítja az időzítőt és a Stopwatch-ot (az idő nem telik); a Mégse leállítja a feldolgozást, a jelző Megszakítva (128 / 500) szöveget kap; a gombok állapota helyes (Fut(true/false)).
  6. Befejezés: Style = Continuous, a jelző a végén, a szöveg Kész: 500 elem, 14 mp alatt; a hang helyett látható üzenet; a UseWaitCursor visszaáll.
  7. Akadálymentesség: AccessibleName a jelzőn és a gombokon; a szöveges állapot másodpercenként frissül (nem minden Tick-ben); a gombok billentyűvel elérhetők (Alt+I Indítás, Esc Mégse).
  8. Hibatűrés: 0 elem (érthető üzenet, nincs ArgumentOutOfRangeException); a Form bezárása futó feldolgozás közben (az időzítő leáll); az Indítás kétszeri kattintása.
  9. Teszteld: 10, 500, 2000 elem; lassú elemekkel (a becslés ingadozása); szünet és folytatás; Mégse; ablak mozgatása és átméretezése feldolgozás közben (a felület él); a Blokkos és Folytonos stílus; képernyőolvasó (ha van).
Megoldás megnyitása (próbáld ki előbb önállóan!)

A központi rész a tmrMunka_Tick időkeretes ciklusa, a mozgóátlagos becslés és a gombállapotok.

Form1.cs (using System.Diagnostics; using System.Collections.Generic; using System.Linq; using System.Threading;)C#
private int osszes = 0, kovetkezo = 0;
private Random veletlen = new Random();
private int fazis = 0; // 0: nincs, 1: keresés, 2: feldolgozás
private Stopwatch ora = new Stopwatch();
private Stopwatch kereses = new Stopwatch();
private Queue<KeyValuePair<double, int>> minta = new Queue<KeyValuePair<double, int>>(); // (idő, kész) az utolsó 5 mp-ből
private DateTime utolsoSzoveg = DateTime.MinValue;

private void Form1_Load(object sender, EventArgs e)
{
cmbStilus.Items.AddRange(new object[] { "Folytonos", "Blokkos" });
cmbStilus.SelectedIndex = 0;
pb.AccessibleName = "Elemek feldolgozása";
tmrMunka.Interval = 30;
Fut(false);
}

private void Fut(bool fut)
{
btnIndit.Enabled = !fut;
btnSzunet.Enabled = fut;
btnMegse.Enabled = fut;
nudDb.Enabled = !fut;
chkVaratlan.Enabled = !fut;
this.UseWaitCursor = fut;
}

private void btnIndit_Click(object sender, EventArgs e)
{
osszes = (int)nudDb.Value;

if (osszes <= 0) { tsslUzenet.Text = "Nincs feldolgozandó elem."; return; }

lstNaplo.Items.Clear();
kovetkezo = 0;
minta.Clear();
fazis = 1;
Fut(true);

pb.Style = ProgressBarStyle.Marquee; // 1. fázis: határozatlan
pb.MarqueeAnimationSpeed = 30;
lblAllapot.Text = "Elemek keresése...";
lblSzazalek.Text = "";
kereses.Restart();
tmrMunka.Start();
}

private void tmrMunka_Tick(object sender, EventArgs e)
{
if (fazis == 1)
{
if (kereses.ElapsedMilliseconds < 1500) { return; } // a „keresés” 1,5 másodperc

// 2. fázis: most már ismert az összes
fazis = 2;
pb.MarqueeAnimationSpeed = 0;
pb.Style = cmbStilus.SelectedIndex == 0 ? ProgressBarStyle.Continuous : ProgressBarStyle.Blocks;
pb.Minimum = 0;
pb.Maximum = Math.Max(1, osszes);
pb.Value = 0;
tspb.Minimum = 0; tspb.Maximum = Math.Max(1, osszes); tspb.Value = 0;
lblAllapot.Text = "Feldolgozás...";
ora.Restart();
return;
}

Stopwatch keret = Stopwatch.StartNew();

while (kovetkezo < osszes && keret.ElapsedMilliseconds < 25) // időkeret: a felület lélegzik
{
int ido = chkVaratlan.Checked && kovetkezo % 40 == 7 ? 300 : veletlen.Next(5, 40);

Thread.Sleep(Math.Min(ido, 25)); // a „munka” szimulálása (valódi háttérmunka: 11.5 lecke)
kovetkezo++;

if (kovetkezo % 50 == 0) { lstNaplo.Items.Insert(0, DateTime.Now.ToString("HH:mm:ss") + " " + kovetkezo + " elem kész"); }
}

Jelent();

if (kovetkezo >= osszes) { Befejez("Kész: " + osszes + " elem, " + ora.Elapsed.TotalSeconds.ToString("0.0") + " mp alatt."); }
}

private void Jelent()
{
pb.Value = Math.Min(pb.Maximum, kovetkezo);
tspb.Value = Math.Min(tspb.Maximum, kovetkezo);

// a szöveg legfeljebb másodpercenként frissül (képernyőolvasó, villogás ellen)
if ((DateTime.Now - utolsoSzoveg).TotalMilliseconds < 1000 && kovetkezo < osszes) { return; }

utolsoSzoveg = DateTime.Now;

double arany = (double)kovetkezo / osszes;
string szoveg = kovetkezo + " / " + osszes + " (" + arany.ToString("P0") + ")";

// mozgóátlag: az utolsó 5 másodperc sebessége
double most = ora.Elapsed.TotalSeconds;

minta.Enqueue(new KeyValuePair<double, int>(most, kovetkezo));
while (minta.Count > 1 && most - minta.Peek().Key > 5) { minta.Dequeue(); }

KeyValuePair<double, int> elso = minta.Peek();
double seb = most - elso.Key > 0.5 ? (kovetkezo - elso.Value) / (most - elso.Key) : 0;

if (arany >= 0.05 && most >= 3 && seb > 0 && kovetkezo < osszes) { szoveg += ", még kb. " + Hatralevo(TimeSpan.FromSeconds((osszes - kovetkezo) / seb)); }

lblSzazalek.Text = szoveg;
lblMostani.Text = kovetkezo < osszes ? "Elem: " + (kovetkezo + 1) : "";
}

private string Hatralevo(TimeSpan t)
{
if (t.TotalSeconds < 5) { return "néhány másodperc"; }
if (t.TotalSeconds < 90) { return Math.Round(t.TotalSeconds / 5) * 5 + " mp"; }

return Math.Round(t.TotalMinutes) + " perc";
}

private void btnSzunet_Click(object sender, EventArgs e)
{
if (tmrMunka.Enabled) { tmrMunka.Stop(); ora.Stop(); btnSzunet.Text = "Folytatás"; lblAllapot.Text = "Szünet"; this.UseWaitCursor = false; }
else { tmrMunka.Start(); ora.Start(); btnSzunet.Text = "Szünet"; lblAllapot.Text = "Feldolgozás..."; this.UseWaitCursor = true; }
}

private void btnMegse_Click(object sender, EventArgs e)
{
Befejez("Megszakítva (" + kovetkezo + " / " + osszes + ").");
}

private void Befejez(string uzenet)
{
tmrMunka.Stop();
fazis = 0;
pb.MarqueeAnimationSpeed = 0;
pb.Style = ProgressBarStyle.Continuous;
lblAllapot.Text = uzenet;
tsslUzenet.Text = uzenet; // látható üzenet, nem csak hang
btnSzunet.Text = "Szünet";
lblMostani.Text = "";
Fut(false);
}

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Escape && btnMegse.Enabled) { btnMegse.PerformClick(); return true; }

return base.ProcessCmdKey(ref msg, keyData);
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e) { tmrMunka.Stop(); }
📷 Képernyőkép helye

Mit tegyél ide: a kész folyamatjelző-labor feldolgozás közben, a becsléssel.Javasolt fájlnév: winforms-11-2-kesz.webp · Alt szöveg: A kész folyamatjelző-labor

Három önálló gyakorlófeladat

Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.

1. Szöveges folyamatjelző

Készíts egy 20 karakteres szöveges jelzőt ([#####---------------]). Hogyan számolod?

Egy lehetséges megoldás

A kitöltött karakterek száma (int)Math.Round(arany * 20); new string('#', n) + new string('-', 20 - n). Ez szöveges (konzolos) felületen és naplóban hasznos.

2. Letöltési sebesség

Írd ki a sebességet (MB/s) és az átlagos sebességet. Mit mérsz?

Egy lehetséges megoldás

A pillanatnyi sebesség az utolsó másodperc bájtjaiból, az átlag az összes bájt / eltelt idő. A kettő különbsége mutatja az ingadozást.

3. Ikon a tálcán

A tálca ikonja is mutassa a haladást. Mit használhatsz?

Egy lehetséges megoldás

A Windows tálca-folyamatjelzője (ITaskbarList3) a .NET-ben nincs beépítve: harmadik fél csomaggal (például Windows API Code Pack) vagy COM hívással érhető el. Egyszerűbb megoldás: az ablak címe tartalmazza a százalékot (Feldolgozás: 42%).

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.

Alap szint

1. Marquee vagy folytonos?

Melyiket használod: (a) 300 fájl másolása; (b) egy ismeretlen méretű szerverkérés?

Megoldás megnyitása

(a) Folytonos (százalékos): az összes ismert; (b) Marquee: nem tudod a hátralévő mennyiséget.

2. Százalék

125 elemből 40 kész. Hány százalék, egész számra kerekítve?

Megoldás megnyitása

40 / 125 = 0,32 → 32%. Egész osztásnál (40 / 125 egészekkel) 0 lenne: legalább az egyik tag double legyen.

Közepes szint

3. Hátralévő idő

20 másodperc alatt a munka 25%-a készült el. Mennyi a becsült hátralévő idő?

Megoldás megnyitása

A teljes 20 / 0,25 = 80 mp, a hátralévő 80 − 20 = 60 mp.

4. Gombállapotok

Sorold fel a gombok állapotát futás közben és utána.

Megoldás megnyitása

Futás közben: Indít tiltott; Szünet, Mégse engedélyezett; a beállító mezők tiltottak. A vége után: Indít engedélyezett; Szünet, Mégse tiltott.

Kihívás szint

5. Több feladat egy jelzőn

Három fázis (letöltés 50%, kitömörítés 30%, ellenőrzés 20%) egy közös jelzőn. Hogyan számolod a teljes arányt?

Megoldás megnyitása

A fázisok súlyozott összege: teljes = 0,5 · letöltés + 0,3 · kitömörítés + 0,2 · ellenőrzés, ahol minden tag 0–1 arány; a Maximum = 1000, a Value = (int)(teljes * 1000).

6. Visszalépő jelző

A felhasználó a műveletet újra indítja, a jelző nem nulláról kezd. Mi a hiba?

Megoldás megnyitása

Az új indításkor nincs nullázás (Value = 0, Maximum beállítása, a számlálók és a Stopwatch nullázása). Az állapot teljes visszaállítása az indítás első lépése.

Gyors önellenőrzés

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

1. Mikor határozott a folyamat?

Ha az összes munka ismert (elemszám, bájtok): százalékos jelző.

2. Mire való a Marquee?

Határozatlan folyamat jelzése: „dolgozom”, de a hátralévő idő ismeretlen.

3. Mi történik, ha a Value kívül esik a tartományon?

ArgumentOutOfRangeException.

4. Hogyan becsülöd a hátralévő időt?

eltelt / arany − eltelt; csak elegendő minta után, mozgóátlaggal.

5. Mi mindent mondj a felhasználónak szövegben?

Mit csinál (feldolgozás), hol tart (12 / 40, 30%), mi az aktuális elem, és a végén: Kész vagy Megszakítva.

6. Miért darabolt munka a Tick-ben?

Hogy a felület szál időnként visszatérjen az üzenetkezeléshez, és az ablak éljen.

7. Mi tiltott futás közben?

Az Indít gomb és a beállító mezők; a Mégse engedélyezett.

Mit tudsz már?

  • A ProgressBar tulajdonságait és stílusait helyesen használod.
  • Megkülönbözteted a határozott és a határozatlan folyamatot, és kétfázisú jelzést építesz.
  • Százalékot és becsült hátralévő időt számolsz, hamis pontosság nélkül.
  • Akadálymentes, szöveges állapotjelzést adsz, és helyesen kezeled a gombok állapotát.
  • A munkát időzítővel kis darabokra osztod, így a felület közben él.

Következő lecke: UI-szál és a felület lefagyása

Mi az a felületi szál, miért fagy le az ablak a hosszú műveletnél, és mit jelent az üzenetsor és a szálak szabálya.