Grafikus C# – Windows Forms tanfolyam › 7.1 lecke Windows Forms · 7.1 lecke · menük és eszköztárak Az 1.7 leckében elkészítetted az első menüt (Fájl → Névjegy, Kilépés). Egy valódi program menüje ennél többet tud: gyorsbillentyűk, bejelölhető és választócsoportként működő menüpontok, az aktuális állapotot követő (tiltott vagy engedélyezett) elemek, az utoljára megnyitott fájlok listája, és egy eszköztár, amely ugyanazt a kódot használja. Ebben a leckében a menük és eszköztárak rendezett, karbantartható felépítését tanulod meg.MenuStrip, ToolStrip és menüelemek

A lecke végére
- ismered a menüelemek típusait (
ToolStripMenuItem, elválasztó,ToolStripComboBox,ToolStripTextBox) és az almenüket; - gyorsbillentyűt és mnemonikus betűt adsz a menüpontoknak;
- kapcsolós (
CheckOnClick) és választócsoport-szerű menüpontokat készítesz; - a menü állapotát a megnyitáskor frissíted (
DropDownOpening); - dinamikus menüt építesz kódból (utoljára megnyitott fájlok);
- eszköztárat készítesz, amely a menüvel közös kódot használ (
PerformClick).
Mielőtt elkezded
Ehhez a leckéhez az 1.7 lecke (MenuStrip alapjai), az 5.4 lecke (gyorsbillentyűk, & jel), az 5.8 lecke (közös kezelő, sender, Tag) és a 6.2 lecke (Dock, z-sorrend) szükséges. Új projektben próbáld ki a példákat.
Menüelemek és gyorsbillentyűk
A MenuStrip a menüsor, elemei a ToolStripItem leszármazottai. A ToolStripMenuItem egy menüpont, amelynek DropDownItems gyűjteménye az almenü. A tervezőben a Type Here mezőkbe írsz, kódból a Items és DropDownItems gyűjteményekhez adsz elemet.
| Elem | Mire való? |
|---|---|
ToolStripMenuItem | Menüpont (kattintható, lehet almenüje). |
ToolStripSeparator | Vízszintes elválasztó vonal a csoportok között. |
ToolStripComboBox, ToolStripTextBox | Legördülő lista vagy szövegmező a menüben vagy eszköztáron (például betűméret, keresés). |
// menüpont létrehozása: felirat, kép, kezelő, gyorsbillentyű
ToolStripMenuItem miFajl = new ToolStripMenuItem("&Fájl");
miFajl.DropDownItems.Add(new ToolStripMenuItem("&Új", null, Uj_Click, Keys.Control | Keys.N));
miFajl.DropDownItems.Add(new ToolStripMenuItem("&Megnyitás...", null, Megnyit_Click, Keys.Control | Keys.O));
miFajl.DropDownItems.Add(new ToolStripSeparator());
miFajl.DropDownItems.Add(new ToolStripMenuItem("&Kilépés", null, Kilep_Click, Keys.Alt | Keys.F4));
menu.Items.Add(miFajl);
// a tervezőben: Properties → ShortcutKeys, ShowShortcutKeys, ToolTipText, Enabled, Visible
miMent.ShortcutKeys = Keys.Control | Keys.S;
miMent.ToolTipText = "A dokumentum mentése";& a Alt + betű működéshez. Egy menüben a betűk ne ütközzenek (6.6 lecke).ShowShortcutKeys). Ne használj olyat, amit a szövegmező már használ (Ctrl+C, Ctrl+V jól működik, mert ugyanazt teszi).Image tulajdonsága ikont ad (16 × 16 képpont, vagy DPI-hez igazított, 6.8 lecke). Az ikon sosem helyettesíti a feliratot a menüben.Jósolj!
A menüpont ShortcutKeys értéke Ctrl+S, a menü zárva van, és a szövegmezőben állsz. Lefut-e a Mentés kezelő a Ctrl+S megnyomásakor?
Jóslat ellenőrzése
Igen: a ShortcutKeys gyorsbillentyű az ablak bármely vezérlőjéből működik, a menü zárt állapotában is, feltéve, hogy a menüpont engedélyezett és látható. Ezért nem kell külön ProcessCmdKey a menüből elérhető funkciókhoz (5.4 lecke).
Kapcsoló és választócsoport-szerű menüpontok
A menüpont Checked tulajdonsága pipát tesz mellé. A CheckOnClick = true beállítással a kattintás átbillenti a pipát (kapcsoló: Sortörés, Eszköztár). A menü nem ismer választógomb-csoportot, de könnyen megvalósítható: kattintáskor az összes testvér pipáját töröljük, a választottét beállítjuk:
// kapcsoló: CheckOnClick = true a tervezőben
private void miSortores_CheckedChanged(object sender, EventArgs e)
{
rtbSzoveg.WordWrap = miSortores.Checked;
}
// csoport: a Betűméret almenü három pontja közös kezelővel, a Tag a pontméret
private void BetuMeret_Click(object sender, EventArgs e)
{
ToolStripMenuItem valasztott = (ToolStripMenuItem)sender;
foreach (ToolStripItem elem in miBetuMeret.DropDownItems)
{
ToolStripMenuItem pont = elem as ToolStripMenuItem;
if (pont != null)
{
pont.Checked = pont == valasztott;
}
}
float meret;
if (valasztott.Tag != null && float.TryParse(valasztott.Tag.ToString(), out meret))
{
rtbSzoveg.Font = new Font(rtbSzoveg.Font.FontFamily, meret);
}
}Control (5.2 lecke): a sender ToolStripMenuItem típusú, a Tag, Text, Checked tulajdonságai használhatók, a Focus() viszont nem.CheckedChanged a pipa bármilyen változására (kódból is) lefut, a Click csak kattintásra. A kapcsolóhoz a CheckedChanged kényelmes.ToolStripItem elemeket tartalmaz (elválasztót is), ezért az as átalakítás és a null ellenőrzés szükséges.Jósolj!
A három betűméret menüpont mind CheckOnClick = true értékű, de a kezelő nem törli a többi pipáját. Mit látsz, ha sorban rákattintasz a háromra?
Jóslat ellenőrzése
Mindhárom bejelölve marad: a menü nem kezeli csoportként az elemeket. Az „egyszerre egy” szabályt a kódnak kell megvalósítania. A választócsoportnál ne használj CheckOnClick értéket, a kezelő állítja a pipákat (egyedül a kijelölt marad).
Dinamikus menü: állapot és utolsó fájlok
A menü frissítése megnyitáskor
A menüpontok engedélyezett állapota az alkalmazás állapotától függ (a Beillesztés csak akkor aktív, ha a vágólapon szöveg van). A frissítés legjobb helye a DropDownOpening esemény: közvetlenül a menü megnyílása előtt fut, és csak a látható menüt frissíti:
private void miSzerkeszt_DropDownOpening(object sender, EventArgs e)
{
bool vanKijeloles = rtbSzoveg.SelectionLength > 0;
miKivag.Enabled = vanKijeloles;
miMasol.Enabled = vanKijeloles;
miBeillesztes.Enabled = Clipboard.ContainsText();
miVisszavon.Enabled = rtbSzoveg.CanUndo;
}Az utoljára megnyitott fájlok listája
Ismert minta: a Fájl menü alján az utolsó néhány fájl. Kódból építjük: a korábbi elemeket töröljük, majd az újakat beszúrjuk egy rögzített hely (egy elválasztó) elé. A felismeréshez a Name tulajdonságot használjuk, a fájl útvonala a Tag-ben van:
private readonly List<string> utolso = new List<string>(); // legfrissebb elöl, legfeljebb 5
private void UtolsoHozzaad(string utvonal)
{
utolso.Remove(utvonal); // ha már szerepel, előre tesszük
utolso.Insert(0, utvonal);
while (utolso.Count > 5)
{
utolso.RemoveAt(utolso.Count - 1);
}
UtolsoMenuFrissit();
}
private void UtolsoMenuFrissit()
{
// a korábbi elemek törlése visszafelé, felszabadítással
for (int i = miFajl.DropDownItems.Count - 1; i >= 0; i--)
{
ToolStripItem elem = miFajl.DropDownItems[i];
if (elem.Name.StartsWith("miUtolso"))
{
elem.Click -= Utolso_Click;
miFajl.DropDownItems.RemoveAt(i);
elem.Dispose();
}
}
int hely = miFajl.DropDownItems.IndexOf(sepUtolso); // a lista a sepUtolso elválasztó elé kerül
for (int i = 0; i < utolso.Count; i++)
{
ToolStripMenuItem m = new ToolStripMenuItem((i + 1) + ". " + Path.GetFileName(utolso[i]));
m.Name = "miUtolso" + i;
m.Tag = utolso[i];
m.ToolTipText = utolso[i];
m.Click += Utolso_Click;
miFajl.DropDownItems.Insert(hely + i, m);
}
}
private void Utolso_Click(object sender, EventArgs e)
{
string utvonal = ((ToolStripMenuItem)sender).Tag.ToString();
Megnyit(utvonal);
}Name előtagjáról (miUtolso) ismerjük fel törléskor. A Tag a fájl útvonalát hordozza (5.8 lecke).Insert(index, elem) adott helyre teszi az elemet; az IndexOf megadja egy másik elem helyét, így a lista a rögzített elválasztó elé kerül.Settings-ben (egy sorokkal elválasztott szövegként) őrizni, hogy az újraindítás után is megmaradjon (5.6 lecke).Jósolj!
A menüpontok frissítését (Enabled beállítása) a TextChanged eseményben végzed minden betű beírásánál, a DropDownOpening helyett. Mi a hátránya?
Jóslat ellenőrzése
Feleslegesen sokszor (minden betű után) fut, és a vágólap állapota közben is változhat, amiről a szerkesztő eseménye nem tud. A DropDownOpening csak akkor fut, amikor a menü ténylegesen megnyílik, és az állapot akkor a legfrissebb. A gyorsbillentyű (Ctrl+V) viszont nem nyitja meg a menüt: egy letiltott menüpont gyorsbillentyűje nem működik, ezért ott a szerkesztő beépített viselkedése dönt.
ToolStrip: eszköztár a menü mellé
Az eszköztár (ToolStrip) a leggyakoribb műveletek gyors gombjait tartalmazza. Elemei:
| Elem | Jelentése |
|---|---|
ToolStripButton | Egyszerű gomb (DisplayStyle: Text, Image, ImageAndText); CheckOnClick mellett kapcsoló (félkövér). |
ToolStripSeparator | Elválasztó a csoportok között. |
ToolStripComboBox, ToolStripTextBox | Legördülő lista, szövegmező (betűméret, keresés). |
ToolStripDropDownButton, ToolStripSplitButton | Gomb legördülő menüvel (a split gombnak alapműveletet is van). |
ToolStripLabel | Felirat az eszköztáron. |
Egy kód, két kezelőfelület
A leggyakoribb hiba, hogy az eszköztár gombja és a menüpont külön kódot tartalmaz: később az egyiket módosítod, a másikat nem. A megoldás: a funkció a menüpont kezelőjében van (az állapotkezeléssel együtt), az eszköztár gombja megnyomja a menüpontot:
// az eszköztár gombjai a menüpontot nyomják meg (PerformClick)
private void tsbMent_Click(object sender, EventArgs e)
{
miMent.PerformClick(); // letiltott menüpontnál nem csinál semmit
}
// vagy: közös kezelő az egész eszköztárra, a Tag a menüpont neve
private void Eszkoz_Click(object sender, EventArgs e)
{
ToolStripItem gomb = (ToolStripItem)sender;
string nev = gomb.Tag as string;
ToolStripMenuItem pont = null;
if (nev != null)
{
ToolStripItem[] talalat = menu.Items.Find(nev, true); // név alapján, az almenükben is
pont = talalat.Length > 0 ? talalat[0] as ToolStripMenuItem : null;
}
if (pont != null)
{
pont.PerformClick();
}
}
// az állapot szinkronja: a kapcsoló gomb a menüpont pipáját tükrözi
private void miFelkover_CheckedChanged(object sender, EventArgs e)
{
tsbFelkover.Checked = miFelkover.Checked;
}ToolStripMenuItem.PerformClick() úgy hajtja végre a menüpontot, mintha a felhasználó kattintott volna. Letiltott menüpontnál hatástalan: az eszköztár így mindig a menü szabályait követi.CheckedChanged eseményben az egyik a másikat frissíti, és mindkét irányban a kód ne hurkoljon (5.5 lecke jelzője).DropDownOpening a menüt frissíti, az eszköztár állapotát a változás pillanatában kell (például a SelectionChanged eseményben).ToolStrip alapból Dock = Top; a MenuStrip fölé vagy alá kerülése a z-sorrendtől függ (6.2 lecke): a menü legyen legfelül.Jósolj!
A Mentés menüpont letiltott (nincs mit menteni), de az eszköztár Mentés gombja aktív maradt, és a saját kezelőjében külön mentő kódot hívsz. Mit tapasztalsz a gombnyomáskor?
Jóslat ellenőrzése
A gomb akkor is ment, amikor a menü szerint nincs mit: a két kezelőfelület ellentmond egymásnak, és az üres dokumentumot menti. A PerformClick() minta ezt kizárja: a szabályok (engedélyezés, ellenőrzés) egy helyen vannak.
Mit tegyél ide: egy szerkesztő ablak menüsorral (Fájl menü megnyitva, az utolsó fájlok listájával) és eszköztárral.Javasolt fájlnév: winforms-7-1-menu.webp · Alt szöveg: Menü és eszköztár egy szerkesztő ablakban
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. A gyorsbillentyű nem működik
A menüpont feliratában szerepel a Ctrl+S, de a lenyomására nem történik semmi. A feliratba beírt szöveg (Ok és javítás
"Mentés Ctrl+S") csak szöveg. A gyorsbillentyűt a ShortcutKeys tulajdonság állítja be, a felirat mellé a ShowShortcutKeys teszi ki. Ellenőrizd azt is, hogy a menüpont engedélyezett és látható-e.
2. InvalidCastException a menü kezelőjében
private void Pont_Click(object sender, EventArgs e)
{
Control c = (Control)sender; // a menüpont nem Control!
}Hiba és javítás
A ToolStripMenuItem nem Control leszármazott. Használd a ToolStripMenuItem vagy a közös ToolStripItem típust (5.2 lecke).
3. Minden betűméret bejelölve marad
A betűméret menüpontok mind pipásak, mert mindegyik A menü nem csoportkezelő. A választócsoportnál a kezelő törölje a testvérek pipáját, és ne használj CheckOnClick.Ok és javítás
CheckOnClick értéket.
4. Az utolsó fájlok listája duplázódik
Minden megnyitás után újabb elemek jelennek meg a régiek mellett. A frissítés nem törli a korábbi dinamikus elemeket. Előbb töröld a Ok és javítás
Name előtag alapján felismert elemeket (visszafelé), és csak utána add hozzá az újakat.
5. A Beillesztés mindig aktív (vagy mindig inaktív)
// csak egyszer, a Load-ban állítjuk
miBeillesztes.Enabled = Clipboard.ContainsText();Hiba és javítás
A vágólap állapota változik, a menüpont állapotát ezért a DropDownOpening eseményben kell frissíteni (a menü megnyitása előtt).
6. A menüsor az eszköztár alatt van
Az eszköztár a menüsor fölé került, vagy a szerkesztő elcsúszott a menü mögé. A z-sorrend rossz (6.2 lecke): a Ok és javítás
Fill szerkesztő legyen leghátul (Send to Back), a menüsor pedig legyen a legelöl. A Document Outline ablak mutatja a sorrendet.
Mini projekt: jegyzetfüzet menüvel és eszköztárral
Készíts jegyzetfüzet programot, amelynek menüje és eszköztára közös kódot használ:
- Az ablak:
menu(MenuStrip),eszkoz(ToolStrip),rtbSzoveg(RichTextBox,Dock = Fill, leghátul), alul egylblAllapotcímke (a 7.3 lecke előkészítéseként). - Fájl menü: Új (Ctrl+N), Megnyitás... (Ctrl+O), Mentés (Ctrl+S), az utolsó legfeljebb 5 fájl (egy
sepUtolsoelválasztó elé), Kilépés. - Szerkesztés menü: Visszavonás, Kivágás, Másolás, Beillesztés, Mindent kijelöl (Ctrl+A); az engedélyezés a
DropDownOpeningeseményben a kijelölés, a vágólap és a visszavonhatóság szerint. - Nézet menü: Sortörés (
CheckOnClick, bejelölve indul), Eszköztár (CheckOnClick, az eszköztár láthatósága), Betűméret almenü (Kicsi 9, Közepes 12, Nagy 16, választócsoportként, közös kezelő,Taga méret). - Súgó → Névjegy (
MessageBox). - Eszköztár: Új, Megnyitás, Mentés, elválasztó, Kivágás, Másolás, Beillesztés, elválasztó,
ToolStripComboBoxa betűmérethez (9, 12, 16). Minden gomb a megfelelő menüpontot nyomja meg (PerformClick). - A fájlnév és a módosítás jelzés (
*) az ablak címében. - Teszteld: minden gyorsbillentyű, a menüpontok engedélyezése, az utolsó fájlok (6 fájl megnyitása után csak 5 marad, a legutóbbi elöl), a betűméret csoport és az eszköztár együtt.
Megoldás megnyitása (próbáld ki előbb önállóan!)
A funkciók a menüpontok kezelőiben vannak, az eszköztár csak továbbítja. Az eszköztár betűméret-listája a menü betűméret-pontjait nyomja meg (PerformClick), így a pipa is frissül.
private string fajl = "";
private bool modosult = false;
private readonly List<string> utolso = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
tscBetu.Items.AddRange(new object[] { "9", "12", "16" });
tscBetu.SelectedIndex = 0;
miKicsi.Tag = "9";
miKozepes.Tag = "12";
miNagy.Tag = "16";
miSortores.Checked = true;
CimFrissit();
UtolsoMenuFrissit();
}
private void CimFrissit()
{
string nev = fajl.Length == 0 ? "Névtelen" : Path.GetFileName(fajl);
this.Text = nev + (modosult ? "*" : "") + " – Jegyzetfüzet";
}
private void rtbSzoveg_TextChanged(object sender, EventArgs e)
{
if (!modosult)
{
modosult = true;
CimFrissit();
}
}
private void miUj_Click(object sender, EventArgs e)
{
rtbSzoveg.Clear();
fajl = "";
modosult = false;
CimFrissit();
}
private void miMegnyit_Click(object sender, EventArgs e)
{
if (ofd.ShowDialog() == DialogResult.OK)
{
Megnyit(ofd.FileName);
}
}
private void Megnyit(string utvonal)
{
try
{
rtbSzoveg.Text = File.ReadAllText(utvonal);
fajl = utvonal;
modosult = false;
CimFrissit();
UtolsoHozzaad(utvonal);
}
catch (Exception ex)
{
MessageBox.Show("A fájl nem nyitható meg: " + ex.Message);
}
}
private void miMent_Click(object sender, EventArgs e)
{
if (fajl.Length == 0)
{
if (sfd.ShowDialog() != DialogResult.OK)
{
return;
}
fajl = sfd.FileName;
}
File.WriteAllText(fajl, rtbSzoveg.Text);
modosult = false;
CimFrissit();
UtolsoHozzaad(fajl);
}
private void miKilep_Click(object sender, EventArgs e)
{
this.Close();
}
private void UtolsoHozzaad(string utvonal)
{
utolso.Remove(utvonal);
utolso.Insert(0, utvonal);
while (utolso.Count > 5)
{
utolso.RemoveAt(utolso.Count - 1);
}
UtolsoMenuFrissit();
}
private void UtolsoMenuFrissit()
{
for (int i = miFajl.DropDownItems.Count - 1; i >= 0; i--)
{
ToolStripItem elem = miFajl.DropDownItems[i];
if (elem.Name.StartsWith("miUtolso"))
{
elem.Click -= Utolso_Click;
miFajl.DropDownItems.RemoveAt(i);
elem.Dispose();
}
}
int hely = miFajl.DropDownItems.IndexOf(sepUtolso);
for (int i = 0; i < utolso.Count; i++)
{
ToolStripMenuItem m = new ToolStripMenuItem((i + 1) + ". " + Path.GetFileName(utolso[i]));
m.Name = "miUtolso" + i;
m.Tag = utolso[i];
m.ToolTipText = utolso[i];
m.Click += Utolso_Click;
miFajl.DropDownItems.Insert(hely + i, m);
}
}
private void Utolso_Click(object sender, EventArgs e)
{
Megnyit(((ToolStripMenuItem)sender).Tag.ToString());
}
private void miSzerkeszt_DropDownOpening(object sender, EventArgs e)
{
bool kijeloles = rtbSzoveg.SelectionLength > 0;
miVisszavon.Enabled = rtbSzoveg.CanUndo;
miKivag.Enabled = kijeloles;
miMasol.Enabled = kijeloles;
miBeillesztes.Enabled = Clipboard.ContainsText();
}
private void miVisszavon_Click(object sender, EventArgs e) { rtbSzoveg.Undo(); }
private void miKivag_Click(object sender, EventArgs e) { rtbSzoveg.Cut(); }
private void miMasol_Click(object sender, EventArgs e) { rtbSzoveg.Copy(); }
private void miBeillesztes_Click(object sender, EventArgs e) { rtbSzoveg.Paste(); }
private void miMindent_Click(object sender, EventArgs e) { rtbSzoveg.SelectAll(); }
private void miSortores_CheckedChanged(object sender, EventArgs e)
{
rtbSzoveg.WordWrap = miSortores.Checked;
}
private void miEszkoztar_CheckedChanged(object sender, EventArgs e)
{
eszkoz.Visible = miEszkoztar.Checked;
}
private void BetuMeret_Click(object sender, EventArgs e)
{
ToolStripMenuItem valasztott = (ToolStripMenuItem)sender;
foreach (ToolStripItem elem in miBetuMeret.DropDownItems)
{
ToolStripMenuItem pont = elem as ToolStripMenuItem;
if (pont != null)
{
pont.Checked = pont == valasztott;
}
}
float meret;
if (float.TryParse(valasztott.Tag.ToString(), out meret))
{
rtbSzoveg.Font = new Font(rtbSzoveg.Font.FontFamily, meret);
tscBetu.SelectedItem = valasztott.Tag.ToString();
}
}
private void tscBetu_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (ToolStripItem elem in miBetuMeret.DropDownItems)
{
ToolStripMenuItem pont = elem as ToolStripMenuItem;
if (pont != null && pont.Tag.ToString() == tscBetu.Text && !pont.Checked)
{
pont.PerformClick(); // a menüpont végzi el, és a pipát is frissíti
}
}
}
private void tsbUj_Click(object sender, EventArgs e) { miUj.PerformClick(); }
private void tsbMegnyit_Click(object sender, EventArgs e) { miMegnyit.PerformClick(); }
private void tsbMent_Click(object sender, EventArgs e) { miMent.PerformClick(); }
private void tsbKivag_Click(object sender, EventArgs e) { miKivag.PerformClick(); }
private void tsbMasol_Click(object sender, EventArgs e) { miMasol.PerformClick(); }
private void tsbBeilleszt_Click(object sender, EventArgs e) { miBeillesztes.PerformClick(); }
private void miNevjegy_Click(object sender, EventArgs e)
{
MessageBox.Show("Jegyzetfüzet 1.0", "Névjegy");
}Megjegyzés: a PerformClick csak engedélyezett menüpontra hat. A Kivágás, Másolás pontok állapotát a DropDownOpening frissíti, ezért az eszköztár gombjának előtte is hívja az állapotfrissítést (például a SelectionChanged eseményben); a gyakorlati megoldás a lecke Gyakorlótárában szerepel.
Mit tegyél ide: a kész jegyzetfüzet a Nézet menü megnyitva (pipák, Betűméret almenü) és az eszköztár.Javasolt fájlnév: winforms-7-1-kesz.webp · Alt szöveg: A jegyzetfüzet menüvel és eszköztárral
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. Menü kódból egy táblázatból
Építs Szín menüt, amelynek pontjai (Piros, Zöld, Kék) egy tömbből jönnek létre ciklusban, közös kezelővel. A kezelő a szöveg színét állítja. Hol tárolod a színt? Az elem Egy lehetséges megoldás
Tag tulajdonságába tehetsz tetszőleges objektumot (Color), így a kezelő nem kell, hogy a nevekből találgasson (5.8 lecke).private void Form1_Load(object sender, EventArgs e)
{
string[] nevek = { "Piros", "Zöld", "Kék" };
Color[] szinek = { Color.Firebrick, Color.SeaGreen, Color.RoyalBlue };
for (int i = 0; i < nevek.Length; i++)
{
ToolStripMenuItem pont = new ToolStripMenuItem(nevek[i]);
pont.Tag = szinek[i];
pont.Click += Szin_Click;
miSzin.DropDownItems.Add(pont);
}
}
private void Szin_Click(object sender, EventArgs e)
{
ToolStripMenuItem pont = (ToolStripMenuItem)sender;
if (pont.Tag is Color szin)
{
rtbSzoveg.ForeColor = szin;
}
}
2. Kapcsoló menü és gomb szinkronban
A Félkövér menüpont ( Az állapot beállítása előtt ellenőrizd, hogy az érték valóban különbözik-e (a CheckOnClick) és az eszköztár F gombja (CheckOnClick) egymást tükrözi. Hogyan akadályozod meg a végtelen visszacsatolást?Egy lehetséges megoldás
CheckedChanged csak változáskor fut), vagy használj jelzőt (5.5 lecke).private bool szinkron = false;
private void miFelkover_CheckedChanged(object sender, EventArgs e)
{
if (szinkron) { return; }
szinkron = true;
tsbFelkover.Checked = miFelkover.Checked;
szinkron = false;
FelkoverAlkalmaz(miFelkover.Checked);
}
private void tsbFelkover_CheckedChanged(object sender, EventArgs e)
{
if (szinkron) { return; }
szinkron = true;
miFelkover.Checked = tsbFelkover.Checked;
szinkron = false;
FelkoverAlkalmaz(tsbFelkover.Checked);
}
3. Eszköztár ikonok DPI-hez
Az eszköztár ikonjai 16 képpontosak. Magasabb DPI-nél élesebb kell. Hogyan oldod meg a Az ToolStrip.ImageScalingSize segítségével?Egy lehetséges megoldás
ImageScalingSize az ikonok méretét adja meg: a DPI szerint állítva (DeviceDpi, 6.8 lecke) a nagyobb ikon élesebb marad, ha a forráskép elég nagy (32 képpontos vagy vektoros). A kicsi képet nagyítani elmosódott eredményt ad.private void Form1_Load(object sender, EventArgs e)
{
int meret = (int)Math.Round(16 * this.DeviceDpi / 96.0);
eszkoz.ImageScalingSize = new Size(meret, meret);
}
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. ShortcutKeys értékek
Add meg kódból a következő gyorsbillentyűket: Új: Ctrl+N; Keresés: Ctrl+Shift+F; Súgó: F1.Megoldás megnyitása
miUj.ShortcutKeys = Keys.Control | Keys.N;
miKeres.ShortcutKeys = Keys.Control | Keys.Shift | Keys.F;
miSugo.ShortcutKeys = Keys.F1;
2. Menüpont letiltása
A Mentés menüpont csak módosított dokumentumnál legyen aktív. Hol állítod az A Enabled értékét: a TextChanged vagy a DropDownOpening eseményben? Mi a különbség a gyorsbillentyűvel?Megoldás megnyitása
modosult jelző változásakor (a módosítás és a mentés helyén) állítsd: a gyorsbillentyű (Ctrl+S) a menü zárva állapotában is érvényesül, ezért az Enabled állapotnak mindig naprakésznek kell lennie, nem csak a menü megnyitásakor. A DropDownOpening a vágólaphoz hasonló, külső állapotok frissítésére való.
Közepes szint
3. Az eszköztár állapota követi a kijelölést
A Kivágás és Másolás eszköztár-gombok legyenek tiltottak kijelölés nélkül. Melyik eseményt használod? A Megoldás megnyitása
SelectionChanged eseményt a RichTextBoxon (2.11 lecke): a kijelölés változásakor azonnal frissíti az eszköztár állapotát.private void rtbSzoveg_SelectionChanged(object sender, EventArgs e)
{
bool van = rtbSzoveg.SelectionLength > 0;
tsbKivag.Enabled = van;
tsbMasol.Enabled = van;
miKivag.Enabled = van;
miMasol.Enabled = van;
}
4. Az utolsó fájlok mentése és betöltése
Az Az útvonalakat utolso lista maradjon meg újraindítás után. Hogyan tárolod egy string típusú Settings beállításban?Megoldás megnyitása
| jellel összefűzzük (fájlnévben nem fordulhat elő), betöltéskor Split-tel bontjuk. Az eltűnt fájlokat kiszűrjük (File.Exists).private void Betolt()
{
string mentett = Properties.Settings.Default.Utolso;
foreach (string ut in mentett.Split('|'))
{
if (ut.Length > 0 && File.Exists(ut))
{
utolso.Add(ut);
}
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Properties.Settings.Default.Utolso = string.Join("|", utolso);
Properties.Settings.Default.Save();
}
Kihívás szint
5. Közös kezelő az egész eszköztárra
Az eszköztár összes gombjához egyetlen kezelő tartozik. A gombok A Tag tulajdonsága a megfelelő menüpont neve (miMent). Hogyan találod meg a menüpontot a név alapján?Megoldás megnyitása
MenuStrip.Items.Find(név, true) keresi a nevet a teljes menüfában (a true az almenükben is keres), és ToolStripItem tömböt ad.private void Eszkoz_Click(object sender, EventArgs e)
{
ToolStripItem gomb = (ToolStripItem)sender;
string nev = gomb.Tag as string;
if (nev == null)
{
return;
}
ToolStripItem[] talalat = menu.Items.Find(nev, true);
if (talalat.Length > 0 && talalat[0] is ToolStripMenuItem pont)
{
pont.PerformClick();
}
}
6. Menü nyelvváltás
A Nyelv menü Magyar és English pontja átírja a menü felirat szövegeit egy szótárból. Hogyan járod be a menüt, és mire kell vigyáznod a mnemonikus A menüfa rekurzív bejárásával (& jelnél?Megoldás megnyitása
DropDownItems), az elem Name értéke a szótár kulcsa. A & jel a szótári szövegben is szerepeljen, és az új nyelvben a betűk ne ütközzenek.private void Fordit(ToolStripItemCollection elemek, bool angol)
{
foreach (ToolStripItem elem in elemek)
{
if (elem.Tag is string[] szovegek)
{
elem.Text = angol ? szovegek[1] : szovegek[0]; // a Tag: { magyar, angol }
}
ToolStripMenuItem pont = elem as ToolStripMenuItem;
if (pont != null)
{
Fordit(pont.DropDownItems, angol);
}
}
}
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. A A menüpont A kezelő törli a testvérek pipáját, és beállítja a választottét; A menü megnyitása előtt frissíti a pontok állapotát (például vágólap). Az eszköztár gombja a menüpontot nyomja meg ( A Semmit: nem fut le a kezelő.1. Mi a menüelemek közös őse?
ToolStripItem (nem Control).2. Hol állítod a gyorsbillentyűt?
ShortcutKeys tulajdonságában. Az egész ablakon érvényes, a menü zárva állapotában is.3. Hogyan készítesz választócsoportot a menüben?
CheckOnClick nélkül.4. Mire való a DropDownOpening?
5. Hogyan kerüld el a dupla kódot menü és eszköztár között?
PerformClick), a funkció a menüpont kezelőjében van.6. Hogyan ismered fel a dinamikus menüelemet?
Name előtagjáról (például miUtolso); a Tag az adatot (útvonal) hordozza.7. Mit tesz a PerformClick letiltott menüponton?
Mit tudsz már?
- Menüt építesz tervezőben és kódból, gyorsbillentyűkkel.
- Kapcsoló és választócsoport-szerű menüpontokat készítesz.
- A menü állapotát a megnyitáskor frissíted, és dinamikus listát építesz.
- Eszköztárat készítesz, amely a menüvel közös kódot használ.
- Felismered a gyakori menühibákat.
Következő lecke: ContextMenuStrip és helyi menü
A jobb egérgombbal előhívott menü: dinamikus elemek, a kattintott vezérlő azonosítása és saját helyi menü a szövegmezőhöz.



