Delphi tools: Align component editor
Erik Stok (aka Baldo)
Delphis open tools api (OTA) biedt geweldige mogelijkheden
om de IDE uit te breiden met handigheden van jezelf. Er is veel
over de OTA te vinden op het web, maar veel artikelen vertellen
vooral wat er kan en verzuimen een praktisch toepasbaar voorbeeld
te geven van het gebruik van de OTA. NLDelphi is een plaats die
draait om Delphi in de praktijk, dus een betere plaats om de praktische
kan van de OTA te beschrijven kan ik me niet indenken. Dit tweede
artikel beschrijft het bouwen van een component editor.
Het idee
RSI is een niet te onderschatten risico in het vak van de programmeur.
Voor mezelf was het gebruik van de muis tijdens het ontwerpen van
schermen vaak een net iets te zware belasting. Toen ik zag dat ik
vaak dezelfde handelingen aan het verrichten was, ging het instinct
van de programmeur alweer kriebelen om dit te automatiseren. De
align component editor was geboren.
De schermen die ik bouw bestaan veelal uit een aantal wincontrols
met daarvoor een label met wat er in deze wincontrols kan worden
ingevuld. Tussen de wincontrols wordt een afstand gehouden van 4
pixels, de labels ervoor worden links uitgelijnd en de wincontrols
worden links uitgelijnd op afstand van 4 pixels van het breedste
label. Onderstaande afbeelding is hiervan een voorbeeld.

Vaak liggen deze wincontrols in een container zoals een panel,
groupbox of tabsheet. De tabvolgorde van de wincontrols loopt van
boven naar beneden.
Wat ik wilde doen was ervoor zorgen dat ik voor een aantal containers
een functie kon starten die de wincontrols zou uitlijnen volgens
de genoemde regels.
Het meest gemakkelijk leek mij een rechtsklik op de container waar
de controls in liggen. Een component editor lag voor de hand dus.
In dit artikel zal ik de bouw van deze component editor behandelen.
Component editors
In de DesignEditors unit (terug te vinden in de Delphi map onder
Source\ToolsAPI) zit een class genaamd TComponentEditor. Door een
afgeleide van deze class te maken en bepaalde methods te overriden
is het eenvoudig een eigen component editor te maken. Als in de
Delphi help gezocht wordt op TComponentEditor dan staat vrij expliciet
uitgelegd wat de TComponentEditor allemaal kan. Ik ga hier dan ook
niet verder in op de details van TComponentEditor, behalve die details
die noodzakelijk zijn om de align component editor te bouwen.
Het zal geen verrassing zijn dat de class definition voor de align
component editor er als volgt uitziet:
TAlignEditor = class(TComponentEditor) function GetVerbCount: Integer; override; function GetVerb(Index: Integer): string; override; procedure ExecuteVerb(Index: Integer); override; end;
Via de GetVerbCount method kunnen we aangeven hoeveel acties
er kunnen worden uitgevoerd met de component editor. In dit geval
is er één actie voor de component editor geïmplementeerd:
align.
Om het pop-up menu te kunnen vullen zal voor het aantal acties
opgegeven in GetVerbCount de GetVerb van de component
editor aangeroepen worden om de captions van de menu items op te
halen. In dit geval is er maar één menu-item dus kan
worden volstaan met het resultaat Align.
De executeverb method zal worden aangeroepen voor de in
het pop-up menu geselecteerde menu-item. In dit geval is er maar
één mogelijke actie, dus kan altijd de align worden
uitgevoerd.
Voorwaarden voor uitlijnen
Het is eenvoudig om de wincontrols uit te lijnen op basis van de
tabvolgorde. Het maken van een lijst van wincontrols, het sorteren
van deze lijst op tabvolgorde en de contols in de lijst en het links
uitlijnen is voldoende om dat gedaan te krijgen. De moeilijkheid
zit hem in de labels voor de controls. Hoe komt de component editor
te weten welk label bij welk control hoort zodat deze mee uitgelijnd
kan worden?
De oplossing ligt in de focuscontrol property van het label.
Indien een label wordt aangemaakt om voor (of boven) een control
te plaatsen dan is het vestandig om in de focuscontrol property
van het label in te vullen voor welk control het label van toepassing
is. Indien in de caption van het label namelijk een shortcut
verwerkt wordt, dan zorgt de focuscontrol property ervoor
dat bij het intoetsen van de shortcut de focus naar het overeenkomstige
control gezet wordt. Veel programmeurs gebruiken deze property niet
en plaatsen maar wat labels voor controls, maar het is aan te raden
gebruik te maken van deze functionaliteit. Sterker nog: om het uitlijnen
te laten werken is het zelfs noodzakelijk om hiervan gebruik te
maken.
Uitlijnen
Door voor ieder item in de lijst van uit te lijnen wincontrols
van de container te kijken welk label er via de focuscontrol
property gekoppeld is, is het mogelijk om parallel aan de lijst
van wincontrols een lijst van labels samen te stellen. Zodra beide
lijsten bekend zijn is het eenvoudig om de positie van de labels
te bepalen en de controls achter de labels te plaatsen.
Het package waarin de
broncode staat voor de simpele versie van de component editor kan
worden geïnstalleerd net als ieder ander designtime package.
Het is mogelijk om de component editor te registreren voor ieder
container die afgeleidt is van TWinControl.
Selectief uitlijnen
Er zijn natuurlijk gevallen waarin er wincontrols in de container
staan waar geen uitlijning op gewenst is. Als deze controls al juist
uitgelijnd staan (bijvoorbeeld een set buttons onderaan het scherm)
dan moet het mogelijk zijn om deze buiten beschouwing te laten bij
het uitlijnen. Om dit te kunnen bewerkstelligen kan er een selectiescherm
voor het daadwerkelijke uitlijnen worden getoond waarin de gebruiker
kan aangeven welke wincontrols dienen te worden uitgelijnd.
Het package waarin
de broncode staat voor deze versie van de component editor kan worden
geïnstalleerd net als ieder ander designtime package.
Conclusie
Het is duidelijk dat de Delphi open tools api op eenvoudige wijze
toestaat handige IDE extensies te maken die het leven vereenvoudigen.
En het mooiste is: alles kan worden geprogrammeerd in de bekende
Delphi syntax. De align component editor is een voorbeeld hiervan
dat menige ontwikkelaar zal aanspreken vanwege zijn eenvoud en toepasbaarheid.
|