8. Párbeszéd ablakok (Dialog boxes)
2014.06.07. 22:36
Példa: dlg_one
Párbeszéd ablakok, a grafikus felület (GUI) fejlesztőinek barátja
Nehezen találunk olyan windózos programot, ami ne alkalmazna párbeszéd paneleket. Elég megkeresni kedvenc szövegszerkesztőnkben a Fájl menü Megnyitás parancsát, és máris ott van előttünk egy ilyen. Nem csak a fájl megnyitás lehet párbeszéd ablak! Nagy előnye, hogy gyorsan össze lehet dobni egy felhasználói felületet (GUI azaz grafikus felhasználói felület). Ezek az alapértelmezett műveleteket el is tudják végezni, nekünk csak a lényegi dolgokkal kell foglalkoznunk. A párbeszéd panelek pontosan azt tudják mint a hagyományos ablakok, de lényegi eltérés, hogy kiegészülnek pár alapvető funkcióval. Ilyen a vezérlők létrehozása és kezelése. Szinte az összes API használható ablakon, és párbeszéd panelen egyaránt!
Első lépésként létrehozzuk a párbeszéd panel erőforrást. Ez természetesen függ a fordítótól, mi most a szöveges változatot írjuk meg.
IDD_ABOUT DIALOG DISCARDABLE 0, 0, 239, 66 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "My About Box" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "&OK",IDOK,174,18,50,14 PUSHBUTTON "&Cancel",IDCANCEL,174,35,50,14 GROUPBOX "About this program...",IDC_STATIC,7,7,225,52 CTEXT "An example program showing how to use Dialog Boxes\r\n\r\nby theForger", IDC_STATIC,16,18,144,33 END
Az első sorban az IDD_ABOUT az erőforrás azonosítója, DIALOG az erőforrás típusa, a számok pedig az X, Y, Szélesség, Magasság dimenziói. Ezek nem pixelben értendőek! Ez függ a szöveg méretétől (ami pedig a felhasználó beállításaitól). Nagyobb betűméret esetén a párbeszéd ablak is nagyobb lesz, kissebb esetén meg kissebb. Így biztosított, hogy a felhasználó minden esetben el tudja olvasni a szöveget. Azért van befolyásunk a méretre, mégpedig a MapDialogRect() segítségével. Ez már pixel alapú. A DISCARDABLE azt jelenti, hogy ha akarja, akkor a windóz swappelheti az erőforrásunkat.
A következő sor a STYLE-lal kezdődik, és azt követi a létrehozandó párbeszéd panel stílusa. Ahhoz, hogy az előredefiniált konstansokat használni tudjuk, szükséges include-olni a window.h fejléc állományt az .rc fájlunkban, vagy ha VC++-t használunk, akkor winres.h-ban, vagy afxres.h-ban. A szerkesztő lehet ezt automatikusan meg is teszi.
A CAPTION sor egy magyarázó szöveg.
A FONT sor határozza meg az alkalmazott font nevét és méretét. Ettől még nem fog minden számítógépen, minden felhasználónál ugyanúgy megjelenni. Általában ez nem okoz gondot.
Jöhetnek a párbeszéd ablak vezérlői.
DEFPUSHBUTTON "&OK",IDOK,174,18,50,14
Ez egy "OK" gomb lesz. Az idézőjelben az '&' jel az azt követő karaktert aláhúzza. Ez azt eredményezi, hogy ha megnyomjuk az Alt+O kombinációt, az ugyanaz, mintha megnyomtuk volna a gombot. Nem feltétlenül van így szükség egérre. Az IDOK az azonosítója. Ezt nem kell külön definiálnunk, mert már előre definiált. A számok a sor végén az X,Y pozíciók, és a szélesség, magasság értékek.
Két helyen is szerepel az ID_STATIC azonosító (ami -1 értéket képvisel). Ezzel azt jelezzük, hogy mi nem akarjuk használni, nincs is szükségünk azonosítóra. A fordító magától is csinálhat ilyet.
A "\r\n" a windózos újsor jelölés, ez gondolom senkinek sem új dolog.
Most, hogy ez mind bekerült az .rc fájlba, itt az ideje hogy elkészüljön a párbeszéd eljárás is. Nem kell aggódni, kvázi ugyanaz mint a WindProc().
BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: EndDialog(hwnd, IDOK); break; case IDCANCEL: EndDialog(hwnd, IDCANCEL); break; } break; default: return FALSE; } return TRUE; }
Van pár fontos eltérés a párbeszéd eljárás, és a window eljárás között. Nem hívjuk meg a DefWindowProc() eljárást! Ha mégis megtesszük, akkor érdekes dolgok történhetnek.
Ezt nem értem, valaki lefordíthatná nekem:
"Secondly, in general you return FALSE for messages you don't process, and TRUE for messages you do process, UNLESS the message specifies you return something else. Note that this is what we do above, the default is to do nothing and return FALSE, while messages we do handle break the switch() and return TRUE."
Harmadszor, nem hívjuk meg a DestroyWindow() eljárást hogy bezárjuk a párbeszéd ablakot, helyette az EndDialog()-ot használjuk. Második paramétere az az érték, amit a DialogBox() adott.
Végezetül anélkül hogy a WM_CREATE-et kezelnénk, a WM_INITDIALOG amivel foglalkozunk, hogy végrehajtsuk a párbeszéd ablak megnyitása előtt szükséges dolgokat. Ezután TRUE-val visszatérünk, a billentyűzet fókuszt pedig megkapja az alapértelmezett vezérlő. Valójában kezelhetjük a WM_CREATE üzenetet is, de ez még azelőtt megjelenik, mielőtt a vezérlők létrejönnének, ezért azokhoz nem férünk hozzá. A WM_INITDIALOG érkezésekor már létrejöttek a vezérlők is.
case WM_COMMAND: switch(LOWORD(wParam)) { case ID_HELP_ABOUT: { int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc); if(ret == IDOK){ MessageBox(hwnd, "Dialog exited with IDOK.", "Notice", MB_OK | MB_ICONINFORMATION); } else if(ret == IDCANCEL){ MessageBox(hwnd, "Dialog exited with IDCANCEL.", "Notice", MB_OK | MB_ICONINFORMATION); } else if(ret == -1){ MessageBox(hwnd, "Dialog failed!", "Error", MB_OK | MB_ICONINFORMATION); } } break; // Other menu commands... } break;
Ezzel a kóddal hozzuk létre az "about box"-ot, amit beleteszünk a WM_COMMAND() kezelőbe. Ha nem tiszta teljesen, akkor a menüvel foglalkozó részben le volt írva részletesen. Az ID_HELP_ABOUT azonosító a Help menü About menüpontjára hivatkozik. Mivel ezt a menüt a fő ablakban szeretnénk látni, ezért a kódot nem a párbeszéd ablakban, hanem a fő ablak WndProc() eljárásába kell tenni.
Most hogy eltároltuk a DialogBox() visszatérési értékét, láthatjuk annak a hatását, ha megnyomunk valamit (Esc, Enter stb).
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);
IDD_ABOUT a párbeszéd ablak erőforrás azonosítója, hwnd a szülőablak handlere. Az AboutDlgProc() a párbeszéd ablak vezérlőit kezeli.
Felmerül a kérdés, hogy ha a DialogBox() még nem tért vissza, akkor hogyan tudjuk kezelni az üzeneteit. A DialogBox() is rendelkezik saját üzenethurokkal. Ez gondoskodik arról, hogy ha Tab billentyűt nyomunk, akkor a billentyű fókusz vándoroljon vezérlőről vezérlőre.
A DialogBox() használatának másik hatása, hogy amíg be nem zárjuk, addig a fő ablak inaktív lesz. Van hogy ez jó nekünk, és van hogy nem (például lebegő eszköztárnak használnánk). A következőkben erre helyezzük a hangsúlyt.
A bejegyzés trackback címe:
Kommentek:
A hozzászólások a vonatkozó jogszabályok értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a Felhasználási feltételekben és az adatvédelmi tájékoztatóban.