Grafikus C# – Windows Forms tanfolyam › 7.5 lecke

Windows Forms · 7.5 lecke · több ablak

Form.Show és Form.ShowDialog

Egy valódi program nem egyetlen ablakból áll: van beállítóablak, névjegy, keresőablak, szerkesztő, eszköztár-ablak. Az ablakok megnyitására két metódus szolgál: a Show() nem modális ablakot nyit (a felhasználó közben a főablakban is dolgozhat), a ShowDialog() modálisat (addig nem lehet másik ablakot használni, amíg be nem zárul, és a kód megvárja az eredményt). Ebben a leckében megtanulod a különbséget, a tulajdonos (Owner) kapcsolatot, az ablak élettartamát (Close, Hide, Dispose) és az egypéldányos ablak mintáját.

  • kb. 100 perc
  • közepes szint
  • több ablak
Diáklány C# programot készít laptopon

A lecke végére

  • megkülönbözteted a Show és a ShowDialog viselkedését és használatát;
  • a tulajdonost (Owner) helyesen adod meg, és érted a hatását;
  • tudod, mikor semmisül meg az ablak (Close), és mikor kell kézzel felszabadítani (ShowDialog);
  • egypéldányos nem modális ablakot készítesz (IsDisposed, FormClosed);
  • az Application.OpenForms segítségével kezeled a nyitott ablakokat;
  • felismered a gyakori hibákat (ObjectDisposedException, using a Show mellett, ablakok halmozódása).

Mielőtt elkezded

Ehhez a leckéhez a 6.7 lecke (ShowDialog és DialogResult első bemutatása), az 5.6 lecke (FormClosed, Application.OpenForms) és az 5.7 lecke (feliratkozás, leiratkozás) szükséges.

7.4 MessageBox →

Nem modális és modális ablak

Show() (nem modális)ShowDialog() (modális)
A hívó kódAzonnal továbbfut (nem vár).Megáll, amíg az ablak be nem záródik.
A hívó ablakHasználható marad.Le van tiltva, amíg a dialógus nyitva van.
Visszatérési értékNincs (void).DialogResult (6.7 lecke).
Mire való?Önálló munkaablak, eszköztár, kereső, súgó, megfigyelő.Döntés vagy adat bekérése: beállítás, mentés kérdés, bejelentkezés.
BezáráskorMegsemmisül (Dispose).Csak elrejtődik: kézzel kell felszabadítani (using).
Form1.csC#
// nem modális: a tulajdonos a főablak, a kód azonnal folytatódik
private void btnKereso_Click(object sender, EventArgs e)
{
KeresoForm ablak = new KeresoForm();
ablak.Show(this); // az Owner = this
lblInfo.Text = "A kereső megnyílt."; // ez azonnal lefut
}

// modális: a kód megvárja az ablak bezárását
private void btnBeallitas_Click(object sender, EventArgs e)
{
using (BeallitasForm ablak = new BeallitasForm())
{
if (ablak.ShowDialog(this) == DialogResult.OK)
{
lblInfo.Text = "A beállítások elfogadva."; // csak a bezárás után fut le
}
}
}
OwnerA Show(this) és a ShowDialog(this) beállítja a tulajdonost. A tulajdonos ablak fölött marad az ablak, vele együtt kicsinyítődik és záródik be, és a CenterParent értékű StartPosition ennek közepére helyezi. Tulajdonos nélkül az ablak független, és a főablak mögé kerülhet.
Modális: letiltott hívóA modális ablak az alkalmazás többi ablakát letiltja. A felhasználó nem tud a főablakba kattintani, ezért a dialógust nem lehet „elfelejteni”.
Mikor melyik?Ha az ablak választ ad (OK/Mégse, érték), modális. Ha a felhasználó közben mást is csinálna (szerkeszt, miközben keres), nem modális.
A hívó ablak eltűnéseA ShowDialog alatt a hívó kód „áll”, de az üzenetek feldolgozása (Timer, újrarajzolás) működik: az időzítők a modális ablak alatt is futnak.

Jósolj!

A kereső ablakot Show() hívással nyitod meg (tulajdonos nélkül), majd a főablakra kattintasz. Mi történhet a kereső ablakkal?

Jóslat ellenőrzése

A kereső ablak a főablak mögé kerülhet (nincs tulajdonos, ami fölötte tartaná), és a tálcán külön gombként látszik. A Show(this) megadja a tulajdonost, így az ablak a főablak fölött marad, és vele együtt kicsinyedik.

Az ablak élettartama: Close, Hide, Dispose

Close()

Bezárja az ablakot. A Show() ablaknál ez megsemmisíti (Dispose): az objektum nem használható újra, a Show() második hívása ObjectDisposedException kivételt dob. A ShowDialog() ablaknál a Close csak elrejti, az objektum él tovább, és a Dispose a hívó dolga (using).

Hide()

Elrejti az ablakot (Visible = false), de megőrzi az állapotát (a beírt szöveget, a vezérlők értékét). A Show() újra megjeleníti ugyanazt a példányt. Ez az „eltűnik és visszatér” ablak módja.

Form1.csC#
KeresoForm kereso = new KeresoForm();
kereso.Show(this);
kereso.Close();
kereso.Show(this); // ObjectDisposedException: a bezárt ablak megsemmisült

// helyesen: elrejtés és újramegjelenítés ugyanazzal a példánnyal
kereso.Hide();
kereso.Show(this); // működik, az állapot megmaradt

// vagy: új példány a bezárás után
if (kereso == null || kereso.IsDisposed)
{
kereso = new KeresoForm();
}

kereso.Show(this);

A klasszikus csapda: using a Show() mellett

A using (var ablak = new Form2()) { ablak.Show(); } a blokk végén azonnal felszabadítja az ablakot, ezért az megjelenik, majd azonnal eltűnik. A using csak a ShowDialog mellett helyes, mert az megvárja a bezárást. A Show() ablak magától megsemmisül, amikor bezárják.

Jósolj!

Egy beállítóablakot ShowDialog() hívással nyitsz meg using nélkül, és minden gombnyomásra új példányt hozol létre. Mit tapasztalsz a program memóriahasználatánál sok megnyitás után?

Jóslat ellenőrzése

A modális ablak bezáráskor csak elrejtődik, és Dispose nélkül erőforrásai (vezérlők, kezelők) csak a szemétgyűjtésig élnek tovább: sok megnyitás után a memória- és GDI-objektumok száma észrevehetően nőhet. A using (vagy a Dispose() hívás) a bezárás után azonnal felszabadít.

Egypéldányos nem modális ablak

Gyakori igény: az eszköztár- vagy keresőablak egyetlen példányban létezzen. Ha a felhasználó másodszor is megnyomja a gombot, ne nyíljon újabb ablak, hanem a meglévő kerüljön előre:

Form1.csC#
private PaletteForm paletta = null;

private void btnPaletta_Click(object sender, EventArgs e)
{
if (paletta == null || paletta.IsDisposed)
{
paletta = new PaletteForm();
paletta.FormClosed += Paletta_FormClosed; // ha bezárják, a mezőt nullázzuk
paletta.Show(this);
}
else
{
if (paletta.WindowState == FormWindowState.Minimized)
{
paletta.WindowState = FormWindowState.Normal;
}

paletta.Activate(); // előre hozza, a fókuszt is megkapja
}
}

private void Paletta_FormClosed(object sender, FormClosedEventArgs e)
{
paletta.FormClosed -= Paletta_FormClosed; // 5.7 lecke: leiratkozás
paletta = null;
}
IsDisposedA bezárt (megsemmisült) ablak IsDisposed értéke igaz. A mező null vagy IsDisposed vizsgálata megmondja, kell-e új példány.
ActivateAz Activate() előrehozza az ablakot, és a fókuszt is neki adja. A BringToFront() csak a sorrendet változtatja.
FormClosed és nullA bezáráskor a mezőt nullázva a következő megnyitás új példányt készít, és a régi ablak felszabadulhat (nem marad rá hivatkozás).
Hide a Close helyettHa az ablak állapota (kijelölés, beírt szöveg) megőrzendő, a bezáráskor elrejtsd: a FormClosing eseményben e.Cancel = true; this.Hide(); (csak UserClosing esetén, a program kilépésekor engedd a bezárást).

Jósolj!

A Paletta_FormClosed kezelőben nem nullázod a paletta mezőt, de az IsDisposed vizsgálat megvan. Működik-e a második megnyitás?

Jóslat ellenőrzése

Igen: az IsDisposed igaz a bezárt ablakra, ezért új példány készül. A null beállítás kényelmes, és a régi, bezárt ablakra mutató hivatkozást is eltávolítja (a szemétgyűjtő felszabadíthatja), de a működéshez az IsDisposed elég.

A nyitott ablakok kezelése

Form1.csC#
// az összes nyitott ablak listája (a főablakot is tartalmazza)
private void ListaFrissit()
{
lstAblakok.Items.Clear();

foreach (Form f in Application.OpenForms)
{
lstAblakok.Items.Add(f.Text + " (" + f.GetType().Name + ")");
}
}

// az összes tulajdonolt ablak bezárása: másolat a bejáráshoz, mert a gyűjtemény módosul
private void btnMindBezar_Click(object sender, EventArgs e)
{
Form[] tulajdonolt = this.OwnedForms; // már másolat (tömb)

for (int i = tulajdonolt.Length - 1; i >= 0; i--)
{
tulajdonolt[i].Close();
}
}

// az aktív ablak
Form aktiv = Form.ActiveForm; // null, ha a program ablaka nem aktív
Application.OpenFormsA program összes nyitott (megjelenített) ablakának gyűjteménye. Bezárás közben módosul, ezért a bejáráshoz érdemes másolatot készíteni, vagy visszafelé haladó for ciklust használni.
OwnedFormsA tulajdonolt ablakok tömbje (az Owner kapcsolat alapján). A főablak bezárásakor ezek is bezáródnak.
A főablak bezárásaAz Application.Run által indított főablak bezárásakor a program kilép, a többi ablak is bezáródik. Ha a főablak helyett másik ablaknak kell tovább élnie, a program szerkezetét kell átgondolni (a bejelentkező ablak mintája, 6.7 lecke).
Form.ActiveFormAz éppen aktív ablak. A null érték azt jelzi, hogy a program egyik ablaka sem aktív (például másik programra váltottak).

Jósolj!

A foreach (Form f in Application.OpenForms) { if (f != this) f.Close(); } ciklus bezár minden más ablakot. Mi a hiba veszélye?

Jóslat ellenőrzése

A bezárás módosítja a bejárt gyűjteményt, ezért a foreach InvalidOperationException kivételt dobhat (a gyűjtemény módosult), vagy kihagyhat ablakokat. Biztonságos megoldás: előbb másolat egy listába, vagy visszafelé haladó for ciklus (a Application.OpenForms[i] indexeléssel).

📷 Képernyőkép helye

Mit tegyél ide: a főablak a nyitott ablakok listájával, mellette két dokumentumablak és az eszköztár-ablak.Javasolt fájlnév: winforms-7-5-ablakok.webp · Alt szöveg: A főablak és a tulajdonolt ablakok

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. ObjectDisposedException a második megnyitáskor

private KeresoForm kereso = new KeresoForm();

private void btnKereso_Click(object sender, EventArgs e)
{
kereso.Show(this); // az első bezárás után megsemmisült
}
Hiba és javítás

A bezárt ablak megsemmisült. Készíts új példányt, ha a mező null vagy IsDisposed, vagy a bezárás helyett Hide() hívással rejtsd el.

2. Az ablak megjelenik, és azonnal eltűnik

using (RiportForm ablak = new RiportForm())
{
ablak.Show(); // a blokk végén felszabadul
}
Hiba és javítás

A using a Show azonnali visszatérése után felszabadítja az ablakot. Nem modális ablaknál ne használj using-ot (az ablak magától megsemmisül bezáráskor), modálisnál (ShowDialog) a using helyes.

3. Minden gombnyomásra új ablak nyílik

A kereső ablakból tíz példány jelenik meg.

Ok és javítás

Nem őrzöl hivatkozást a meglévőre. Használd az egypéldányos mintát: mező, IsDisposed vizsgálat, Activate().

4. A dialógus eredményét hibásan veszi a kód

ablak.ShowDialog(this);
lblNev.Text = ablak.Nev; // akkor is, ha a felhasználó a Mégse gombot nyomta
Hiba és javítás

Az eredményt vizsgálni kell: if (ablak.ShowDialog(this) == DialogResult.OK) { ... }. Mégse esetén az adatot nem szabad átvenni.

5. A főablak mögé kerül az ablak

A segédablak elvész a főablak mögött.

Ok és javítás

Nincs tulajdonos. Használd a Show(this) hívást (vagy az Owner tulajdonságot).

6. InvalidOperationException az ablakok bezárásakor

foreach (Form f in Application.OpenForms)
{
if (f != this) { f.Close(); } // a gyűjtemény módosul
}
Hiba és javítás

Készíts másolatot egy listába, és azon haladj, vagy használj visszafelé haladó for ciklust az OpenForms[i] indexeléssel.

Mini projekt: ablakkezelő

Készíts programot, amely a három ablaktípust és az élettartamot szemlélteti:

  1. Főablak (Form1): gombok: Új dokumentumablak, Paletta (egy példány), Paletta elrejtése / megjelenítése, Modális kérdés, Mind bezár; egy lstAblakok lista (a nyitott ablakok), egy lblInfo címke és egy 1 másodperces időzítő a lista frissítéséhez.
  2. DokumentumForm: egy RichTextBox, a cím Dokumentum N (a főablak számlálója adja). A főablak Show(this) hívással nyitja, és nem kell using.
  3. PaletteForm: egypéldányos, nem modális; a bezárásakor a főablak mezője nullázódik; az elrejtés gomb Hide() hívással elrejti (az állapot megmarad), a megjelenítés ugyanazt a példányt hozza vissza. A palettán egy TextBox van, amelynek tartalma az elrejtés után is megmarad (a bizonyíték).
  4. KerdesForm: modális ablak Igen és Nem gombbal (DialogResult), using blokkban; az eredmény a lblInfo címkében.
  5. A Mind bezár gomb visszafelé haladva bezárja a OwnedForms összes ablakát.
  6. Teszteld: több dokumentumablak, a palette második megnyitása (előrehozás), elrejtés és megjelenítés (a szöveg megmarad), bezárás utáni új palette (üres szöveg), a modális kérdés alatt a főablak letiltása, a főablak kicsinyítése (a tulajdonolt ablakok vele mennek), a lista pontossága.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A palette elrejtése és újra megjelenítése ugyanazt a példányt használja, a bezárás viszont megsemmisíti. A lista frissítését az időzítő végzi, mert az ablakok maguktól záródhatnak.

Form1.csC#
private PaletteForm paletta = null;
private int szamlalo = 0;

private void Form1_Load(object sender, EventArgs e)
{
tmrLista.Interval = 1000;
tmrLista.Start();
ListaFrissit();
}

private void tmrLista_Tick(object sender, EventArgs e)
{
ListaFrissit();
}

private void ListaFrissit()
{
lstAblakok.Items.Clear();

foreach (Form f in Application.OpenForms)
{
string allapot = f.Visible ? "" : " (rejtett)";
string tulajdonos = f.Owner == null ? "" : " ← " + f.Owner.Text;

lstAblakok.Items.Add(f.Text + " [" + f.GetType().Name + "]" + allapot + tulajdonos);
}
}

private void btnUjDok_Click(object sender, EventArgs e)
{
szamlalo = szamlalo + 1;

DokumentumForm dok = new DokumentumForm(szamlalo);
dok.Show(this); // nem modális, tulajdonos a főablak; using nélkül
ListaFrissit();
}

private void btnPaletta_Click(object sender, EventArgs e)
{
if (paletta == null || paletta.IsDisposed)
{
paletta = new PaletteForm();
paletta.FormClosed += Paletta_FormClosed;
paletta.Show(this);
}
else
{
if (paletta.WindowState == FormWindowState.Minimized)
{
paletta.WindowState = FormWindowState.Normal;
}

if (!paletta.Visible)
{
paletta.Show(this);
}

paletta.Activate();
}

ListaFrissit();
}

private void Paletta_FormClosed(object sender, FormClosedEventArgs e)
{
paletta.FormClosed -= Paletta_FormClosed;
paletta = null;
}

private void btnPalettaRejt_Click(object sender, EventArgs e)
{
if (paletta != null && !paletta.IsDisposed)
{
if (paletta.Visible)
{
paletta.Hide(); // az állapot (szöveg) megmarad
}
else
{
paletta.Show(this);
}

ListaFrissit();
}
}

private void btnKerdes_Click(object sender, EventArgs e)
{
using (KerdesForm kerdes = new KerdesForm("Folytatod?"))
{
DialogResult v = kerdes.ShowDialog(this); // a hívó kód itt vár

lblInfo.Text = v == DialogResult.Yes ? "Igen" : "Nem";
}
}

private void btnMindBezar_Click(object sender, EventArgs e)
{
Form[] tulajdonolt = this.OwnedForms;

for (int i = tulajdonolt.Length - 1; i >= 0; i--)
{
tulajdonolt[i].Close();
}

ListaFrissit();
}

// PaletteForm.cs: a FormClosing-ban nincs külön kód; a btnRejt: this.Hide();
// DokumentumForm.cs: public DokumentumForm(int szam) { InitializeComponent(); this.Text = "Dokumentum " + szam; }
// KerdesForm.cs: btnIgen.DialogResult = Yes; btnNem.DialogResult = No; AcceptButton = btnIgen; CancelButton = btnNem;
📷 Képernyőkép helye

Mit tegyél ide: a főablak az ablaklistával (két dokumentum, egy rejtett paletta) és a nyitott ablakok.Javasolt fájlnév: winforms-7-5-kesz.webp · Alt szöveg: Az ablakkezelő program

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. Egypéldányos súgóablak

A F1 billentyű vagy a Súgó menüpont egyetlen súgóablakot nyit. Ha már nyitva van, kerüljön előre. Hol tárolod a példányt?

Egy lehetséges megoldás

A főablak mezőjében, az IsDisposed vizsgálattal és az Activate() hívással. A menüpont gyorsbillentyűje (F1, 7.1 lecke) hívja ugyanazt a kezelőt.

Form1.csC#
private SugoForm sugo = null;

private void miSugo_Click(object sender, EventArgs e)
{
if (sugo == null || sugo.IsDisposed)
{
sugo = new SugoForm();
sugo.Show(this);
}
else
{
sugo.Activate();
}
}

2. Modális dialógus eredmény nélkül

A felhasználó a Beállítások ablakot a bezáró X gombbal zárja be. Mit ad vissza a ShowDialog, és hogyan kezeled?

Egy lehetséges megoldás

DialogResult.Cancel értéket (az X gomb így zár). Ezért csak az OK eredménynél veszed át az adatokat.

3. Dokumentumablakok száma

A főablak címsora mutassa a nyitott dokumentumablakok számát (Főablak – 3 dokumentum). Hogyan számolod, és mikor frissíted?

Egy lehetséges megoldás

A OwnedForms tömb elemeit típus szerint számolod (is DokumentumForm). A frissítés a nyitáskor és az ablakok FormClosed eseményén történik (a bezáráskor a tulajdonolt ablakok száma már csökkent).

Form1.csC#
private void CimFrissit()
{
int db = 0;

foreach (Form f in this.OwnedForms)
{
if (f is DokumentumForm)
{
db++;
}
}

this.Text = "Főablak – " + db + " dokumentum";
}

private void Dok_FormClosed(object sender, FormClosedEventArgs e)
{
((Form)sender).FormClosed -= Dok_FormClosed;
CimFrissit();
}

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. Melyik metódus?

Show vagy ShowDialog: (a) beállítóablak OK/Mégse gombbal; (b) kereső, amely közben a szerkesztőt is használni kell; (c) bejelentkezés indulás előtt; (d) nyomtatási előnézet.

Megoldás megnyitása

(a) ShowDialog; (b) Show; (c) ShowDialog; (d) általában ShowDialog (a felhasználó azonnal döntést vár), de külön ablakként is lehet Show.

2. Mi a különbség Close és Hide között?

Magyarázd el két mondatban.

Megoldás megnyitása

A Close a Show ablakot megsemmisíti, a példány nem használható újra. A Hide csak elrejti, az állapota megmarad, és a Show újra megjeleníti.

Közepes szint

3. Hide bezáráskor

A keresőablak X gombja ne zárja be, hanem rejtse el (az állapota megmarad), de a program kilépésekor engedje a bezárást. Hol kezeled?

Megoldás megnyitása

A FormClosing eseményben, a CloseReason vizsgálatával.

KeresoForm.csC#
private void KeresoForm_FormClosing(object sender, FormClosingEventArgs e){
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true; // nem zárjuk be
this.Hide(); // csak elrejtjük
}
}

4. Ablak a tálca nélkül

A segédablak ne kapjon tálcagombot. Mely tulajdonságot állítod, és mi a következménye, ha nincs tulajdonos?

Megoldás megnyitása

A ShowInTaskbar = false. Tulajdonos nélkül az ablak a főablak mögé kerülhet, és a felhasználó nem találja meg: ilyenkor a Show(this) (Owner) és/vagy TopMost szükséges.

Kihívás szint

5. Mindig a tulajdonos közepén

Írj segédmetódust (Megnyit(Form ablak)), amely egy ablakot a főablak közepére helyez és megnyit. Mit állítasz?

Megoldás megnyitása

A StartPosition = CenterParent (tulajdonossal együtt működik), és a Show(this).

Form1.csC#
private void Megnyit(Form ablak){
ablak.StartPosition = FormStartPosition.CenterParent;
ablak.ShowInTaskbar = false;
ablak.Show(this);
}

6. Az utolsó ablak bezárása után kilépés

A program több független ablakból áll (nincs főablak): az utolsó ablak bezárásakor lépjen ki. Hogyan oldod meg az Application.Run segítségével?

Megoldás megnyitása

Az Application.Run(new ApplicationContext()) saját környezettel, amelynek ExitThread() hívása az utolsó ablak bezárásakor történik. Haladó téma: egyszerűbb, ha van egy főablak, amely a többi tulajdonosa.

Program.csC#
public class TobbAblakKornyezet : ApplicationContext{
private int nyitott = 0;

public void Hozzaad(Form ablak)
{
nyitott = nyitott + 1;

ablak.FormClosed += (s, e) =>
{
nyitott = nyitott - 1;

if (nyitott == 0)
{
ExitThread();
}
};

ablak.Show();
}
}

Gyors önellenőrzés

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

1. Mi a különbség a Show és a ShowDialog között?

A Show nem modális, azonnal visszatér. A ShowDialog modális, megvárja a bezárást, és DialogResult értéket ad.

2. Mire való az Owner?

A tulajdonos ablak fölött marad az ablak, vele kicsinyedik és záródik, és a CenterParent annak közepére helyezi.

3. Mikor semmisül meg az ablak?

A Show() ablak a Close() hívásakor. A ShowDialog() ablak csak elrejtődik: a Dispose a hívó dolga (using).

4. Miért hibás a using a Show mellett?

A blokk végén azonnal felszabadítja az ablakot, ezért az megjelenik és azonnal eltűnik.

5. Hogyan készítesz egypéldányos ablakot?

Mezőben tárolod, null vagy IsDisposed esetén új példányt készítesz, egyébként Activate().

6. Hogyan zárod be az összes ablakot biztonságosan?

Másolatból vagy visszafelé haladó for ciklussal (OwnedForms tömb, OpenForms[i]).

7. Mit ad vissza a ShowDialog az X gomb után?

DialogResult.Cancel értéket (ha a DialogResult nincs más módon beállítva).

Mit tudsz már?

  • Megkülönbözteted a modális és a nem modális ablakot, és tudod, mikor melyiket válaszd.
  • Helyesen kezeled az ablak élettartamát (Close, Hide, Dispose).
  • Egypéldányos ablakot készítesz, és az Owner kapcsolatot használod.
  • Kezeled a nyitott ablakokat (OpenForms, OwnedForms) biztonságosan.
  • Felismered a gyakori hibákat (ObjectDisposedException, using a Show mellett).

Következő lecke: Új Form hozzáadása és modalitás

Hogyan készíts saját párbeszédablakot: a tervezés szabályai, a modalitás fajtái és egy nem modális keresőablak a főablakkal összekötve.