Professionele ToolBar

Inleiding

In Delphi (in ieder geval vanaf versie 5) zijn een aantal componenten waarmee u heel gemakkelijk een applicatie kunt voorzien van professionele werkbalken, die u kunt dokken, ontdokken en verslepen.

Bovendien zijn er componenten die ervoor zorgen dat u zo min mogelijk code hoeft te schrijven voor de verschillende andere componenten die u gebruikt en waarachter min of meer dezelfde code zit.

De knoppen op een werkbalk zijn doorgaans “verbonden” met menu-items.

In deze aflevering gaan we een project maken, met een menu en twee werkbalken met knoppen.

We gaan ervoor zorgen dat de menu-items en de knoppen worden voorzien van iconen, sneltoetsen en events op een zo efficiënt mogelijke manier.

Tevens gaan we ervoor zorgen dat we de werkbalken kunnen verslepen, dokken, ontdokken, weghalen en laten verschijnen.

U zult er verbaasd over zijn met hoe weinig inspanning en code dit voor elkaar te krijgen is.

Bekijk het project hier voordat u het zelf gaat bouwen. Experimenteer met het verslepen van de werkbalken, de menu-itmes etc..

OPMERKING: Bewaar regelmatig uw project!

De start

– start Delphi met een nieuw project
– bewaar het project in een “eigen” map
– download de icoontjes en pak deze uit in de “eigen” map
– plaats op het form de volgende componenten:
– MainMenu (tab Standard)
– PopupMenu (tab Standard)
– ActionList (tab Standard)
– ImageList (tab Win32)
– StatusBar (tab Win32)
– ApplicationEvents (tab Additional)
– ControlBar (tab Additional)
– plaats op de ControlBar1 de volgende twee componenten:
– ToolBar (tab Win32)
– ToolBar (tab Win32)

Zo, hier moeten we het mee doen.

Properties

Nu gaan we van de Controls een aantal properties (eigenschappen) instellen:

Form1:
– Caption = ToolBarTest

ControlBar1:
– Align = alTop
– PopupMenu = PopupMenu1

ToolBar1/2:
– EdgeBorders = [] (klik op de + en zet alles op False)
– Flat = True
– Images = ImageList1 – Width = 100

ActionList1:
– Images = ImageList1

MainMenu1:
– Images = ImageList1

Vullen van de ImageList1

We gaan de icoontjes toevoegen aan de ImageList1:

– dubbelklik op het icoontje van de ImageList1 op het Form1
– klik op de knop “Add…”
– zoek de “eigen” map waar de uitgepakte icoontjes staan
– selecteer alle icoontjes
– klik op de knop “Openen”
– klik op de knop “OK”

Dat viel gelukkig reuze mee.

Toevoegen van knoppen op de ToolBars

Nu gaan we knoppen toevoegen aan de toolbars:

– klik met de rechter-muis-knop op ToolBar1
– kies het menu-item “New Button”
– klik met de rechter-muis-knop op ToolBar1
– kies het menu-item “New Button”
– klik met de rechter-muis-knop op ToolBar1
– kies het menu-item “New Separator”
– verander in de Object Inspector de property Style in tbsDivider
– klik met de rechter-muis-knop op ToolBar1
– kies het menu-item “New Button”

Bijna hetzelfde voor ToolBar2:

– klik met de rechter-muis-knop op ToolBar1
– kies het menu-item “New Button”
– klik met de rechter-muis-knop op ToolBar1
– kies het menu-item “New Button”
– klik met de rechter-muis-knop op ToolBar1
– kies het menu-item “New Button”

Dat de knopjes nog geen icoontjes hebben lossen we later op.

Vullen van het MainMenu1 en het PopupMenu1

Aanemende dat u al vaker met een MainMenu en een PopupMenu heeft gewerkt gaan we hier niet al te diep op de zaken in.
We beperken ons slechts tot een overzicht van de menu-structuur.

Vul het MainMenu1 als volgt (property Caption):

– dubbel-klik op het icoontje MainMenu1 op het Form1
– zorg voor het volgende menu:
&Bestand
&Openen
&Bewaren

&Afsluiten
Be&werken
&Copieren
&Knippen
&Plakken
Werk&balken
&Standaard
&Bewerken
&Help
&Copyright

Voeg aan het PopupMenu1 de volgende twee items toe:

– Standaard
– Bewerken

Wederom: de rest van de instellingen komen straks.

Tijd voor Action(List)!

Het wordt tijd voor wat actie, vindt u ook niet?

We gaan de meeste zaken aan elkander knopen via de ActionList1.

Zo gaan we elke event-handler via de ActionList1 maken en voegen tevens per event-handler bepaalde properties toe, die dan automatisch door andere componenten (via de property Action) worden overgenomen.

De component ActionList is dus een erg handig component.

– dubbelklik op het icoontje van de component ActionList1 op het Form1
– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Openen
– Hint = Bestand openen
– ImageIndex = (kies het juiste icoontje uit de lijst)
– Name = Openen
– ShotCut = Ctrl+O

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Bewaren
– Hint = Bestand bewaren
– ImageIndex = (kies het juiste icoontje uit de lijst)
– Name = Bewaren
– ShotCut = Ctrl+S

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Afsluiten
– Hint = Programma afsluiten|Hiermee sluit u het programma af
– ImageIndex = (kies het juiste icoontje uit de lijst)
– Name = Afsluiten

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Copieren
– Hint = Kopieren
– ImageIndex = (kies het juiste icoontje uit de lijst)
– Name = Copieren
– ShotCut = Ctrl+C

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Knippen
– Hint = Knippen
– ImageIndex = (kies het juiste icoontje uit de lijst)
– Name = Knippen
– ShotCut = Ctrl+X

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Plakken
– Hint = Plakken
– ImageIndex = (kies het juiste icoontje uit de lijst)
– Name = Plakken
– ShotCut = Ctrl+V

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Copyright
– Hint = Copyright
– ImageIndex = (kies het juiste icoontje uit de lijst)
– Name = Copyright

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Standaard
– Checked = True
– Name = Standaard

– klik op de knop “New Action (Ins)”
– Verander in de Object Inspector de volgende properties:
– Caption = Bewerken
– Checked = True
– Name = Bewerken

Nu gaan we een aantal event-handlers toevoegen:

– klik in de ActionList op de Action Openen
– klik in de Object Inspector op de tab Events
– dubbelklik in het vak achter OnExecute
– verander de naam OpenenExecute van de procedure in MessageExecute
– verander die naam ook in de Form-definitie in het interface-gedeelte!!!
– voeg aan de event-handler de volgende regel code toe (dus tussen begin en end;):
ShowMessage((Sender as TAction).Caption+’…’);
– keer terug naar het Form1 en naar de ActionList van ActionList1
– kies voor de waarde MessageExecute voor het event OnExecute bij de volgende Actions:   – Bewaren
– Copieren
– Knippen
– Plakken
– Copyright
– klik op de Action Afsluiten in de Actio List
– dubbelklik in het vak achter het event OnExecute in de Object Inspector
– voeg aan de event-handler de volgende regel code toe:
Close;
– sluit de ActionList
– dubbelklik op het component MainMenu1 op het Form1
– klik op de optie Openen
– klik in de Object Inspector op de tab Properties
– kies voor de property Action de waarde Openen
– doe dit vervolgens ook voor de andere menu-opties (uiteraard de bijbehorende actie kiezen, niet overal Openen)
– sluit het MainMenu1-overzicht
– klik op de eerste knop van ToolBar1
– kies voor de property Action in de Object Ispector de waarde Openen
– Voor de volgende knoppen achtereenvolgens: Bewaren, Afsluiten, ToolBar2: Copieren, Knippen, Plakken

– Bewaar het project
– Run het project en klik op de knoppen en kies de verschillende menu-items

Met zeer weinig code en wat instellingen zijn we nu al een aardig eind op weg.

Merk op dat we de werkbalken binnen hun “vakje” kunnen verplaatsen.

Dat sommige menu-items grijs zijn (disabled), komt doordat er in de ActionList nog geen Event-handler aan de Action zit.

Maar nog niet alles wat we willen is gerealiseerd.

Sleur & pleur

Nu gaan we kijken hoe we de werkbalken uit hun “vakje” kunnen trekken en hoe we de werkbalken weer terug kunnen plaatsen in hun “vakje”.

– als het project nog runt, sluit het running-project dan af
– verander voor ToolBar1 en Toolbar2 de volgende twee properties:
– DragKind = dkDock
– DragMode = dmAutomatic
– bewaar het project
– run het project en probeer de werkbalken uit kun vakje te halen
– probeer ze ook weer in hun vakje te plaatsen

Dit was erg gemakkelijk, niet waar?

Werkbalken aan/uit zetten

De werkbalken kunnen we op twee manieren aan/uit zetten: via het menu Werkbalken of via het PopupMenu.

Beide worden weer aangestuurd via de ActionList1.

– als het project nog runt, sluit het
– dubbelklik op de ActionList
– klik op de Action Standaard
– klik op de tab Events in de Object Inspector
– dubbelklik in het vak achter OnExecute
– voeg de volgende regel code toe aan de event-handler:
ToolBar1.Visible := not (Sender as TAction).checked;
– doe hetzelfde voor het event OnExecute voor de Action Bewerken
de regel is nu natuurlijk: ToolBar2.Visible := not (Sender as TAction).checked

We moeten ook het Update-event van de Actions voorzien van een handler voor het correct bijwerken van de menu-items.

– voeg voor de events OnUpdate van respectievelijk de Action Standaard en Bewerken de volgende regels code toe:
(Sender as TAction).Checked := Toolbar1.Visible; [voor de Action Standaard]

(Sender as TAction).Checked := ToolBar2.Visivle; [voor de Action Bewerken]
– sluit de ActionList
– dubbelklik op de PopupMenu
– klik op de optie Standaard
– klik in de Object Inspector op de tab Properties
– geef de property Action de waarde Standaard
– klik op de optie Bewerken
– geef de property Action de waarde Bewerken
– sluit de itemlist van het PopupMenu
– bewaar het project
– run het project
– kijk of de werkbalken aan/uit gezet kunnen worden via het menu of via het snelmenu van het werkbalken-vak

We beginnen al aardig te vorderen.

Hints

Bij de Actions van ActionList hebben we de property Hint toegevoegd. We zien deze hints echter nog niet.

We gaan de hints op twee manieren laten zien (tegelijkertijd): als label bij de knoppen en in de statusbalk.

Om te beginnen gaan we twee panels aan de statusbalk toevoegen:

– als het project nog runt, sluit deze dan
– dubbelklik op de statusbalk
– klik twee keer op de knop “Add New (Ins)”
– klik op 0 – TStatusPanel
– geef de property Width de waarde 250
– sluit de Panel-list
– klik op de ControlBar1
– geef de property ShowHint de waarde True
– klik op de ToolBar1
– geef de property ShowHint de waarde True
– klik op de ToolBar2
– geef de property ShowHint de waarde True

In Delphi is een Hint een onderdeel (property) van het object Application. Om de hints in de statusbalk te kunnen tonen gaan we via het component ApplicationEvents1 een event-handler toevoegen die de hints weergeven.

Voor de knoppen geldt dat wanneer de property ShowHint van de ToolBar True is er automatisch een label verschijnt.

Voor de menu-items van het MainMenu is het (bijna) praktisch onmogelijk om hints in labels te laten verschijnen.

– klik op het component ApplicationEvents1 op het Form1
– klik in de Object Inspector op de tab Events
– dubbelklik in het vak achter het event OnHint
– voeg de volgende code toe aan de event-handler:
var
  h: String;
begin
  h := Application.Hint;
  if GetLongHint(h) <> ” then
    StatusBar1.Panels[0].Text := GetLongHint(h)
  else
    StatusBar1.Panels[0].Text := h;
end;

Wanneer een Hint gescheiden wordt door een verticale balk (|) dan ziet Delphi dat als een Hint voor het Label en een Hint voor een ander doeleind. Het deel voor de verticale balk is dan de hint voor het Label. De functie GetLongHint test hierop.

– bewaar het project
– run het project en kijk of de hints verschijnen (zowel in de labels als in de statusbalk)

De Action Afsluiten heeft een LongHint; aan de knop Afsluiten verschijnt het label “Programma afsluiten” terwijl in de statusbalk de tekst “Hiermee sluit u het programma af” verschijnt.

En hiermee zijn we feitelijk aan het eind van deze aflevering gekomen. U ziet dat het reuze meevalt om een professionele user-interface te maken. Al wat u nodig heeft zijn de juiste componenten. Het zetten van de juiste properties en enkele regels code doen de rest.

Het volgende stukje is dan ook alleen bedoeld om het één en ander nog fraaier te maken, maar voegt niet echt nieuwe functionaliteit toe.

Dokplaats aanpassen

Wanneer u de werkbalken naast elkaar zet, of ze uit de dokplaats haalt of ze uitzet, dan blijft de dokplaats zichtbaar en even groot als bij de start.

Het zou mooier zijn als de dokplaats zich automatisch aanpast aan de situatie.

Om één en ander voor elkaar te krijgen hebben we wat regels code nodig alsmede een aantal event-handlers.

Als eerste gaan we een algemene procedure aan TForm1 toevoegen.

– activeer het code-venster
– voeg aan de definitie van TForm1 de volgende regel toe:
procedure CheckControlBar;
– voeg in het implementation gedeelte de volgende regels toe:
procedure TForm1.CheckControlBar;
begin
  if ControlBar1.VisibleDockClientCount > 0 then
    ControlBar1.BevelEdges := [beLeft,beTop,beRight,beBottom]
  else
    ControlBar1.BevelEdges := [];
end;
– klik op het Form1 op het component ControlBar1
– klik in de Object Inspector op de tab Events
– dubbelklik in het vak achter OnDockDrop
– voeg de volgende regel code toe:
if (Source.Control is TToolBar) then
  ControlBar1.BevelEdges := [beLeft, beTop, beRight, BeBottom];
– dubbelklik in de Object Inspector in het vak achter OnDockOver:
if (Source.Control is TToolBar) then
  ControlBar1.BevelEdges := [beLeft, beTop, beRight, BeBottom];

– klik op het Form1 op de component ToolBar1
– klik in de Object Inspector in het vak achter OnEndDock
– voeg de volgende regel toe:
CheckControlBar;
– doe de vorige drie stappen voor ToolBar2
– klik op het Form1 op het component ControlBar1
– klik in de Object Inspector op de tab Properties
– zet de waarde van de property AutoSize op True
– zet de waarde van de property Hint op “|In dit gebied kunt u de werkbalken dokken” (zonder “)
– bewaar het project
– run het project en experimenteer met het dokken en ontdokken van de werkbalken

U ziet dat het bijna allemaal goed gaat. Alleen direct na het opstarten gaat het een beetje mis. Als er na het opstarten één van de werkbalken uit het vak wordt gehaald verdwijnen de grenslijnen.

Dit is op te lossen door het Form1Create-event van de volgende regels te voorzien:

ToolBar1.ManualDock(ControlBar1);
ToolBar2.ManualDock(ControlBar1);

– als het project nog runt, stop dan
– klik op het Form1
– klik in de Object Inspector op de tab Events
– dubbelklik in het vak achter OnCreate
– voeg bovenstaande twee programmaregels toe aan de event-handler
– bewaar het project
– run het project
– experimenteer weer

Als het goed is werkt nu alles wel naar behoren.

Wat hebben we nu zoal gedaan?

Het event OnDochDrop van de ControlBar1 treedt op wanneer er “iets” op het component wordt gedropt. Wanneer dit het geval is dan komen de grenslijnen tevoorschijn. Ditzelfde gebeurt wanneer het event OnDockOver actief wordt. Dit event wordt actief wanneer er “iets” dat op de control gedropt kan worden over het control gesleept wordt.

De event OnEndDock van het component ToolBar1 en ToolBar 2 treedt op wanneer het component na slepen wordt losgelaten.
Op dat moment moet er worden gekeken of het component binnen of buiten het component ControlBar1 staat, en dient overeenkomstig wel of geen grenslijnen getekend te worden.

De property VisibleDockClientCount van de control ControlBar1 geeft aan hoeveel zichtbare dokbare cliënten er zich binnen de grenzen van de ControlBar1 zich bevinden.

De opdrachten in het FormCreate-event zorgen ervoor dat de ToolBars in de ControlBar1 worden gedokt. Het is mij niet geheel duidelijk waarom dit het probleem oplost dat na het opstarten bij de eerste verwijdering van een werkbalk de grenslijnen verdwijnen.

En hiermee zijn we echt aan het einde van deze aflevering gekomen.