Delphi - TActionList komponens

TActionList 1. rész

forráskód letöltése
A Delphi 4-től már létező, a programfejlesztést nagy mértékben segítő új lehetőséggel ismerkedünk meg kétrészes új cikksorozatunkban, melynek fő témája a TActionList és annak felhasználási lehetőségei. Egy alkalmazásban a felhasználónak felkínált parancsokat célszerű összegyűjteni egy csoportba, azután az egyes vezérlőkhöz, mint például menüelemek, gombok ebből a csoportból csak ki kell választani a társított parancsot. Ilyen csoport létrehozására a Delphi a 4-es verziótól rendelkezik egy akciólistát egyesítő TActionList komponenssel, elemeit akcióknak nevezzük melyek a TAction osztály példányai. Az akciók dinamikusan kötődnek a vezérlőkhöz, tehát a vezérlők tulajdonságainak módosítása helyett csak akción kell változtatnunk, és az érvényes lesz a vezérlőkre is. Az akciók bevezetésének igénye abból ered, hogy az alkalmazásokban az egyes parancsokat általában több vezérlőhöz társítjuk: menüelem, gomb vagy helyi menü eleme, és a művelet állapotának megváltozásánál a vezérlők kódjait külön-külön kellett módosítani.

A cikksorozatban bővebben áttekintjük az akciólisták és akciók használatát, megismerkedünk saját akció komponens fejlesztésének alapjaival. Az első részben egy szöveg-editoron keresztül fogjuk bemutatni az alapvető felhasználást. A programban szövegbevitelre a TMemo komponens egy példányát használtuk.
A működés könnyebb követése végett a programot kiegészítettük egy panellel, mely a legutóbb végrehajtott, vagy a panelen kiválasztott akcióról nyújt információt. Az Execute (lejátszás ikon) eszközgombbal bármikor végrehajthatjuk a panel aktuális akcióját.
Akciólistákat használnak a File ŕ New ŕ Projects ŕ MDI Application, SDI Application, Win95/98 LogoApplication alkalmazások. A Delphi5 Demos mappájában a következő példaprogramokban találunk akciólistákat: Ado\AdoTest, AppEvents, Coolstuf, Corba\Datamodule, Docking, Midas\Alchtest, Midas\Brfcase, Richedit, ToolsAPI\INTAServices.


TActionList példány létrehozása, akciók felvétele

Az ActnList unithoz tartozó TActionList nem vizuális komponenst a Standard palettalapon találjuk, ennek egy példányát kell az alkalmazás formjára helyezni. Kettőskattintással az akciólista komponensre előhívjuk szerkesztőjét (Action List Editor). A szerkesztő bal oldali ablakában az akciók csoportjai (Categories), jobboldalt egy csoport elemei vannak felsorolva (Actions). Akció felvételéhez jobb egérkattintással hívjuk elő a szerkesztő helyi menüjét, innen választhatjuk a New Action és a New Standard Action parancsot. Utóbbi az Edit, Window, Help menük, továbbá az adathalmazon (DataSet) végezhető műveletek akcióit tartalmazza, melyek a Windows alkalmazásokban megszokott módon működnek. Tehát a standard akciókhoz nem kell programkódot írni, például még a Vágólapra másolás (EditCopy) parancs aktív voltát sem kell figyelni.

Noha az alkalmazás nem követeli meg, a példaprogramban három akciólistát veszünk fel: FileActionList, EditActionList, ExitActionlist, akciói a File és Edit menük parancsait végzik el. Az EditActionList tartalmazza az összes, az Edit menühöz rendelendő standard akciót: Undo, Cut, Copy, Paste, Delete, Select All, a FileActionList-hez felvettük a New, Open, Save akciókat. Az ExitActionList elemei a kilépés (Exit) és egy akció végrehajtása (Execute). (Akció felvételekor az Objektum-figyelőben megadjuk nevét (Name), címkéjét (Caption), a tipp szövegét (Hint) és a billentyűkombinációt, mely az akciót aktivizálja (ShortCut). A kategória (Category) tulajdonsággal az akciót a listán belül csoportosítjuk. Ha nem létező kategórianevet írunk egy akcióhoz, azzal új csoport jön létre.


Képek hozzárendelése az akciókhoz

Windows alkalmazásokban a parancsokhoz kis képeket társíthatunk. A Delphi Win32 lapján található TImageList komponens egy képsorozatot reprezentál, ezt az akciólistához annak ImageList tulajdonságával csatoljuk. Az alapértelmezett képméret 16´16 pont. A képlistára kettőskattintással vehetünk fel ikonokat. A Delphi a Program Files \ Common Files \ Borland Shared \ Images \ Buttons mappában tárol 32´16 pontból álló képpárokat, azaz egy fájlban egy gomb két képét találjuk, amit a Delphi szét is választ. (Egy képlistán az összes képnek egyforma, a Width, Height tulajdonsággal megadott méretűnek kell lennie). Az első kép a parancs aktív, a második az inaktív állapotához tartozik, utóbbit szükség esetén letörölhetjük. A programokban megszokott ikonok itt nem találhatók meg, ezeket a mellékelt buttons.bmp kép felvételével és szétdaraboltatásával nyertük. A listában minden képhez egy sorszám tartozik, az első elem 0 sorszámú. Ezt adjuk az akciólistában az egyes akciók ImageIndex tulajdonságának értékül (előtte -1 volt), és máris ikont csatoltunk az akcióhoz.


Akciók hozzárendelése vezérlőkhöz

Számos vezérlő, mint például a TToolButton, TSpeedButton, TMenuItem, TButton rendelkezik Action nevű published tulajdonsággal, ezzel tervezéskor a vezérlőhöz csatolhatunk egy akciót. Példánk tartalmaz fő- és helyi menüt (TMainMenu, TPopupMenu), eszköztárat (TToolBar), ezek elemeihez rendeltünk akciókat.
Menüt akciókkal nem a megszokott módon tervezünk, amikor is létrehoztuk a menüelemeket, megadtuk címkéjüket (Label), ikonjukat (Bitmap), tippet (Hint), az aktivizáláskor használatos billentyűkombinációt (ShortCut) és beállítottuk az OnClick eseményt. Most viszont egy menüelemhez (TMenuItem) csak az akciót rendeljük, és máris feltöltődnek a szükséges tulajdonságok az akció megfelelő tulajdonságaival, még az OnClick esemény is tartalmazza az akció OnExecute eljárását. Hasonlóan egy eszközgombon (TToolButton), vagy más gombokon is csak az Action tulajdonságot kell beállítanunk, és máris a megszokott módon használhatjuk őket.


Az akciók végrehajtása

Amikor egy vezérlőre kattintunk a hozzácsatolt akció OnExecute eseménye generálódik, mely meghívja az Execute eljárást. Az Execute végrehajtása előtt, az akció saját magát paraméterül adva az akciólista OnExecute eseményét váltja ki, az ezt lekezelő eljárás kerül végrehajtásra (ha definiálva van):
procedure TActionListDemo1.ActionListExecute
  (Action: TBasicAction; var Handled: Boolean);
begin
  if MessageDlg(Action.GetPArentComponent.Name+
           ': Execute action '+Action.Name+'?',
    mtConfirmation, [mbYes, mbNo], 0)=mrNo
    then Handled:=true
    Else begin
       ActiveList:=Action.GetPArentComponent as TActionList;
       ActionListHandle(Action as TContainedAction);
    end;
end;
A Handled logikai változó jelzi, hogy az akciólista lekezelte-e az akciót, értéke alapértelmezésben False. Ha True-ra állítjuk, akkor az akció végrehajtása itt megszakad. Ha az akciólista nem kezeli le az akciót, akkor az alkalmazás OnExecute eseménye generálódik, ennek az akciólistához hasonlóan, lehetősége van lekezelni az akciót. Ha ennek is False marad a Handled változója, akkor az akció saját magát paraméterül adva CM_ACTIONEXECUTE üzenetet küld az alkalmazás WndProc eljárásának. Ezután az alkalmazás megpróbálja megtalálni a célobjektumot, melyen végre kell hajtani az akciót.
A példaprogramban a FileActionList és EditActionList a fenti eseménykezelő eljárást használják, az ExitActionList akciólistának nincs OnExecute eseménykezelője. Mivel az alkalmazás is lekezelheti az OnExecute eseményét, ezért a form-ra fel kellett venni egy TApplicationEvents példányt (komponenspaletta Additional lap), hogy hozzáférhessünk az alkalmazás eseményihez.
procedure TActionListDemo1.
      ApplicationEventsActionExecute(Action: TBasicAction;
      var Handled: Boolean);
begin
  if MessageDlg('"'+ActionListDemo1.Name+'": 
    Execute action: '+Action.Name+'?',
    mtConfirmation, [mbYes, mbNo], 0)=mrNo
   then Handled:=true;
end;
Ezek az eljárások egy üzenetablakban (MessageDlg) kérdezik meg a felhasználót, hogy végre akarja-e hajtani az akciót. Ha a válasz nem, akkor a Handled változót True-ra állítják, ezzel az akció lekezeltté nyilvánítódik, végrehajtása leáll.
A standard akciókat a StdActns unit tartalmazza, ezekhez nem kell eljárást írnunk, a programokban megszokott módon működnek. Így például az is biztosított, hogy az EditCopy csak akkor aktív, ha kijelöltünk egy szöveget.
Egyéb, általunk létrehozott akciók eseménykezelőinek megírása ránk vár:
procedure TActionListDemo1.FileNewExecute(Sender: TObject);
begin
  If MemoEditor.Lines.Count > 0 then
     MemoEditor.Clear;
end;
procedure TActionListDemo1.FileOpenExecute(Sender: TObject);
begin
  If OpenDialog.Execute then
     MemoEditor.Lines.LoadfromFile(Opendialog.FileName);
end;
procedure TActionListDemo1.FileSaveExecute(Sender: TObject);
begin
  If SaveDialog.Execute then begin
     MemoEditor.Lines.SaveToFile(SaveDialog.FileName);
     MemoEditor.Modified:=False;
  end;
end;
procedure TActionListDemo1. ExitExecute(Sender: TObject);
begin
  Close;
end;
procedure TActionListDemo1.ExecuteExecute(Sender: TObject);
begin
  ActiveList[SpinSelectedIndex.Value].Execute;
end;
Mivel az Execute akció valójában a panelen kijelölt akciót végzi el, és maga az Execute is kijelölhető, így ha önmagát szeretné aktivizálni, akkor egy végtelen eseményfolyamatot indíthatna el. Az alkalmazás OnExecute eseménykezelője azonban megszakítja ezt a sorozatot, amint a felhasználó nemmel válaszol a végrehajtás kérdésére.
A TActionList komponens

Öröklődési hierarchia
TObject - TPersistent - TComopnent - TCustomActionList - TActionList
Tulajdonságok
· property ActionCount: Integer; - az akciók száma az akciólistában.
· property Actions[Index: Integer]: TContainedAction; - az Index-edik akció az akciólistában. A listába gyűjtött akciók a TContainedAction osztály példányai.
· property Images: TCustomImageList; - az akciólistához csatolt képlista.
Metódusok
· function ExecuteAction(Action: TBasicAction): Boolean; override; - az Action paraméter Execute eljárása hívja meg. Az ExecuteAction az akciólista OnExecute eseménykezelőjét indítja.
· function IsShortCut(var Message: TWMKey): Boolean; - eldönti, hogy egy bemenő billentyűkombináció hozzá van-e rendelve a lista egy akciójához. Belsőleg használatos, nem szükséges a programban meghívnunk.
· function UpdateAction(Action: TBasicAction): Boolean; override; - értesíti az akciólistát egy akció frissítéséről. OnUpdate eseményt vált ki, értéke True, ha OnUpdate-hez van eljárás rendelve, különben False.

Események
· property OnChange: TNotifyEvent; - akkor keletkezik, amikor az akciólistában változás áll be.
· property OnExecute: TActionEvent; - egy akció Execute eljárása generálja.
· property OnUpdate: TActionEvent; - akkor keletkezik, amikor az akciólista értesítést kap egy akció frissítéséről.

A TContainedAction komponens
Öröklődési hierarchia
TObject - TPersistent - TComopnent - TBasicAction - TContaiedAction - TCustomAction - TAction
Tulajdonságok
· property ActionList: TCustomActionList; - értéke az akciót tartalmazó lista. Csak TContainedAction vagy abból származó osztályokra alkalmazható.
· property Category: string; - értéke az akciót tartalmazó csoport (kategória) neve.
· property Index: Integer; - az akciólistában az akció sorszáma.
Metódusok
· function Execute: Boolean; override; - megállapítja, hogy egy OnExecute eseménykezelő meghívásra került-e. Ha az akció eseménykezelője definiált, akkor azt meghívja, különben az akciólista eseménykezelőjét hívja meg. Ha egyik sincs, akkor az alkalmazáshoz fordul, annak eseménykezelőjét próbálja végrehajtani. Az eredmény igaz, ha talált hívható eseménykezelőt.
· function GetParentComponent: TComponent; override; - az objektum szülőkomponensét adja eredményül, jelen esetben az akciót tartalmazó akciólistát.
· function HasParent: Boolean; override; - megállapítja, hogy az akció tagja-e egy akciólistának.
· function Update: Boolean; override; - megállapítja, hogy az akció, az akciólista vagy az alkalmazás OnUpdate eseménykezelője végre lett-e hajtva. Ha egyik eseménykezelő sincs definiálva, akkor False értékkel tér vissza, különben értéke True.
Események
· property OnExecute: TNotifyEvent; - az eseményt a kapcsolt vezérlő aktivizálása (általában menüelemek, eszközgombok OnClick eseménye) váltja ki. Ennek eseménykezelőjében kell leírni az akció végrehajtásának műveleteit.
· property OnUpdate: TNotifyEvent; - ha az alkalmazásban nem történik semmi, vagy az akciólista frissítésére kerül sor, akkor OnUpdate esemény keletkezik az akciókban. Ehhez olyan frissítő eljárást kell írni, mely az akció célobjektumának állapotát vizsgálva megváltoztatja az akció állapotát, például tiltja vagy engedélyezi az akciót.

TActionList cikksorozat

TActionList komponens - TActionList 1. rész

TActionList komponens - TActionList 2. rész