Grafikus C# – Windows Forms tanfolyam › 11.2 lecke Windows Forms · 11.2 lecke · á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 és állapotjelzés
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.
A lecke végére
- beállítod a
ProgressBartulajdonsá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 (
Valuea 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.
A ProgressBar beállításai
| Tulajdonság / metódus | Jelentés |
|---|---|
Minimum, Maximum | A tartomány (alapból 0–100). A Maximum lehet a feldolgozandó elemek száma. |
Value | Az 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. |
Style | Blocks (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. |
MarqueeAnimationSpeed | A Marquee animációjának sebessége (ezredmásodperc; 0 = áll). |
// 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;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 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).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.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.
// 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ő
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";
}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.Hatralevo metódus a becsléshez illő nagyságrendre kerekít (kb. 2 perc).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:
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.");
}
}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.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).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.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).
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 lehetHiba é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. A Ok és javítás
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ásHiba é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. 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.Ok és javítás
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. A gombok állapota nem követi a futást. Futás alatt Ok és javítás
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):
- 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(aProgressBar),lblSzazalek,lblMostani(a jelenlegi elem),lblAllapot;lstNaplo; állapotsor:tspb(ToolStripProgressBar) éstsslUzenet. - 1. fázis (határozatlan): az Elemek keresése (1–2 másodperc, időzítővel szimulálva):
Marqueesáv, szöveg (Elemek keresése...); a végén az összes ismert. - 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 (
Stopwatchidőkeret); apbés atspbegyütt frissül. - 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.
- 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)). - 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; aUseWaitCursorvisszaáll. - Akadálymentesség:
AccessibleNamea 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). - 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. - 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.
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(); }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? A kitöltött karakterek száma Egy lehetséges megoldás
(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? 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.Egy lehetséges megoldás
3. Ikon a tálcán
A tálca ikonja is mutassa a haladást. Mit használhatsz? A Windows tálca-folyamatjelzője (Egy lehetséges megoldás
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? (a) Folytonos (százalékos): az összes ismert; (b) Megoldás megnyitása
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? 40 / 125 = 0,32 → 32%. Egész osztásnál (Megoldás megnyitása
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ő? A teljes 20 / 0,25 = 80 mp, a hátralévő 80 − 20 = 60 mp.Megoldás megnyitása
4. Gombállapotok
Sorold fel a gombok állapotát futás közben és utána. 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.Megoldás megnyitása
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? A fázisok súlyozott összege: Megoldás megnyitása
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? Az új indításkor nincs nullázás (Megoldás megnyitása
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. Ha az összes munka ismert (elemszám, bájtok): százalékos jelző. Határozatlan folyamat jelzése: „dolgozom”, de a hátralévő idő ismeretlen. 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. Hogy a felület szál időnként visszatérjen az üzenetkezeléshez, és az ablak éljen. Az Indít gomb és a beállító mezők; a Mégse engedélyezett.1. Mikor határozott a folyamat?
2. Mire való a Marquee?
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?
6. Miért darabolt munka a Tick-ben?
7. Mi tiltott futás közben?
Mit tudsz már?
- A
ProgressBartulajdonsá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.



