Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi ActionList mit Actions unterschiedlicher Klassen kopieren (https://www.delphipraxis.net/162080-actionlist-mit-actions-unterschiedlicher-klassen-kopieren.html)

shadowman 5. Aug 2011 09:25

ActionList mit Actions unterschiedlicher Klassen kopieren
 
Hallo,

ich würde gerne eine ActionList kopieren / duplizieren / klonen / wie auch immer.

Es gibt viel dazu im Internet, verschiedene Ansätze etc., allerdings beziehen sie sich alle auf Actions vom Typ TAction. Das ist aber in meinem Fall nicht so, deswegen kann ich mit diesen Beispielen nicht viel anfangen, fürchte ich.

Es geht um eine ActionList mit RichViewActions, d.h. über 100 Actions, die alle von unterschiedlichen Typen sind: TrvActionNew, TrvActionOpen etc.

Die sind zwar alle von TRVAction abgeleitet, aber ich komme trotzdem nicht weiter...

Meine Versuche bisher:
Code:
procedure ActionListDuplizieren(ZielActionList, SourceActionList: TActionList);
var
   i: integer;
   NeueAktion: TObject;
begin
   if assigned(ZielActinList) and assigned(SourceActionList) then begin
      for i := 0 to SourceActionList.ActionCount - 1 do begin
         NeueAktion := SourceActionList.Actions[i].ClassType.Create;
         
         // NeueAktion ist an dieser Stelle jeweils vom richtigen Typ: TrvActionNew, TrvActionOpen etc.
         
         if NeueAktion is TRVAction then begin
            TRVAction(NeueAktion).Caption := TRVAction(SourceActionList.Actions[i]).Caption;
            TRVAction(NeueAktion).Hint := TRVAction(SourceActionList.Actions[i]).Hint;
            TRVAction(NeueAktion).ShortCut := TRVAction(SourceActionList.Actions[i]).ShortCut;
            TRVAction(NeueAktion).ImageIndex := TRVAction(SourceActionList.Actions[i]).ImageIndex;
            TRVAction(NeueAktion).ActionList := ZielActinList;
         end;
      end;
   end;
end;
Bereits beim Ersten Zugriff auf "NeueAktion", also beim Setzen von "Caption" kommt es zu einer Zugriffsverletzung und der grund dafür ist nicht so richtig ersichtlich.

Ich habe es ausprobiert, die ActionList-Eigenschaft zuerst zu setzen, also
Code:
TRVAction(NeueAktion).ActionList := ZielActinList;
TRVAction(NeueAktion).Caption := TRVAction(SourceActionList.Actions[i]).Caption;
und das geht komischwerweise, aber bei Caption kommt wieder die Zugriffsverletzung...


Dann habe ich es auf die Art und Weise versucht, wie es hier vorgeschlagen wurde, aber auch das klappt nicht.

Mein Code:
Code:
type
   TRichViewActionKlasse = class of TRVAction;

procedure ActionListDuplizieren(ZielActinList, SourceActionList: TActionList);
var
   i: integer;
   NeueAktion: TRVAction;
   RichViewActionKlasse: TRichViewActionKlasse;
begin
   if assigned(ZielActinList) and assigned(SourceActionList) then begin
      for i := 0 to SourceActionList.ActionCount - 1 do begin
         RichViewActionKlasse := TRichViewActionKlasse(FindClass(SourceActionList.Actions[i].ClassName));
         NeueAktion := RichViewActionKlasse.Create(nil);
         if NeueAktion is TRVAction then begin
            TRVAction(NeueAktion).Caption := TRVAction(SourceActionList.Actions[i]).Caption;
            TRVAction(NeueAktion).Hint := TRVAction(SourceActionList.Actions[i]).Hint;
            TRVAction(NeueAktion).ShortCut := TRVAction(SourceActionList.Actions[i]).ShortCut;
            TRVAction(NeueAktion).ImageIndex := TRVAction(SourceActionList.Actions[i]).ImageIndex;
            TRVAction(NeueAktion).ActionList := ZielActinList;
         end;
      end;
   end;
 end;
Hier scheitert es am Aufruf von "FindClass" mit der Meldung:
Zitat:

[...]eine Exception der Klasse EClassNotFound mit der Meldung 'Klasse TrvActionNew nicht gefunden' aufgetreten

Ist einer der Ansätze halbwegs richtig und es fehlt "nur" etwas oder ist es komplett falsch oder gar nicht erst möglich?

Über ein paar Hinweise würde ich mich sehr freuen, vielen Dank.

Sliver18 5. Aug 2011 13:55

AW: ActionList mit Actions unterschiedlicher Klassen kopieren
 
Zitat:

Zitat von shadowman (Beitrag 1115191)
Bereits beim Ersten Zugriff auf "NeueAktion", also beim Setzen von "Caption" kommt es zu einer Zugriffsverletzung und der grund dafür ist nicht so richtig ersichtlich.

Ich denke mal, das Setzen von Caption wird irgendeinen Event innerhalb der Actionlist abfeuern - die zu dem Zeitpunkt ja noch nicht gesetzt ist. (Wenn Du die Property "Caption" vor "Actionlist" setzt)

Zitat:

Zitat von shadowman (Beitrag 1115191)
NeueAktion := SourceActionList.Actions[i].ClassType.Create;

Ich habe hier das Gefühl, dass hier nur der Konstruktor von TObject aufgerufen wird und nicht der Deiner ActionKlasse - das könnte eine der Ursachen sein, teste das doch mal.

Ich habe mal ein bischen getestet und folgender Code läuft bei mir (ich musste allerdings die TRVActionklassen durch TAction ersetzen, da die TRV's bei mir nicht vorhanden sind):

Code:
procedure ActionListDuplizieren(ZielActionList:TActionList; SourceActionList: TActionList);
var
   i: integer;
   Ta:TContainedActionClass;
   NeueAktion, AlteAktion: TAction; // typ geändert (damit nicht ständig gecastet werden muss
begin
   if assigned(ZielActionList) and assigned(SourceActionList) then begin
      if SourceActionList.ActionCount > 0 then begin
        for i := 0 to SourceActionList.ActionCount - 1 do begin
          AlteAktion := TAction(SourceActionList.Actions[i]); // alte Aktion holen, damit wir nicht immer über den index gehen müssen
          NeueAktion := TAction( AlteAktion.ClassType.Create );

          if NeueAktion is TAction then begin
            NeueAktion.ActionList := ZielActionList;
            NeueAktion.Caption := 'hi';
            NeueAktion.Hint := AlteAktion.Hint;
            NeueAktion.ShortCut := AlteAktion.ShortCut;
            NeueAktion.ImageIndex := 0;
          end;
        end;
      end;
   end;
end;

shadowman 5. Aug 2011 14:56

AW: ActionList mit Actions unterschiedlicher Klassen kopieren
 
Hallo und vielen Dank!

Das funktioniert natürlich, aber das ist ja auch gleichzeitig mein Problem: auf diese Weise sind alle neuen Actions vom Typ "TAction" und nicht von demselben Typen wie die Quell-Action.

"NeueAktion" ist ja bereits jeweils vom richtigen Typ: TrvActionNew, TrvActionOpen etc. nach Aufruf von
Code:
NeueAktion := SourceActionList.Actions[i].ClassType.Create;
Du machst anschließend noch einmal
Code:
NeueAktion := TAction.create(nil);
wenn es nötig ist (wo ich mir allerdings nicht sicher bin), dann würde mir die entsprechende Klasse fehlen "TrvKlasseXYZ.Create(nil)", die ich statt TAction.Create(nil) nutzen müsste.

Sliver18 5. Aug 2011 15:57

AW: ActionList mit Actions unterschiedlicher Klassen kopieren
 
Zitat:

Zitat von shadowman (Beitrag 1115270)
Hallo und vielen Dank!
Das funktioniert natürlich, aber das ist ja auch gleichzeitig mein Problem: auf diese Weise sind alle neuen Actions vom Typ "TAction" und nicht von demselben Typen wie die Quell-Action.

Das kann ich nachvollziehen.

Zitat:

Zitat von shadowman (Beitrag 1115270)
Du machst anschließend noch einmal
Code:
NeueAktion := TAction.create(nil);
wenn es nötig ist (wo ich mir allerdings nicht sicher bin), dann würde mir die entsprechende Klasse fehlen "TrvKlasseXYZ.Create(nil)", die ich statt TAction.Create(nil) nutzen müsste.

Oh nein, natürlich ist es nicht nötig - das ist beim Testen wohl stehengeblieben - gemeint war nur die Zeile
Code:
NeueAktion := TAction( AlteAktion.ClassType.Create );
Aber da war ich mir ja wie gesagt nicht sicher, ober Delphi dann den korrekten Konstruktor aufruft. Denn TAction-Klassen erwarten ja im Konstruktor die Angabe eines Owners (und an der stehengebliebenen Zeile siehst Du ja, dass der auch nil sein darf).


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:45 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz