Wie füge ich Unterstützung für Aktionen in meiner Komponente hinzu
-
25-10-2019 - |
Frage
Was muss ich tun, um meine Komponente zu unterstützen. Es ist eine Knopfkomponente, aber ich denke, es ist für jeden Komponenten -Typ das gleiche. Alle Informationen oder wie man hilft.
Lösung
Das hängt davon ab, wie Sie definieren Aktionsunterstützung. Es gibt zwei Arten:
- Eine möglicherweise angepasste Aktionseigenschaft Ihrer Komponente, die von einer Aktionskomponente zugeordnet werden kann
- Die Aktionskomponente selbst.
Eine Aktionseigenschaft
Jeder TCONTROL -Nachkommen verfügt über eine Aktionseigenschaft, die ausführlich mit einer linken Maustaste verknüpft ist. Dies Verknüpfung wird von einem ActionLink verwaltet. Der Standard -ActionLink ist vom Typ tcontrolactionLink, der die Synchronisation der Bildunterschrift, des Hinweiss, des aktivierten Zustands usw. sowohl der Aktion als auch der der Kontrolle übernimmt. Wenn diese Grundlage alles ist, was Sie möchten, veröffentlichen Sie einfach die Aktionseigenschaft in Ihrer Komponententyp -Deklaration, und das Delphi -Framework kümmert sich um alle, wie es Serg und Lu rd schon beantwortet.
Wenn Sie möchten, dass Ihre eigene Aktionseigenschaft mit einer anderen Bedingung oder einem anderen Ereignis (dh außer Klick) verknüpft wird oder wenn Sie eine Aktionseigenschaft für ein bestimmtes Subelement Ihrer Komponente implementieren möchten (das ist kein Tontrol -Nachkomme), dann dann Sie können Ihre eigene benutzerdefinierte Aktionseigenschaft implementieren, indem Sie eine benutzerdefinierte ActionLink -Klasse definieren und implementieren.
Angenommen, Ihre Komponente ist eine Art Raster mit Spalten, und Sie möchten, dass jede Spalte eine Aktionseigenschaft hat, die aufgerufen werden sollte, wenn der Benutzer auf den Titel einer Spalte klickt. Da solche Spalten wahrscheinlich einen TCollectionItem -Typ haben, hat der Spaltentyp standardmäßig keine Aktionseigenschaft. Sie müssen also selbst eine implementieren. Betrachten Sie das nächste Beispiel, das die Bildunterschrift der Aktion mit dem Titel der Spalte verknüpft, den aktivierten Status der Aktion umgekehrt mit der Readonly -Eigenschaft der Spalte verknüpft und so weiter ...:
unit Unit1;
interface
uses
Classes, ActnList, SysUtils;
type
TColumn = class;
TColumnActionLink = class(TActionLink)
protected
FClient: TColumn;
procedure AssignClient(AClient: TObject); override;
function IsCaptionLinked: Boolean; override;
function IsEnabledLinked: Boolean; override;
function IsOnExecuteLinked: Boolean; override;
function IsVisibleLinked: Boolean; override;
procedure SetCaption(const Value: String); override;
procedure SetEnabled(Value: Boolean); override;
procedure SetOnExecute(Value: TNotifyEvent); override;
procedure SetVisible(Value: Boolean); override;
end;
TColumnActionLinkClass = class of TColumnActionLink;
TColumn = class(TCollectionItem)
private
FActionLink: TColumnActionLink;
FGrid: TComponent;
FOnTitleClick: TNotifyEvent;
FReadOnly: Boolean;
FTitle: String;
FVisible: Boolean;
function DefaultTitleCaption: String;
procedure DoActionChange(Sender: TObject);
function GetAction: TBasicAction;
function IsOnTitleClickStored: Boolean;
function IsReadOnlyStored: Boolean;
function IsVisibleStored: Boolean;
procedure SetAction(Value: TBasicAction);
protected
procedure ActionChanged(Sender: TObject; CheckDefaults: Boolean); dynamic;
procedure DoTitleClick; virtual;
function GetActionLinkClass: TColumnActionLinkClass; virtual;
property ActionLink: TColumnActionLink read FActionLink write FActionLink;
public
destructor Destroy; override;
procedure InitiateAction; virtual;
published
property Action: TBasicAction read GetAction write SetAction;
property OnTitleClick: TNotifyEvent read FOnTitleClick write FOnTitleClick
stored IsOnTitleClickStored;
property ReadOnly: Boolean read FReadOnly write FReadOnly
stored IsReadOnlyStored;
property Title: String read FTitle write FTitle;
property Visible: Boolean read FVisible write FVisible
stored IsVisibleStored;
end;
implementation
{ TColumnActionLink }
procedure TColumnActionLink.AssignClient(AClient: TObject);
begin
FClient := TColumn(AClient);
end;
function TColumnActionLink.IsCaptionLinked: Boolean;
begin
Result := inherited IsCaptionLinked and (Action is TCustomAction) and
(FClient.Title = TCustomAction(Action).Caption);
end;
function TColumnActionLink.IsEnabledLinked: Boolean;
begin
Result := inherited IsEnabledLinked and (Action is TCustomAction) and
(FClient.ReadOnly <> TCustomAction(Action).Enabled);
end;
function TColumnActionLink.IsOnExecuteLinked: Boolean;
begin
Result := inherited IsOnExecuteLinked and
(@FClient.OnTitleClick = @Action.OnExecute);
end;
function TColumnActionLink.IsVisibleLinked: Boolean;
begin
Result := inherited IsVisibleLinked and (Action is TCustomAction) and
(FClient.Visible = TCustomAction(Action).Visible);
end;
procedure TColumnActionLink.SetCaption(const Value: string);
begin
if IsCaptionLinked then
FClient.Title := Value;
end;
procedure TColumnActionLink.SetEnabled(Value: Boolean);
begin
if IsEnabledLinked then
FClient.ReadOnly := not Value;
end;
procedure TColumnActionLink.SetOnExecute(Value: TNotifyEvent);
begin
if IsOnExecuteLinked then
FClient.OnTitleClick := Value;
end;
procedure TColumnActionLink.SetVisible(Value: Boolean);
begin
if IsVisibleLinked then
FClient.Visible := Value;
end;
{ TColumn }
procedure TColumn.ActionChanged(Sender: TObject; CheckDefaults: Boolean);
begin
if Sender is TCustomAction then
with TCustomAction(Sender) do
begin
if not CheckDefaults or (Caption = DefaultTitleCaption) then
FTitle := Caption;
if not CheckDefaults or (not ReadOnly) then
ReadOnly := not Enabled;
if not CheckDefaults or not Assigned(FOnTitleClick) then
FOnTitleClick := OnExecute;
if not CheckDefaults or (Self.Visible = True) then
Self.Visible := Visible;
Changed(False);
end;
end;
function TColumn.DefaultTitleCaption: String;
begin
Result := 'Column' + IntToStr(Index);
end;
destructor TColumn.Destroy;
begin
FreeAndNil(FActionLink);
inherited Destroy;
end;
procedure TColumn.DoActionChange(Sender: TObject);
begin
if Sender = Action then
ActionChanged(Sender, False);
end;
procedure TColumn.DoTitleClick;
begin
if Assigned(FOnTitleClick) then
if (Action <> nil) and (@FOnTitleClick <> @Action.OnExecute) then
FOnTitleClick(Self)
else if FActionLink = nil then
FOnTitleClick(Self)
else if FActionLink <> nil then
if (FGrid <> nil) and not (csDesigning in FGrid.ComponentState) then
begin
if not FActionLink.Execute(FGrid) then
FOnTitleClick(Self);
end
else
if not FActionLink.Execute(nil) then
FOnTitleClick(Self);
end;
function TColumn.GetAction: TBasicAction;
begin
if FActionLink <> nil then
Result := FActionLink.Action
else
Result := nil;
end;
function TColumn.GetActionLinkClass: TColumnActionLinkClass;
begin
Result := TColumnActionLink;
end;
procedure TColumn.InitiateAction;
begin
if FActionLink <> nil then
FActionLink.Update;
end;
function TColumn.IsOnTitleClickStored: Boolean;
begin
Result := (FActionLink = nil) or not ActionLink.IsOnExecuteLinked;
end;
function TColumn.IsReadOnlyStored: Boolean;
begin
Result := (FActionLink = nil) or not FActionLink.IsEnabledLinked;
if Result then
Result := FReadOnly;
end;
function TColumn.IsVisibleStored: Boolean;
begin
Result := (FActionLink = nil) or not FActionLink.IsVisibleLinked;
if Result then
Result := not Visible;
end;
procedure TColumn.SetAction(Value: TBasicAction);
begin
if Value = nil then
FreeAndNil(FActionLink)
else
begin
if FActionLink = nil then
FActionLink := GetActionLinkClass.Create(Self);
FActionLink.Action := Value;
FActionLink.OnChange := DoActionChange;
ActionChanged(Value, csLoading in Value.ComponentState);
if FGrid <> nil then
Value.FreeNotification(FGrid);
end;
Changed(False);
end;
end.
Beachten Sie, dass dieser Code nur an die entsprechenden Aktionsteile abgezogen wird.
Quelle: www.nldelphi.com.
Eine Aktionskomponente
Eine Aktionskomponente ist der Aktionseigenschaft einer willkürlichen Komponente zugeordnet. Doch da es ziemlich umfassend ist, alles zu erklären, was mit dem Schreiben einer solchen Aktionskomponente beteiligt ist, werde ich es mir leicht machen, das folgende Beispiel anzugeben.
Angenommen, Sie möchten ein Steuerelement erstellen, das Zoomfunktionen bietet und auch die entsprechenden Zoomin- und Zoomout -Aktionen möchten, die den Symbolleistenschaltflächen zugeordnet werden können.
unit Zoomer;
interface
uses
Classes, Controls, ActnList, Forms, Menus, Windows;
type
TZoomer = class;
TZoomAction = class(TCustomAction)
private
FZoomer: TZoomer;
procedure SetZoomer(Value: TZoomer);
protected
function GetZoomer(Target: TObject): TZoomer;
procedure Notification(AComponent: TComponent; Operation: TOperation);
override;
public
destructor Destroy; override;
function HandlesTarget(Target: TObject): Boolean; override;
procedure UpdateTarget(Target: TObject); override;
published
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property ShortCut;
property SecondaryShortCuts;
property Visible;
property OnExecute; { This property could be omitted. But if you want to be
able to override the default behavior of this action
(zooming in on a TZoomer component), then you need to
assign this event. From within the event handler
you could invoke the default behavior manually. }
property OnHint;
property OnUpdate;
property Zoomer: TZoomer read FZoomer write SetZoomer;
end;
TZoomInAction = class(TZoomAction)
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
end;
TZoomer = class(TCustomControl)
public
procedure ZoomIn;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('RoyMKlever', [TZoomer]);
RegisterActions('Zoomer', [TZoomInAction], nil);
end;
{ TZoomAction }
destructor TZoomAction.Destroy;
begin
if FZoomer <> nil then
FZoomer.RemoveFreeNotification(Self);
inherited Destroy;
end;
function TZoomAction.GetZoomer(Target: TObject): TZoomer;
begin
if FZoomer <> nil then
Result := FZoomer
else if (Target is TZoomer) and TZoomer(Target).Focused then
Result := TZoomer(Target)
else if Screen.ActiveControl is TZoomer then
Result := TZoomer(Screen.ActiveControl)
else
{ This should not happen! HandlesTarget is called before ExecuteTarget,
or the action is disabled }
Result := nil;
end;
function TZoomAction.HandlesTarget(Target: TObject): Boolean;
begin
Result := ((FZoomer <> nil) and FZoomer.Enabled) or
((FZoomer = nil) and (Target is TZoomer) and TZoomer(Target).Focused) or
((Screen.ActiveControl is TZoomer) and Screen.ActiveControl.Enabled);
end;
procedure TZoomAction.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FZoomer) then
FZoomer := nil;
end;
procedure TZoomAction.SetZoomer(Value: TZoomer);
begin
if FZoomer <> Value then
begin
if FZoomer <> nil then
FZoomer.RemoveFreeNotification(Self);
FZoomer := Value;
if FZoomer <> nil then
FZoomer.FreeNotification(Self);
end;
end;
procedure TZoomAction.UpdateTarget(Target: TObject);
begin
Enabled := HandlesTarget(Target);
end;
{ TZoomInAction }
constructor TZoomInAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Caption := 'Zoom in';
Hint := 'Zoom in|Zooms in on the selected zoomer control';
ShortCut := Menus.ShortCut(VK_ADD, [ssCtrl]);
end;
procedure TZoomInAction.ExecuteTarget(Target: TObject);
begin
GetZoomer(Target).ZoomIn;
{ For safety, you cóuld check if GetZoomer <> nil. See remark in GetZoomer. }
end;
{ TZoomer }
procedure TZoomer.ZoomIn;
begin
{ implementation of zooming in }
end;
end.
Aktivieren Sie diese Aktion (mit einem Klick auf eine Symbolleistenschaltfläche oder Auswählen eines Menüelements).
- Die Zoomer -Steuerung, die Sie manuell in der inhaltlichen Eigenschaft der Aktion eingestellt haben, wenn dies ausgeführt wird und wenn die Aktion aktiviert ist, sonst:
- die von der von der Bewerbung angeforderten Antrag Ziel, aber nur, wenn dieses Ziel eine fokussierte Zoomer -Kontrolle ist oder auf andere Weise:
- Die aktive Steuerung in der gesamten Anwendung, jedoch nur dann, wenn dies eine fähige Zoomer -Steuerung ist.
Anschließend wird die Zoomout -Aktion einfach hinzugefügt:
type
TZoomOutAction = class(TZoomAction)
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
end;
{ TZoomOutAction }
constructor TZoomOutAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Caption := 'Zoom out';
Hint := 'Zoom out|Zooms out on the selected zoomer control';
ShortCut := Menus.ShortCut(VK_SUBTRACT, [ssCtrl]);
end;
procedure TZoomOutAction.ExecuteTarget(Target: TObject);
begin
GetZoomer(Target).ZoomOut;
end;
Beachten Sie, dass Aktionskomponenten eine Registrierung in der IDE erfordern, damit sie die Entwurfszeit verwenden können.
Lesen Sie Lebensmittel in der Delphi -Hilfe:
- Aktionskomponenten schreiben,
- Wie Aktionen ihre Ziele finden,
- Aktionen registrieren,
- Was passiert, wenn eine Aktion feuert,
- Aktionen aktualisieren,
- Einrichten von Aktionslisten.
Quelle: www.nldelphi.com.
Andere Tipps
Grundlegende Aktionsunterstützung wird in der TControl -Klasse implementiert. Im einfachsten Fall müssen Sie Ihre Komponente von TControl Nachkommen und Deklary erben Action
Eigentum wie veröffentlicht, z.
type
TMyGraphicControl = class(TGraphicControl)
published
property Action;
end;
Wenn Ihre Komponente über zusätzliche Eigenschaften verfügt, die mit Taction -Eigenschaften verknüpft werden sollten, sollten Sie auch überschreiben ActionChange Methode.
Wenn Ihre Komponente bereits ein Nachkomme von Tbutton ist, wird die Aktionsunterstützung vererbt. Alles, was Sie tun müssen, ist die Aktionseigenschaft wie veröffentlicht zu deklarieren.