Grafikus C# – Windows Forms tanfolyam › 6.3 lecke Windows Forms · 6.3 lecke · tárolók Egy nagy űrlapon húsz vezérlő rendezetlenül kuszaság. A tárolóvezérlők (Panel, GroupBox és SplitContainer
Panel, GroupBox, SplitContainer) csoportosítják a vezérlőket: a tartalom együtt mozog, együtt kapcsolható ki, együtt igazítható, és a felhasználó számára is átlátható. A GroupBox kitüntetett szerepet kap a RadioButton-ok csoportosításában, a SplitContainer pedig húzható elválasztót ad két rész között. Ebben a leckében megtanulod mindhármat, a lapozó („oldalas”) felület alapjait, és a leggyakoribb tárolóhibákat.
A lecke végére
- érted a szülő–gyermek kapcsolatot (
Parent,Controls), és tudod, hogy a gyermek helye a szülőhöz viszonyított; - használod a
Panelvezérlőt (AutoScroll, lapozás aVisibleésBringToFrontsegítségével); - a
GroupBoxsegítségével csoportosítod aRadioButtonvezérlőket, és egy csoport tartalmát egyszerre engedélyezed vagy letiltod; - a
SplitContainersegítségével húzható elválasztót készítesz (SplitterDistance,Panel1Collapsed,FixedPanel); - beágyazott tárolókkal háromoszlopos elrendezést építesz;
- felismered a gyakori hibákat (közös
RadioButtoncsoport,SplitterDistancekivétel, rossz szülő).
Mielőtt elkezded
Ehhez a leckéhez a 6.2 lecke (Anchor, Dock), az 1.4 lecke (RadioButton) és az 5.8 lecke (vezérlők bejárása) szükséges. Új projektben próbáld ki a példákat.
Tárolók: szülő és gyermek
A tárolóvezérlő (container) más vezérlőket tartalmaz. A tartalmazott vezérlők a tároló Controls gyűjteményében vannak, és a tároló a szülőjük (Parent). Ennek három következménye van:
1. A hely a szülőhöz képest
A gyermek Location értéke a szülő bal felső sarkához viszonyít, nem az ablakhoz. Ha a panelt elmozdítod, a benne lévő vezérlők vele mozognak, a Location értékük pedig nem változik.
2. Közös állapot
Ha a tároló Enabled értéke hamis, minden gyermeke is letiltott. Ha a Visible hamis, a gyermekek is eltűnnek. Így egyetlen beállítással kezelhető egy egész csoport.
3. Levágás
A gyermek csak a szülő területén belül látszik. Ami túllóg a panel szélén, levágódik (hacsak az AutoScroll nem ad görgetősávot).
4. Anchor és Dock a szülőre vonatkozik
A 6.2 lecke szabálya: a gyermek horgonya és dokkolása a közvetlen szülőre hat, ezért a tárolók egymásba ágyazásával rétegesen építhető az elrendezés.
// vezérlő áthelyezése egyik tárolóból a másikba: a Parent átállításával, vagy az Add hívásával
gomb.Parent = pnlJobb; // kikerül a régi szülőből, az újba kerül
pnlJobb.Controls.Add(gomb); // ugyanezt teszi
// a szülő lekérdezése és a koordináták átszámolása
Control szulo = gomb.Parent;
Point kepernyoHely = gomb.Parent.PointToScreen(gomb.Location); // a gomb helye a képernyőn
// egy csoport engedélyezése, letiltása egyetlen beállítással
grpBeallitasok.Enabled = chkEngedelyez.Checked;Jósolj!
Egy gomb Location értéke a panelben (20, 10), a panel helye az ablakban (100, 50). Hol van a gomb bal felső sarka az ablak kliensterületéhez képest?
Jóslat ellenőrzése
A (120, 60) pontnál (a két érték összege): a panel bal felső sarka (100, 50), és a gomb ettől (20, 10) távolságra van. A gomb.Location értéke továbbra is (20, 10), mert a szülőhöz viszonyított. A képernyő-koordinátát a PointToScreen adja.
Panel: a láthatatlan tároló
A Panel a legegyszerűbb tároló: nincs felirata, és alapból keret sincs, csak csoportosít. Fontosabb tulajdonságai:
| Tulajdonság | Mit tesz? |
|---|---|
BorderStyle | None (alap), FixedSingle, Fixed3D: keret a panel körül. |
BackColor | A panel háttérszíne (vizuális csoportosítás, színes sáv). |
AutoScroll | Ha a tartalom nagyobb a panelnél, görgetősáv jelenik meg. |
Padding | Belső margó (a dokkolt gyermekek ennyivel beljebb kerülnek). |
Dock, Anchor | A panel elrendezése az ablakban (6.2 lecke). |
Lapozó felület: oldalak panelekkel
Gyakori minta: több panel van egymás tetején (mindegyik Dock = Fill), és mindig csak egy látszik. Ez a varázsló (wizard) és a beállítóablak alapja:
private Panel[] oldalak;
private int aktualis = 0;
private void Form1_Load(object sender, EventArgs e)
{
oldalak = new Panel[] { pnlOldal1, pnlOldal2, pnlOldal3 };
Mutat(0);
}
private void Mutat(int index)
{
aktualis = index;
for (int i = 0; i < oldalak.Length; i++)
{
oldalak[i].Visible = i == index; // csak az aktuális látszik
}
btnVissza.Enabled = index > 0;
btnTovabb.Text = index == oldalak.Length - 1 ? "Befejezés" : "Tovább";
lblLepes.Text = $"{index + 1}. lépés / {oldalak.Length}";
}
private void btnTovabb_Click(object sender, EventArgs e)
{
if (aktualis < oldalak.Length - 1)
{
Mutat(aktualis + 1);
}
else
{
MessageBox.Show("A varázsló kész.");
}
}
private void btnVissza_Click(object sender, EventArgs e)
{
if (aktualis > 0)
{
Mutat(aktualis - 1);
}
}Visible a nem aktuális oldalt rejtetté teszi (a gyermekei sem látszanak, és nem kapnak fókuszt). A BringToFront csak előre hozza, a mögötte lévők láthatatlanok, de aktívak maradnak (fókuszba kerülhetnek Tab billentyűvel). A lapozáshoz a Visible a biztonságos.TabControl (6.5 lecke), amely a lapozást beépítve tudja.AutoScroll mellett görgetősáv jelenik meg. A ScrollControlIntoView(vezérlő) metódus egy konkrét vezérlőt görget láthatóvá.Dock értékét Fill-re.Jósolj!
A varázsló második oldalát a Visible = false helyett csak a SendToBack() metódussal rejted el a harmadik mögé. Mit tapasztalsz a Tab billentyű lenyomásakor?
Jóslat ellenőrzése
A takart panel vezérlői látható nélkül is megkaphatják a fókuszt a Tab billentyűvel (a felhasználó „láthatatlan” mezőbe gépel), mert a panel továbbra is látható, csak más panel fedi. A Visible = false a panelt és minden gyermekét kiveszi a fókuszsorrendből.
GroupBox: keretes csoport felirattal
A GroupBox egy feliratos keretes tároló. A Text tulajdonsága a keret címe. A Panel-hez képest a lényeg: vizuálisan jelzi, hogy a benne lévő vezérlők összetartoznak (például „Szállítási mód”). Legfontosabb szerepe a választógomboknál van:
A RadioButton csoportját a tároló adja
Az azonos tárolóban lévő RadioButton vezérlők kölcsönösen kizárják egymást: egyszerre csak egy lehet bejelölve. Ha két független választást szeretnél (például méret és szín), külön tárolóba (két GroupBox-ba) kell tenned őket. Az ablakon közvetlenül lévő összes választógomb egyetlen csoportot alkot.
// a csoport kiválasztott gombjának megkeresése: a GroupBox Controls gyűjteményének bejárása
private string Valasztott(GroupBox csoport)
{
foreach (Control c in csoport.Controls)
{
RadioButton rb = c as RadioButton;
if (rb != null && rb.Checked)
{
return rb.Text;
}
}
return "(nincs)";
}
private void btnRendel_Click(object sender, EventArgs e)
{
lblEredmeny.Text = "Méret: " + Valasztott(grpMeret) + ", szín: " + Valasztott(grpSzin);
}
// az egész csoport ki-be kapcsolása
private void chkEgyedi_CheckedChanged(object sender, EventArgs e)
{
grpSzin.Enabled = chkEgyedi.Checked;
}Controls gyűjtemény adja. Az as átalakítással a RadioButton típusúakat szűrjük ki, az esetleges más vezérlőket (címke) kihagyjuk (5.2 lecke).Tag-be, és ne a szövegből olvasd vissza (5.8 lecke).Checked = true értékre a tervezőben. Így sosem üres a csoport, és nem kell az „egyik sincs kiválasztva” esettel foglalkozni.GroupBox.Enabled = false a benne lévő összes vezérlőt letiltja (szürkére festi). Ha egy vezérlőnek aktívnak kellene maradnia (például a csoportot kapcsoló CheckBox), tedd a csoporton kívülre, a csoport fölé.Jósolj!
Egy ablakon közvetlenül (tároló nélkül) hat RadioButton van: háromnak a szövege Kicsi/Közepes/Nagy, háromnak Piros/Kék/Zöld. Hányat jelölhet be a felhasználó egyszerre?
Jóslat ellenőrzése
Egyet: mind a hat ugyanabban a tárolóban (az ablakon) van, ezért egyetlen csoportot alkotnak. A méret kiválasztása a szín kiválasztását törli. A megoldás: a két hármast két GroupBox (vagy Panel) tartalmazza.
SplitContainer: húzható elválasztó
A SplitContainer egy tároló két panellel (Panel1 és Panel2) és közöttük egy húzható elválasztóval (splitter). A felhasználó az elválasztót húzva méretezheti át a két részt. Tipikus használat: fájlfa és tartalom, lista és részletek.
| Tulajdonság | Jelentés |
|---|---|
Orientation | Vertical (alap): bal és jobb panel, függőleges elválasztó; Horizontal: felső és alsó panel. |
SplitterDistance | Az elválasztó helye: az első panel mérete képpontban. |
SplitterWidth | Az elválasztó vastagsága. |
FixedPanel | Melyik panel mérete marad állandó az ablak átméretezésekor (None, Panel1, Panel2). A másik panel nyúlik. |
Panel1MinSize, Panel2MinSize | A panelek minimális mérete (az elválasztó nem húzható ennél kisebbre). |
IsSplitterFixed | Igaz esetén a felhasználó nem húzhatja az elválasztót. |
Panel1Collapsed, Panel2Collapsed | Igaz esetén az adott panel összecsukódik (eltűnik), a másik kitölti a helyet. |
private void Form1_Load(object sender, EventArgs e)
{
split.Panel1MinSize = 120; // a bal panel legalább 120 széles
split.Panel2MinSize = 200;
split.FixedPanel = FixedPanel.Panel1; // ablak nagyításakor a bal panel marad, a jobb nő
split.SplitterDistance = 200;
// a panelek tartalma: Dock = Fill
lstFajlok.Dock = DockStyle.Fill; // split.Panel1 gyermeke
rtbTartalom.Dock = DockStyle.Fill; // split.Panel2 gyermeke
}
// az oldalsó panel ki-be kapcsolása egy gombbal
private void btnOldal_Click(object sender, EventArgs e)
{
split.Panel1Collapsed = !split.Panel1Collapsed;
}
// az elválasztó mozgatásának követése
private void split_SplitterMoved(object sender, SplitterEventArgs e)
{
lblInfo.Text = "Bal panel szélessége: " + split.SplitterDistance;
}Beágyazott elválasztók: három oszlop
Háromrészes elrendezéshez a SplitContainer-t egymásba ágyazzuk: a külső Panel2-be teszünk egy másik SplitContainer-t (Dock = Fill). Így két elválasztó lesz, külön húzható:
splitKulso.Dock = DockStyle.Fill;
splitKulso.Panel1MinSize = 120; // 1. oszlop: mappák
splitBelso.Dock = DockStyle.Fill; // a külső Panel2-ben
splitBelso.Panel1MinSize = 160; // 2. oszlop: lista
splitBelso.Panel2MinSize = 200; // 3. oszlop: előnézetSplitContainer panelei tárolók: a bennük lévő vezérlőket (ListBox, RichTextBox) szokás Dock = Fill értékre állítani, hogy kitöltsék a panelt.SplitterDistance értékét érdemes a FormClosed eseményben menteni, és a Load-ban visszaállítani (5.6 lecke), így a felhasználó beállítása megmarad.Panel1Collapsed = false visszaállítja az eredeti elválasztó-helyet.SplitContainer a felhasználó által húzható elválasztót ad. A TableLayoutPanel (6.4 lecke) a program által megadott, százalékos arányú rácsot.Jósolj!
A Panel1MinSize értéke 150, és a Form1_Load eseményben split.SplitterDistance = 100; sort írsz. Mi történik?
Jóslat ellenőrzése
A program InvalidOperationException kivételt dob: A SplitterDistance értéke a Panel1MinSize és a (szélesség - Panel2MinSize) között legyen. A 100 kisebb a 150 minimumnál. Hasonló hibát kapsz, ha a SplitterDistance túl nagy (a második panelnek már nem marad a minimális hely), vagy ha az érték az ablak még be nem állt méretéhez képest érvénytelen. A javítás: előbb a minimum, utána a távolság, és az érték a megengedett tartományon belül legyen.
Mit tegyél ide: egy háromoszlopos ablak (mappák, fájllista, előnézet) két húzható elválasztóval.Javasolt fájlnév: winforms-6-3-split.webp · Alt szöveg: Háromoszlopos elrendezés SplitContainer vezérlőkkel
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. Két csoport választógombjai zavarják egymást
A méret kiválasztása törli a színválasztást. Mindkét hármas ugyanabban a tárolóban (az ablakon) van. Tedd őket külön Ok és javítás
GroupBox-ba. A már kirakott gombokat húzással a GroupBox-ba mozgathatod (a Document Outline ablakban ellenőrizheted a szülőt).
2. A vezérlő nem a panelben van
A panel mozgatásakor az egyik gomb a helyén marad. A gomb véletlenül az ablakra került, nem a panelre (a tervezőben a panel fölé húztad, de nem „ejtetted bele”). A Document Outline ablakban látszik a hierarchia. A javítás: húzd a gombot a panelbe, vagy kódból: Ok és javítás
gomb.Parent = panel;. Az áthelyezés után a Location értéke a panelhez viszonyítva értelmezendő.
3. InvalidOperationException a SplitterDistance beállításakor
split.SplitterDistance = 100; // de a Panel1MinSize 150Hiba és javítás
Az érték kisebb a Panel1MinSize értékénél. Ellenőrizd a megengedett tartományt: Math.Max(split.Panel1MinSize, Math.Min(ertek, split.Width - split.Panel2MinSize - split.SplitterWidth)). Mentett érték visszaállításánál mindig így védekezz.
4. A letiltott csoportban a kapcsoló is letiltódik
Egy jelölőnégyzet a A GroupBox-ban kapcsolja a csoportot, de kikapcsolás után nem lehet újra bekapcsolni.Ok és javítás
GroupBox.Enabled = false a benne lévő jelölőnégyzetet is letiltja. A kapcsoló legyen a csoporton kívül (fölötte). Egy trükk: a jelölőnégyzet a GroupBox felirata mellett kerüljön a csoport fölé, de ne legyen a gyermeke.
5. A tartalom hiányzik a panelből
Egy A sima Visible = false panel után a helye üres marad, és a mellette lévő vezérlők nem foglalják el.Ok és javítás
Anchor/Dock = None vezérlők nem rendeződnek át egy rejtett panel miatt. Dokkolt panelnél (Dock = Top/Left) a Visible = false felszabadítja a helyet a többi dokkolt vezérlőnek, ezért az átrendeződő elrendezéshez dokkolást használj, vagy SplitContainer PanelXCollapsed értéket.
6. A lapozó panelek egymás alá kerültek
Az oldalak nem fedik egymást, hanem egymás alatt jelennek meg. A panelek Ok és javítás
Dock értéke nem Fill, vagy a Location értékük eltér. A lapozáshoz minden oldal ugyanazt a helyet foglalja: Dock = Fill egy közös tárolóban, és a kód csak egy oldalt tesz láthatóvá.
Mini projekt: beállítóablak oldalakkal
Készíts beállítóablakot, amelyben a bal oldali lista kiválasztja, melyik oldal látszik a jobb oldalon:
- Az ablak:
SplitContainer(split,Dock = Fill,Panel1MinSize: 120,FixedPanel: Panel1). A bal panelben egylstOldalak(ListBox,Dock = Fill) a Profil, Megjelenés, Értesítések elemekkel. - A jobb panelben három, egymáson lévő
Panel(pnlProfil,pnlMegjelenes,pnlErtesites, mindDock = Fill). A Profil oldalon: név és e-mail mező. A Megjelenés oldalon kétGroupBox: Téma (Világos, Sötét, Kék) és Betűméret (Kicsi, Közepes, Nagy) választógombokkal. Az Értesítések oldalon egychkErtesiteskapcsoló és egygrpErtesitescsoport (e-mail, felugró ablak jelölőnégyzet), amely csak bekapcsolt kapcsolónál engedélyezett. - A lista kiválasztása (
SelectedIndexChanged) csak a megfelelő oldalt mutatja (Visible). - Egy
btnOldalsavgomb a bal panelt összecsukja (Panel1Collapsed), és újra megnyitja. - Az Alkalmaz gomb az
lblOsszegzescímkében kiírja a kiválasztott értékeket (téma, betűméret, értesítések), a választógombok bejárásával (Valasztottmetódus). - Az elválasztó helye (
SplitterDistance) aSettings-be mentődik, és induláskor visszaállítódik (a tartományvédelemmel). - Teszteld: az oldalak váltása, a két választógomb-csoport függetlensége, a csoport letiltása, az oldalsáv összecsukása, az elválasztó húzása és az újraindítás utáni hely.
Megoldás megnyitása (próbáld ki előbb önállóan!)
A beállításhoz hozz létre egy SplitterTavolsag nevű int típusú User hatókörű beállítást (5.6 lecke). Az oldalak tömbben vannak, hogy a lista sorszáma közvetlenül az oldal sorszáma legyen.
private Panel[] oldalak;
private void Form1_Load(object sender, EventArgs e)
{
oldalak = new Panel[] { pnlProfil, pnlMegjelenes, pnlErtesites };
lstOldalak.Items.AddRange(new object[] { "Profil", "Megjelenés", "Értesítések" });
split.Panel1MinSize = 120;
split.Panel2MinSize = 200;
split.FixedPanel = FixedPanel.Panel1;
int mentett = Properties.Settings.Default.SplitterTavolsag;
if (mentett > 0)
{
int max = split.Width - split.Panel2MinSize - split.SplitterWidth;
split.SplitterDistance = Math.Max(split.Panel1MinSize, Math.Min(mentett, max));
}
grpErtesites.Enabled = chkErtesites.Checked;
lstOldalak.SelectedIndex = 0;
}
private void lstOldalak_SelectedIndexChanged(object sender, EventArgs e)
{
int index = lstOldalak.SelectedIndex;
if (index < 0)
{
return;
}
for (int i = 0; i < oldalak.Length; i++)
{
oldalak[i].Visible = i == index;
}
}
private void chkErtesites_CheckedChanged(object sender, EventArgs e)
{
grpErtesites.Enabled = chkErtesites.Checked;
}
private void btnOldalsav_Click(object sender, EventArgs e)
{
split.Panel1Collapsed = !split.Panel1Collapsed;
}
private string Valasztott(GroupBox csoport)
{
foreach (Control c in csoport.Controls)
{
RadioButton rb = c as RadioButton;
if (rb != null && rb.Checked)
{
return rb.Text;
}
}
return "(nincs)";
}
private void btnAlkalmaz_Click(object sender, EventArgs e)
{
string ertesites = chkErtesites.Checked ? "be" : "ki";
lblOsszegzes.Text = $"Téma: {Valasztott(grpTema)} | Betűméret: {Valasztott(grpBetu)} | Értesítések: {ertesites}";
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (!split.Panel1Collapsed)
{
Properties.Settings.Default.SplitterTavolsag = split.SplitterDistance;
Properties.Settings.Default.Save();
}
}Mit tegyél ide: a kész beállítóablak: bal oldalon az oldalak listája, jobbra a Megjelenés oldal a két választógomb-csoporttal.Javasolt fájlnév: winforms-6-3-kesz.webp · Alt szöveg: A beállítóablak oldalakkal
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. Rendelés két választócsoporttal
Egy pizzarendelő űrlapon a méret (26 cm, 32 cm, 42 cm) és a szósz (paradicsom, tejfölös) választógombokkal választható, és egy Rendelek gomb kiírja az összesítést. Hogyan kerülöd el a csoportok keveredését, és hogyan adsz ármódosítást a mérethez? Két Egy lehetséges megoldás
GroupBox (grpMeret, grpSzosz) tartalmazza a két csoportot. A méret ára a választógomb Tag értékében van (2000, 2800, 3600), így nem kell a szövegből kiolvasni.private RadioButton Kivalasztott(GroupBox csoport)
{
foreach (Control c in csoport.Controls)
{
RadioButton rb = c as RadioButton;
if (rb != null && rb.Checked)
{
return rb;
}
}
return null;
}
private void btnRendel_Click(object sender, EventArgs e)
{
RadioButton meret = Kivalasztott(grpMeret);
RadioButton szosz = Kivalasztott(grpSzosz);
int ar;
if (meret == null || szosz == null || !int.TryParse(meret.Tag.ToString(), out ar))
{
lblOsszeg.Text = "Válassz méretet és szószt!";
return;
}
lblOsszeg.Text = $"{meret.Text}, {szosz.Text}: {ar} Ft";
}
2. Háromlépéses varázsló
Készíts háromoldalas regisztrációs varázslót (Adatok, Jelszó, Összegzés), Vissza és Tovább gombbal. A Tovább gomb csak akkor aktív, ha az aktuális oldal kötelező mezői ki vannak töltve. Hol ellenőrzöd? Az ellenőrzés egy Egy lehetséges megoldás
Ervenyes() metódus: az aktuális oldal szerint dönt. A mezők TextChanged eseménye újraszámolja a gomb állapotát (5.5 lecke), és a lapozáskor is meghívjuk.private bool Ervenyes()
{
if (aktualis == 0)
{
return txtNev.Text.Trim().Length > 0 && txtEmail.Text.Contains("@");
}
if (aktualis == 1)
{
return txtJelszo.Text.Length >= 8 && txtJelszo.Text == txtJelszo2.Text;
}
return true;
}
private void GombFrissit()
{
btnTovabb.Enabled = Ervenyes();
}
private void Mezo_TextChanged(object sender, EventArgs e)
{
GombFrissit();
}
// a Mutat(index) metódus végén: GombFrissit();
3. Háromoszlopos elrendezés
Építs háromoszlopos felületet két egymásba ágyazott A külső elválasztó SplitContainer-rel: mappák, fájlok, tartalom. A mappák oszlop összecsukható egy gombbal. Melyik panelhez rendeled a FixedPanel értéket?Egy lehetséges megoldás
FixedPanel = Panel1 (a mappák szélessége állandó), a belső elválasztón FixedPanel = Panel1 (a fájllista szélessége állandó, az előnézet nyúlik). Az összecsukáshoz a külső Panel1Collapsed kapcsolható.private void Form1_Load(object sender, EventArgs e)
{
splitKulso.FixedPanel = FixedPanel.Panel1;
splitKulso.Panel1MinSize = 120;
splitKulso.SplitterDistance = 160;
splitBelso.FixedPanel = FixedPanel.Panel1;
splitBelso.Panel1MinSize = 160;
splitBelso.Panel2MinSize = 200;
splitBelso.SplitterDistance = 220;
}
private void btnMappak_Click(object sender, EventArgs e)
{
splitKulso.Panel1Collapsed = !splitKulso.Panel1Collapsed;
}
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. Panel és GroupBox
Mi a különbség a A Panel és a GroupBox között, és melyiket választod egy „Szállítási mód” választócsoporthoz?Megoldás megnyitása
GroupBox felirattal és kerettel jelzi a csoportot, a Panel csak csoportosít, és görgethető. A „Szállítási mód” csoporthoz a GroupBox a jobb: a felirat megmondja a csoport tartalmát.
2. Vezérlő áthelyezése
Egy Áthelyez gomb a A btnPelda gombot a pnlBal panelből a pnlJobb panelbe teszi, majd vissza. Hogyan, és mi történik a gomb helyével?Megoldás megnyitása
Parent átállításával. A gomb Location értéke megmarad, de az új szülőhöz viszonyítva értelmeződik, ezért a gomb máshol látszik. Ha ugyanott akarod, számold át: PointToScreen és PointToClient.private void btnAthelyez_Click(object sender, EventArgs e)
{
Point kepernyo = btnPelda.Parent.PointToScreen(btnPelda.Location);
btnPelda.Parent = btnPelda.Parent == pnlBal ? pnlJobb : pnlBal;
btnPelda.Location = btnPelda.Parent.PointToClient(kepernyo); // ugyanazon a képernyőhelyen marad
}
Közepes szint
3. Görgethető panel
Egy Az pnlLista panelben 30 jelölőnégyzet van kódból létrehozva. Mi kell ahhoz, hogy a panel görgethető legyen, és hogyan ugrasz a 25. elemre?Megoldás megnyitása
AutoScroll = true görgetősávot ad, ha a tartalom nagyobb a panelnél. A ScrollControlIntoView a megadott vezérlőt látható területre görgeti.private CheckBox[] elemek = new CheckBox[30];
private void Form1_Load(object sender, EventArgs e)
{
pnlLista.AutoScroll = true;
for (int i = 0; i < elemek.Length; i++)
{
CheckBox cb = new CheckBox();
cb.Text = "Elem " + (i + 1);
cb.Location = new Point(10, 10 + i * 28);
elemek[i] = cb;
pnlLista.Controls.Add(cb);
}
}
private void btnUgras_Click(object sender, EventArgs e)
{
pnlLista.ScrollControlIntoView(elemek[24]); // a 25. elem
}
4. Az elválasztó helyének megjegyzése
Hogyan mented és állítod vissza a A visszaállításnál az értéket a megengedett tartományra szorítjuk (SplitterDistance értéket úgy, hogy hibás (túl nagy vagy túl kicsi) mentett érték se okozzon kivételt?Megoldás megnyitása
Math.Max és Math.Min), a mentés a FormClosed eseményben történik (5.6 lecke).private void Visszaallit(SplitContainer sc, int mentett)
{
int min = sc.Panel1MinSize;
int max = sc.Width - sc.Panel2MinSize - sc.SplitterWidth;
if (mentett > 0 && max >= min)
{
sc.SplitterDistance = Math.Max(min, Math.Min(mentett, max));
}
}
Kihívás szint
5. Csoport rekurzív letiltása kivétellel
Írj Szerkesztő és megtekintő mód váltásánál: a csoport vezérlői le vannak tiltva, de a Szerkesztés gomb aktív marad. A szülő Tilt(Control szulo, bool engedelyezve, Control kivetel) metódust, amely egy tároló minden gyermekét (a beágyazottakat is) letiltja vagy engedélyezi, kivéve egy megadott vezérlőt. Mire jó?Megoldás megnyitása
Enabled = false a gyermekeket is letiltaná, ezért itt a gyermekeken egyenként dolgozunk, és a szülő maga aktív marad.private void Tilt(Control szulo, bool engedelyezve, Control kivetel)
{
foreach (Control c in szulo.Controls)
{
if (c == kivetel)
{
continue;
}
if (c.Controls.Count > 0)
{
Tilt(c, engedelyezve, kivetel); // a tároló maga aktív marad, a gyermekeit kezeljük
}
else
{
c.Enabled = engedelyezve;
}
}
}
6. Függőleges és vízszintes osztás váltása
Egy gomb a Az SplitContainer elrendezését vízszintesről függőlegesre és vissza váltja. Mire kell vigyázni a SplitterDistance és a minimális méretek értékénél?Megoldás megnyitása
Orientation váltáskor az elválasztó helyét az új irányú mérethez kell igazítani, különben a régi érték érvénytelen lehet. Biztonságos megoldás: a minimumot átmenetileg nullázni, váltani, és az elválasztót a méret felére állítani.private void btnIrany_Click(object sender, EventArgs e)
{
split.Panel1MinSize = 25;
split.Panel2MinSize = 25;
split.Orientation = split.Orientation == Orientation.Vertical ? Orientation.Horizontal : Orientation.Vertical;
int osszes = split.Orientation == Orientation.Vertical ? split.Width : split.Height;
split.SplitterDistance = osszes / 2; // az új irányban a felére
}
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. A szülő bal felső sarkához, nem az ablakhoz. A tároló: az azonos tárolóban lévő választógombok kizárják egymást. Külön csoporthoz külön A benne lévő összes vezérlőt letiltja. A Megadja, melyik panel mérete marad állandó az ablak átméretezésekor, a másik nyúlik. Ha az érték kisebb a A 1. Mihez viszonyítja a gyermek a Location értékét?
2. Mi határozza meg egy RadioButton csoportját?
GroupBox vagy Panel kell.3. Mit tesz a GroupBox.Enabled = false?
4. Mi a SplitContainer két panelje?
Panel1 és a Panel2, közöttük húzható elválasztóval (SplitterDistance).5. Mire való a FixedPanel?
6. Miért dobhat kivételt a SplitterDistance?
Panel1MinSize értékénél, vagy a második panelnek nem marad a minimális hely.7. Mi a különbség a Visible = false és a SendToBack között panelek lapozásánál?
Visible = false a panelt és gyermekeit kiveszi a fókuszsorrendből, a SendToBack csak eltakarja őket (a Tab billentyű oda még eljuthat).
Mit tudsz már?
- Érted a szülő–gyermek kapcsolatot és a tárolók közös viselkedését.
- A
Panelsegítségével lapozó felületet építesz. - A
GroupBoxsegítségével független választócsoportokat és letiltható blokkokat készítesz. - A
SplitContainersegítségével húzható, összecsukható, beágyazható elválasztót használsz. - Felismered a gyakori tárolóhibákat.
Következő lecke: TableLayoutPanel és FlowLayoutPanel
Az elrendezés automatizálása: rács százalékos arányokkal és sorokba, oszlopokba törő folyamatos elrendezés.




