Menu's en resources
Ontwerp van Pull-Down Menu's met PBIDLLDoor Alan C. Earnshaw Vorige keer hebben we laten zien hoe resources vanuit een PB/DLL programma kunnen worden gebruikt. In dit laatste artikel in onze drieluik over Windows resources zullen we een blik werpen op pull-down menus. We kijken hoe een menu resource wordt gemaakt, hoe een menu wordt getoond, en hoe er gereageerd moet worden op menu selectie. Hoewel menus ook handmatig kunnen worden gemaakt met Windows API aanroepen, is het veel gemakkelijker om een resource script te gebruiken om ze te definiëren, dus daarom behandelen we de handmatige aanmaak van menus niet in dit artikel.
MENU RESOURCESVoor zover we weten zijn er geen interactieve ontwerp gereedschappen beschikbaar die menu resource scripts kunnen maken. Ze moeten handmatig worden geschreven. Een menu resource is op dezelfde wijze gestructureerd als andere resources, met een naam, het MENU trefwoord en de data die het menu bevat. De verschillende dingen (items) die in het menu verschijnen (we zullen ze in dit artikel menu-items of items noemen) worden omgeven door een paar accolades ( { } ) of tussen de BEGIN en END trefwoorden. Elk item van een menu wordt in het resource script met één van de volgende trefwoorden opgegeven:
of
MENUITEM wordt gebruikt voor items die door de gebruiker kunnen worden gekozen; POPUP wordt gebruikt om aan te geven dat een submenu zal worden geactiveerd als de gebruiker dit item selecteert. Als u een ampersand ( & ) in de tekst van een items zet, zal de letter die onmiddellijk volgt op dit teken als een HOTKEY voor dat item dienst doen (dus Me&nu gebruikt ALT +N als HOTKEY). De item nummers zijn unieke nummers die zijn toegewezen aan de menu items. Dit nummer wordt in het programma gebruikt om de optie aan te geven die een gebruiker uit het menu heeft geselecteerd. Onze voorbeeld-code gebruikt zogenaamde hard-coded nummer als item nummers, hetgeen niet per se de beste programmeerstijl is. Een betere benadering is de aanmaak van een include bestand voor het resource script dat #define gebruikt om constanten te gebruiken, zoals:
Daarna maakt u een apart include bestand aan voor uw programma dat PB/DLL constanten gebruikt om dezelfde waardes toe te wijzen aan de namen.
Het gebruik van deze methode maakt uw programma leesbaarder bij zowel het maken van een programma, als bij het debuggen van uw code. Er zijn verschillende mogelijkheden die bij een menu item gebruikt kunnen worden:
Voor pop-up menus (die onder de menu balk worden getoond), zijn er nog twee andere mogelijkheden:
Er is nog een speciaal item dat in pop-up menus kan worden gebruikt: MENUITEM SEPARATOR. Dit menu item plaatst een horizontale lijn in het menu. Het wordt vaak gebruikt om groepen items van elkaar te scheiden. Kijk eens naar het resource script in Listing 1. Het definieert een menu voor ons voorbeeld programma. Zoals u ziet staan er vier items op de menu balk: FILE, EDIT, ACTIONS en HELP. Elk van deze items heeft een submenu, waarvan de definities ingebed zijn in het resource script (listing 1 laat zien hoe de nesting wordt gedaan). Figuur 1 toont het menu bij uitvoering:
KOPPELEN VAN MENUS AAN WINDOWSEen resource script kan een aantal menus bevatten. Er zijn drie methodes om een
menu uit uw resource script te laden. U kunt het menu definiëren in de Window class
definitie, u kunt het menu instellen als u de CreateWindow functie aanroept, of u kunt de
SetMenu aanroep van de Windows API gebruiken. Om een menu in de Window class definitie te laden, slaat u de naam van het menu (zoals gespecificeerd in het resource script) op in een ASCIIZ string variabele, waarna u een pointer naar de ASCIIZ string plaatst in het lpszMenuName-veld van de Window class variabele. Bijvoorbeeld:
associeert het menu met de naam MainMenu aan het scherm zoals gedefinieerd in de wClass type variabele. Als u het menu wilt instellen bij de aanroep van de CreateWindow functie behoort u het lpszMenuName-veld in de Window class definitie op %NULL in te stellen. Daarna vervangt u de negende parameter van de CreateWindow functie door de menu handle (=variabele die het menu identificeert) die naar uw menu wijst. Eerst laadt u het menu uit uw programmas resource en verkrijgt u de handle ernaar:
Vervolgens gebruikt u de verkregen handle voor de aanroep in de CreateWindow aanroep:
Als u %NULL gebruikt voor het lpszMenuName-veld in de Window class en %NULL als de menu handle in de aanroep van de CreateWindow functie, zal er geen menu met het huidige scherm (window) worden verbonden. Om een menu aan een scherm te verbinden, dient u eerst het menu uit de resource te laden en de handle ernaar verkrijgen:
Daarna roept u de SetMenu functie uit de Windows API aan met de scherm-handle van het betreffende scherm:
Door de SetMenu functie te gebruiken, kunt u het menu van het scherm geheel veranderen. Windows verwijdert automatisch het menu van een scherm als dat scherm wordt gesloten (in Windows houdt dit in dat Windows een resource uit het geheugen verwijdert en dat geheugen teruggeeft aan Windows voor algemeen gebruik). Menus die niet zijn verbonden aan een scherm moeten handmatig worden verwijderd via de DestroyMenu functie, want anders blijven ze in het geheugen totdat uw programma is beëindigd. Hoewel dit normaal gesproken geen probleem is, zal Windows conform uw opdracht bij elke scherm aanmaak en weer verwijderen een nieuwe kopie van het menu in het geheugen laden. Als uw programma lang genoeg draait, zullen deze wees-menus uiteindelijk alle Windows geheugen in beslag nemen. Weesjes (zoals deze wees-menus) zijn de nummer 1 oorzaak van geheugen-lekken in Windows programmas.
REAGEREN OP MENU SELECTIESUw menu is gekoppeld aan een scherm, dus nu is het tijd om code aan de scherm-procedure toe te voegen zodat op elke menu item selectie gereageerd wordt. Als een menu item wordt geselecteerd stuurt Windows een %WM-COMMAND boodschap naar uw scherm-procedure. De wParam% parameter bevat het menu item nummer dat aangeeft welk menu item werd geselecteerd. Ons voorbeeld programma in Listing 2 vertoont een redelijk standaard menu in het programma-scherm. Voor de meeste items in het menu zal de scherm-procedure eenvoudigweg een message-box tonen met de boodschap welk menu item werd geselecteerd. Het HELP/ABOUT menu item vertelt u dat het programma afkomstig is van BASICally Speaking, en het File/Exit menu item vertelt u welk item werd geselecteerd en beëindigt het programma.) In uw eigen programma kunt u in plaats van deze message-boxen aanroepen naar andere functies en procedures doen (zowel in uw programma als in DLLs), die het uiteindelijke werk van uw programma doen.
VINKJES (CHECK MARKS) EN GEBLOKKEERDE MENU ITEMSEerder gaf ik aan dat u een vinkje links vóór de tekst van een menu item kunt plaatsen met de CHECKED optie in het resource script. Om een vinkje om te schakelen, dient u de CheckMenultem functie uit de Windows API te gebruiken. Eerst moet u een handle naar het menu van het uitverkoren scherm krijgen:
Deze functie kunt u alleen gebruiken als het menu al is geladen en met het scherm is verbonden. Daarna roept u de CheckMenultem functie aan, gebruik makend van de wParam% waarde en %MF_UNCHECKED (om het vinkje te verwijderen) of %MF_CHECKED (om het vinkje te plaatsen):
Naast het initieel niet-actief maken van een menu item in het resource script, kunt u ook de actief-status tijdens de uitvoering van uw programma veranderen met behulp van de EnableMenultem functie. Deze functie heeft een handle naar het menu nodig en het item nummer. Om de status van een menu item te veranderen gebruikt u %MF_ENABLED om een menu item actief te maken en %MF_GRAYED om een menu item niet-actief en grijs te maken:
GEADVANCEEERDE MENU OPTIESWindows biedt u de mogelijkheid om menus nog anders te gebruiken. U kunt bijvoorbeeld een pop-up menu gebruiken zonder een menu-balk (dit wordt vaak gebruikt als de gebruiker met de rechter muistoets klikt op een icoontje of een plaatje), items in een menu toevoegen, verwijderen van items uit menus, de tekst in menus veranderen, plaatjes gebruiken in uw menus, het lettertype van de tekst van menu items veranderen, het systeem menu veranderen (het systeem menu wordt vertoond als u op de menu control-knop links boven in uw menu klikt het bevat meestal MINIMIZE, MOVE, CLOSE etc) en items toevoegen en/of verwijderen, en zelfs een tabel met accelerators (HOTKEYS die automatisch items selecteren uit uw menu zonder dat een gebruiker door de menu structuur hoeft te navigeren om de items te selecteren). De meeste windows programmeer referentie boeken verklaren hoe deze taken uitgevoerd moeten worden, of u kunt, met geduld en een proberen het Windows API help bestand gebruiken om uit te puzzelen hoe dit soort zaken te doen.
CONCLUSIEMenus zijn een centrale mogelijkheid van de meeste Windows programmas. Met behulp van resource scripts kunt u deze menus eenvoudig aan uw programma toevoegen en met een paar aanroepen naar de Windows API op eenvoudige wijze uw programma er goed uit laten zien.
TOEVOEGING OVER HANDLESMen kan geen boek over Windows openslaan of er wordt gesproken over handles. Wat is nu
een handle? Een handle is eigenlijk letterlijk een handvat. En waarvoor gebruikt men een
handvat normaal gesproken? Om dingen vast te pakken en te manipuleren, zoals een hete pan
van het fornuis te halen. Bij de aanmaak van bijvoorbeeld een scherm (window) geeft Windows dit scherm een uniek nummer. Dit nummer krijgen we normaal gesproken niet te weten, tenzij we Windows vragen met welk uniek nummer het scherm wordt aangeduid. Dit unieke nummer kunnen we daarna gebruiken om aan de hand van dat nummer iets te doen met het scherm, bijvoorbeeld om aan te geven dat een bepaald menu moet worden toegevoegd aan ons scherm. Aangezien we niet per se meteen na het aanmaken van een scherm een menu hoeven toe te voegen, zou het kunnen zijn dat we eerst 4 schermen aanmaken en daarna pas het menu aan scherm 1 gaan toekennen (ziet u trouwens hoe ik het nummer 1 koppel aan een bepaald scherm, dit nummer is in dit geval te beschouwen als een handle). Om Windows eenduidig te vertellen welk scherm het nieuwe menu moet krijgen, vragen we de handle op van het scherm en geven dit als parameter op bij de menu-koppeling. |
|