Einzelnen Beitrag anzeigen

Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#8

AW: Alle DB Controls je nach state einfärben.

  Alt 30. Dez 2012, 12:30
Ich würde hier das Visitor-Pattern verwenden. Dazu habe ich mal einen Artikel geschrieben, der die Hintergründe ausführlich beleuchtet und ein paar Lösungsansätze aufzeigt. Im 4.Teil des Artikels wird eine Implementation beschrieben, die ich bei dieser Lösung verwendet habe. Als Beispiel habe ich ein Form mit einem DbEdit und einem DbText verwendet. Beide führen das DataSource-Property parallel ein und man kann somit nicht auf einen gemeinsamen Vorfahren zugreifen.

Hier zunächst der Basis-Visitor:
Delphi-Quellcode:
unit uVisitor;

interface

type
  TVisitor = class
  public
    procedure Visit(Instance: TObject); virtual;
  end;

implementation

uses
  Rtti;

procedure TVisitor.Visit(Instance: TObject);
var
  context: TRttiContext;
  currentClass: TClass;
  params: TArray<TRttiParameter>;
  paramType: TRttiType;
  selfMethod: TRttiMethod;
  S: string;
begin
  context := TRttiContext.Create;
  currentClass := Instance.ClassType;
  repeat
    S := currentClass.ClassName;
    Delete(S, 1, 1); // remove "T"
    for selfMethod in context.GetType(self.ClassType).GetMethods('Visit' + S) do begin
      params := selfMethod.GetParameters;
      if (Length(params) = 1) then begin
        paramType := params[0].ParamType;
        if ParamType.IsInstance and (ParamType.AsInstance.MetaclassType = currentClass)then begin
          selfMethod.Invoke(Self, [Instance]);
          Exit;
        end;
      end;
    end;
    currentClass := currentClass.ClassParent;
  until currentClass = nil;
end;

end.
Und hier die abgeleitete Klasse mit den Implementationen für die verschiedenen Controls. Weitere Controls (z.B. TDBAdvEdit) kann man durch einfaches Hinzufügen einer procedure VisitDBAdvEdit(Instance: TDBAdvEdit); abdecken:
Delphi-Quellcode:
unit uVisitorDbState;

interface

uses
  uVisitor, Vcl.DBCtrls, Data.DB;

type
  TVisitorDbState = class(TVisitor)
  private
    FDataSource: TDataSource;
  public
    procedure VisitDbEdit(Instance: TDbEdit);
    procedure VisitDbText(Instance: TDbText);
    property DataSource: TDataSource read FDataSource write FDataSource;
  end;

implementation

uses
  Vcl.Graphics;

procedure TVisitorDbState.VisitDbEdit(Instance: TDbEdit);
begin
  if Instance.DataSource = DataSource then begin
    case DataSource.State of
      dsEdit: Instance.Color := clYellow;
      dsInsert: Instance.Color := clGreen;
    else
      Instance.Color := clWindow;
    end;
  end;
end;

procedure TVisitorDbState.VisitDbText(Instance: TDbText);
begin
  if Instance.DataSource = DataSource then begin
    case DataSource.State of
      dsEdit: Instance.Font.Style := [fsBold];
      dsInsert: Instance.Font.Style := [fsItalic];
    else
      Instance.Font.Style := [];
    end;
  end;
end;

end.
Hier die Verwendung des Visitors. Natürlich kann man auch die Iteration über die Controls durchführen, statt über die Components:
Delphi-Quellcode:
procedure TForm188.AdjustStateColor;
var
  I: Integer;
  visitor: TVisitorDbState;
begin
  visitor := TVisitorDbState.Create;
  try
    visitor.DataSource := DataSource1;
    for I := 0 to ComponentCount - 1 do
      visitor.Visit(Components[I]);
  finally
    visitor.Free;
  end;
end;

procedure TForm188.DataSource1StateChange(Sender: TObject);
begin
  AdjustStateColor;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat