Announcement

Collapse
No announcement yet.

Controls dynamisch erzeugen und zerstören

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Controls dynamisch erzeugen und zerstören

    Hallo,

    ich möchte ein oder mehrere TEdit-Felder während der Laufzeit erzeugen. Dies funktioniert auch mit folgendem Code :

    with Tedit.Create(self) do begin<BR>
    Parent := Panel1;<BR>
    left :=5;<BR>
    top := 90;<BR>
    end;<BR>

    Nach Klick auf einen Button sollen die dynamisch erzeugten TEdit-Felder wieder vom Panel gelöscht werden, wie bekomme ich das hin?

    Danke Werner

  • #2
    Hallo Werner,<br>wenn Du die TEdit's wieder entfernen willst, mußt Du dir irgendwie merken, wo Du sie gelassen hast. statische Array's sind blöd, weil Du Dich dann auf eine Anzahl festlegen mußt. Dynamische Array's hören sich nach VB an (also auch blöd). Ich muß zugeben, ich bin ein TList Fan. Deshalb schlage ich Dir vor, die TEdit's mit TList zu verwalten.<br>
    <pre><font size="1" face="Verdana">
    <pre><font size="1" face="Verdana">
    unit Unit1;

    interface

    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    JsList, StdCtrls, Spin;

    type
    TControlItem =class(TObject)
    private
    FEdit: TEdit;
    public
    constructor Create(Owner,Parent : TWinControl);
    destructor Destroy; override;
    property Edit : TEdit read FEdit;
    end;

    TControlItems = class(TJsCustomList)
    private
    function GetItem(X: Integer): TControlItem;
    public
    function Add(Owner,Parent : TWinControl) : TControlItem;
    property Items[X : Integer] : TControlItem read GetItem; default;
    end;

    TForm1 = class(TForm)
    spedtControlCount: TSpinEdit;
    Label1: TLabel;
    ScrollBox1: TScrollBox;
    btnCreate: TButton;
    btnDestroy: TButton;
    procedure Label1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnDestroyClick(Sender: TObject);
    procedure btnCreateClick(Sender: TObject);
    private
    { Private-Deklarationen }
    FControlItems : TControlItems;
    public
    { Public-Deklarationen }
    end;

    var
    Form1: TForm1;

    implementation

    {$R *.DFM}

    procedure TForm1.Label1Click(Sender: TObject);
    begin

    end;

    { TControlItems }

    function TControlItems.Add(Owner,Parent: TWinControl): TControlItem;
    begin
    Result:=TControlItem.Create(Owner,Parent);
    List.Add(Result);
    end;

    function TControlItems.GetItem(X: Integer): TControlItem;
    begin
    Result:=TControlItem(List.Items[X]);
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    FControlItems:=TControlItems.Create;
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    FControlItems.Free;
    end;

    procedure TForm1.btnDestroyClick(Sender: TObject);
    begin
    FControlItems.Clear;
    end;

    { TControlItem }

    constructor TControlItem.Create(Owner,Parent: TWinControl);
    begin
    inherited Create;
    FEdit:=TEdit.Create(Owner);
    FEdit.Parent:=Parent;
    end;

    destructor TControlItem.Destroy;
    begin
    FEdit.Free;
    inherited Destroy;
    end;

    procedure TForm1.btnCreateClick(Sender: TObject);
    var
    iCnt : Integer;
    Item : TControlItem;
    begin
    For iCnt:=0 to spedtControlCount.Value-1 do
    begin
    Item:=FControlItems.Add(Self,ScrollBox1);
    Item.Edit.SetBounds(4,4+iCnt*(Item.Edit.Height+2), Item.Edit.Width,Item.Edit.Height);
    end;
    end;

    end.
    </font></pre&gt

    Comment


    • #3
      <pre><font size="1" face="Verdana">
      unit JsList;

      interface

      uses SysUtils, Classes;

      Type

      TJsCustomList = class(TObject)
      private
      FList : TList;
      function GetCount: Integer;
      protected
      property List : TList read FList;
      public
      constructor Create;
      destructor Destroy; override;
      procedure Clear;
      procedure Delete(X : Integer);
      property Count : Integer read GetCount;
      end;

      implementation

      Type
      EJsListDeleteIndexError = class(Exception);


      { TJsCustomList }

      procedure TJsCustomList.Clear;
      var
      iCnt : Integer;
      begin
      For iCnt:=0 to FList.Count-1 do
      TObject(FList.Items[iCnt]).Free;
      FList.Clear;
      end;

      constructor TJsCustomList.Create;
      begin
      inherited Create;
      FList:=TList.Create;
      end;

      procedure TJsCustomList.Delete(X: Integer);
      begin
      Try
      TObject(FList.Items[x]).Free;
      FList.Delete(X);
      Except
      raise EJsListDeleteIndexError.Create('Indexfehler bei Delete. Index: '+IntToStr(X)+#13#10+
      'MaxIndex: '+IntToStr(Count-1));
      end;
      end;

      destructor TJsCustomList.Destroy;
      begin
      Clear;
      FList.Free;
      inherited Destroy;
      end;

      function TJsCustomList.GetCount: Integer;
      begin
      Result:=FList.Count;
      end;

      end.

      // Formular Datei
      object Form1: TForm1
      Left = 345
      Top = 230
      Width = 309
      Height = 245
      Caption = 'Form1'
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'MS Sans Serif'
      Font.Style = []
      OldCreateOrder = False
      OnCreate = FormCreate
      OnDestroy = FormDestroy
      PixelsPerInch = 96
      TextHeight = 13
      object Label1: TLabel
      Left = 212
      Top = 16
      Width = 32
      Height = 13
      Caption = 'Anzahl'
      OnClick = Label1Click
      end
      object spedtControlCount: TSpinEdit
      Left = 212
      Top = 36
      Width = 77
      Height = 22
      MaxValue = 0
      MinValue = 0
      TabOrder = 0
      Value = 0
      end
      object ScrollBox1: TScrollBox
      Left = 8
      Top = 20
      Width = 185
      Height = 189
      TabOrder = 1
      end
      object btnCreate: TButton
      Left = 212
      Top = 68
      Width = 75
      Height = 25
      Caption = 'Create'
      TabOrder = 2
      OnClick = btnCreateClick
      end
      object btnDestroy: TButton
      Left = 212
      Top = 100
      Width = 75
      Height = 25
      Caption = 'Destroy'
      TabOrder = 3
      OnClick = btnDestroyClick
      end
      end
      </font></pre>
      <br>Jens Schuman

      Comment


      • #4
        Hallo,<p>
        ich habe einen einfacheren Vorschlag. TPanel ist ein Container und mit der Eigenschaft Controls kann man auf alle untergeordneten Elemente zugreifen. Mit RemoveControl kann ein Element wieder entfernt werden.<br>
        Nun gibt es 2 Möglichkeiten. Werner hat sich nicht darüber ausgelassen, ob das Panel nur dynamisch erzeugte TEdit-Objekte enthält oder ob es auch welche gibt die zur Entwurfszeit eingefügt wurden. Jedes VCL-Objekt hat die Eigenschaft Tag, die jeder für seine eigenen Zwecke verwenden kann. Tag ist vom Typ Longint. Wenn die TEdit-Objekte alle zum gleichen Zeitpunkt wieder entfernt werden sollen und nicht unterschieden werden müssen, so könnte man nach dem erzeugen Tag := 1 setzen und beim Entfernen einfach alle Elemente in einer Schleife durchlaufen und diejenigen entfernen, bei denen Tag = 1 ist. Unter TWinControl.Controls in der Hilfe gibt es ein Beispiel dafür, wie man alle Komponenten in einem TPanel-Objekt durchlaufen kann.<p>
        Man kann sich also die separate Verwaltung in einer Extra-Liste sparen.<p>
        Gruß Wolfgan

        Comment


        • #5
          Hallo,

          zunächst bedanke ich mich für eure Antworten. Ihr habt mir damit einen großen Schritt weitergeholfen. Auf dem Panel gibt es eine Groupbox, die immer vorhanden ist. In der Groupbox sind ein paar Controls vorhanden. Alle anderen Controls auf dem Panel sollen dynamisch erzeugt und wieder entfernt werden. Ich werde beide Möglichkeiten ausprobieren die Ihr mir beschrieben habt.

          Werne

          Comment


          • #6
            Hallo Wolfgang,<br>Du hast sicherkich recht. Dein Vorschlag benötigt weniger Tippaufwand. Früher habe ich solche Probleme auch so gelöst. Jedoch mußte ich mit der Zeit feststellen, dass die Methode über die Tag-Property ziemlich unübersichtlich wird und nicht gerade wartungs- u. erweiterungsfreundlich ist. Deshalb bin dazu übergegangen sowas in Collections zu verwalten. Dann weiß immer wo die Objekte sind. Außerdem bietet diese Methode den Vorteil, dass man die TEdit's in TControlItems als "ein" Objekt auffassen kann. D.h Du kannst sehr einfach TControlItems Methoden hinzufügen, die objektintern alle TEdit's ansprechen. Z.B. den Text aller TEdit's an eine TStringList übergeben.<br>Jens Schuman

            Comment


            • #7
              Hallo Jens,<p>

              mir geht es in erster Linie nicht um den Tippaufwand sondern um sauberes Design. Wobei sauberes Design und wenig Tippaufwand meistens miteinander inhergehen. Wenn du schon den vorhandenen Container von TPanel nicht nutzen willst, so läßt sich deine Lösung um einiges vereinfachen. Ich habe die Klassen TControlItem und TControlItems eingespart und die Klasse TJsCustomList direkt von TList abgeleitet. Die Klasse TControlItem hat nun eine Add-Methode:<p>
              <PRE>
              function Add(Owner, Parent: TWinControl; ClassRef: TControlRef): TControl; virtual;</PRE><p>
              Das dritte Argument ist eine Klassenreferenz. Dadurch wird die Klasse weitaus flexibler, denn es können verschiedene Objekte in das Panel bzw. die ScrollBox aufgenommen werden. Ich habe deshalb auch das Formular TForm1 um einen Button erweitert, der statt einem TEdit-Objekt ein TLabel-Objekt in die ScrollBox einfügt. Nur mal so als Beispiel um zuzeigen wie das mit den Klassenreferenzen syntaktisch funktioniert. In der Add-Methode wird als drittes Argument der Klassen name übergeben. Die Add-Methode erzeugt dann ein Objekt von genau dieser Klasse. Darum kann ich auch den Rückgabewert wieder in ein Objekt von diesem Klasse "casten". Hier ist der Quellcode dazu:<p>
              <pre>
              unit Unit1;

              interface

              uses
              Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
              Dialogs, JsList, StdCtrls;

              const
              ITEM_HEIGHT = 22;
              type

              TForm1 = class(TForm)
              Label1: TLabel;
              ScrollBox1: TScrollBox;
              btnCreate: TButton;
              btnDestroy: TButton;
              ButtonCreateLabel: TButton;
              Edit1: TEdit;
              procedure FormCreate(Sender: TObject);
              procedure FormDestroy(Sender: TObject);
              procedure btnDestroyClick(Sender: TObject);
              procedure btnCreateClick(Sender: TObject);
              procedure ButtonCreateLabelClick(Sender: TObject);
              private
              FListe : TJsCustomList;
              Counter: Integer;
              procedure ClearCounter;
              procedure Positioniere(Item: TControl);
              public
              end;

              var Form1: TForm1;

              implementation

              {$R *.DFM}

              procedure TForm1.FormCreate(Sender: TObject);
              begin
              FListe := TJsCustomList.Create;
              ClearCounter;
              end;

              procedure TForm1.FormDestroy(Sender: TObject);
              begin
              FListe.Free;
              end;

              procedure TForm1.btnDestroyClick(Sender: TObject);
              begin
              FListe.Clear;
              ClearCounter;
              end;

              procedure TForm1.btnCreateClick(Sender: TObject);
              var
              Item: TEdit;
              begin
              Item := TEdit(FListe.Add(Self, ScrollBox1, TEdit));
              Positioniere(Item);
              end;

              procedure TForm1.ButtonCreateLabelClick(Sender: TObject);
              var
              Item: TLabel;
              begin
              Item := TLabel(FListe.Add(Self, ScrollBox1, TLabel));
              Item.Caption := 'Test';
              Positioniere(Item);
              end;

              procedure TForm1.ClearCounter;
              begin
              Counter := 0;
              Edit1.Text := IntToStr(Counter);
              end;

              procedure TForm1.Positioniere(Item: TControl);
              begin
              Item.SetBounds(4, 4 + (Counter * ITEM_HEIGHT), Item.Width, Item.Height);
              Inc(Counter);
              Edit1.Text := IntToStr(Counter);
              end;

              end.

              // Das Formular als Quelltext:
              object Form1: TForm1
              Left = 118
              Top = 160
              Width = 303
              Height = 250
              Caption = 'Form1'
              Color = clBtnFace
              Font.Charset = DEFAULT_CHARSET
              Font.Color = clWindowText
              Font.Height = -11
              Font.Name = 'MS Sans Serif'
              Font.Style = []
              OldCreateOrder = False
              OnCreate = FormCreate
              OnDestroy = FormDestroy
              PixelsPerInch = 96
              TextHeight = 13
              object Label1: TLabel
              Left = 208
              Top = 16
              Width = 32
              Height = 13
              Caption = 'Anzahl'
              end
              object ScrollBox1: TScrollBox
              Left = 8
              Top = 20
              Width = 185
              Height = 189
              TabOrder = 0
              end
              object btnCreate: TButton
              Left = 208
              Top = 68
              Width = 73
              Height = 25
              Caption = 'Create Edit'
              TabOrder = 1
              OnClick = btnCreateClick
              end
              object btnDestroy: TButton
              Left = 208
              Top = 135
              Width = 73
              Height = 25
              Caption = 'Destroy all'
              TabOrder = 2
              OnClick = btnD

              Comment


              • #8
                Hallo Jens,<p>

                mir geht es in erster Linie nicht um den Tippaufwand sondern um sauberes Design. Wobei sauberes Design und wenig Tippaufwand meistens miteinander inhergehen. Wenn du schon den vorhandenen Container von TPanel nicht nutzen willst, so läßt sich deine Lösung um einiges vereinfachen. Ich habe die Klassen TControlItem und TControlItems eingespart und die Klasse TJsCustomList direkt von TList abgeleitet. Die Klasse TControlItem hat nun eine Add-Methode:<p>
                <PRE>
                function Add(Owner, Parent: TWinControl; ClassRef: TControlRef): TControl; virtual;</PRE><p>
                Das dritte Argument ist eine Klassenreferenz. Dadurch wird die Klasse weitaus flexibler, denn es können verschiedene Objekte in das Panel bzw. die ScrollBox aufgenommen werden. Ich habe deshalb auch das Formular TForm1 um einen Button erweitert, der statt einem TEdit-Objekt ein TLabel-Objekt in die ScrollBox einfügt. Nur mal so als Beispiel um zuzeigen wie das mit den Klassenreferenzen syntaktisch funktioniert. In der Add-Methode wird als drittes Argument der Klassenname übergeben. Die Add-Methode erzeugt dann ein Objekt von genau dieser Klasse. Darum kann ich auch den Rückgabewert wieder in ein Objekt von diesem Klasse "casten". Hier ist der Quellcode dazu:<p>
                <pre>
                unit Unit1;

                interface

                uses
                Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
                Dialogs, JsList, StdCtrls;

                const
                ITEM_HEIGHT = 22;
                type

                TForm1 = class(TForm)
                Label1: TLabel;
                ScrollBox1: TScrollBox;
                btnCreate: TButton;
                btnDestroy: TButton;
                ButtonCreateLabel: TButton;
                Edit1: TEdit;
                procedure FormCreate(Sender: TObject);
                procedure FormDestroy(Sender: TObject);
                procedure btnDestroyClick(Sender: TObject);
                procedure btnCreateClick(Sender: TObject);
                procedure ButtonCreateLabelClick(Sender: TObject);
                private
                FListe : TJsCustomList;
                Counter: Integer;
                procedure ClearCounter;
                procedure Positioniere(Item: TControl);
                public
                end;

                var Form1: TForm1;

                implementation

                {$R *.DFM}

                procedure TForm1.FormCreate(Sender: TObject);
                begin
                FListe := TJsCustomList.Create;
                ClearCounter;
                end;

                procedure TForm1.FormDestroy(Sender: TObject);
                begin
                FListe.Free;
                end;

                procedure TForm1.btnDestroyClick(Sender: TObject);
                begin
                FListe.Clear;
                ClearCounter;
                end;

                procedure TForm1.btnCreateClick(Sender: TObject);
                var
                Item: TEdit;
                begin
                Item := TEdit(FListe.Add(Self, ScrollBox1, TEdit));
                Positioniere(Item);
                end;

                procedure TForm1.ButtonCreateLabelClick(Sender: TObject);
                var
                Item: TLabel;
                begin
                Item := TLabel(FListe.Add(Self, ScrollBox1, TLabel));
                Item.Caption := 'Test';
                Positioniere(Item);
                end;

                procedure TForm1.ClearCounter;
                begin
                Counter := 0;
                Edit1.Text := IntToStr(Counter);
                end;

                procedure TForm1.Positioniere(Item: TControl);
                begin
                Item.SetBounds(4, 4 + (Counter * ITEM_HEIGHT), Item.Width, Item.Height);
                Inc(Counter);
                Edit1.Text := IntToStr(Counter);
                end;

                end.
                </pre&gt

                Comment


                • #9
                  Fortsetzung:<br>
                  // Das Formular als Quelltext:
                  object Form1: TForm1
                  Left = 118
                  Top = 160
                  Width = 303
                  Height = 250
                  Caption = 'Form1'
                  Color = clBtnFace
                  Font.Charset = DEFAULT_CHARSET
                  Font.Color = clWindowText
                  Font.Height = -11
                  Font.Name = 'MS Sans Serif'
                  Font.Style = []
                  OldCreateOrder = False
                  OnCreate = FormCreate
                  OnDestroy = FormDestroy
                  PixelsPerInch = 96
                  TextHeight = 13
                  object Label1: TLabel
                  Left = 208
                  Top = 16
                  Width = 32
                  Height = 13
                  Caption = 'Anzahl'
                  end
                  object ScrollBox1: TScrollBox
                  Left = 8
                  Top = 20
                  Width = 185
                  Height = 189
                  TabOrder = 0
                  end
                  object btnCreate: TButton
                  Left = 208
                  Top = 68
                  Width = 73
                  Height = 25
                  Caption = 'Create Edit'
                  TabOrder = 1
                  OnClick = btnCreateClick
                  end
                  object btnDestroy: TButton
                  Left = 208
                  Top = 135
                  Width = 73
                  Height = 25
                  Caption = 'Destroy all'
                  TabOrder = 2
                  OnClick = btnDestroyClick
                  end
                  object ButtonCreateLabel: TButton
                  Left = 208
                  Top = 100
                  Width = 73
                  Height = 25
                  Caption = 'Create Label'
                  TabOrder = 3
                  OnClick = ButtonCreateLabelClick
                  end
                  object Edit1: TEdit
                  Left = 208
                  Top = 32
                  Width = 73
                  Height = 21
                  TabOrder = 4
                  end
                  end
                  </pre><p>
                  Die Unit JsUnit:<p>
                  <pre>
                  unit JsList;

                  interface

                  uses SysUtils, Classes, Controls;

                  Type
                  TControlRef = class of TControl;

                  TJsCustomList = class(TList)
                  private
                  function GetItems(I: Integer): TControl;
                  protected
                  public
                  destructor Destroy; override;
                  function Add(Owner, Parent: TWinControl; ClassRef: TControlRef): TControl; virtual;
                  procedure Clear; virtual;
                  property Items[I: Integer]: TControl read GetItems; default;
                  end;

                  implementation

                  { TJsCustomList }
                  function TJsCustomList.Add(Owner, Parent: TWinControl; ClassRef: TControlRef): TControl;
                  begin
                  Result := ClassRef.Create(Owner);
                  Result.Parent := Parent;
                  inherited Add(Result);
                  end;

                  procedure TJsCustomList.Clear;
                  // Im Gegensatz zu Clear von TList werden hier die Objekte,
                  // die entfernt werden, auch zerstört.
                  var
                  iCnt: Integer;
                  begin
                  for iCnt := Count - 1 downto 0 do begin
                  TControl(Items[iCnt]).Free;
                  Delete(iCnt);
                  end;
                  end;

                  destructor TJsCustomList.Destroy;
                  begin
                  Clear;
                  inherited Destroy;
                  end;

                  function TJsCustomList.GetItems(I: Integer): TControl;
                  begin
                  Result := inherited Items[I];
                  end;

                  end.
                  </pre>
                  <p>
                  Aber um nochmals auf Werners Problem zurückzukommen. In seinem Fall, wo nur TEdit-Objekt dynamisch an das Panel angehängt werden und wo es nur darum geht diese dann wieder zu entfernen, würde ich doch meinen ersten Vorschlag verwenden. Man kann sich sogar die Sache mit dem Tag sparen. Man geht alle Objekte im Panel-Container durch und fragt sie nach ihrer Klasse. Wer mit TEdit antwortet hat Pech gehabt und wird zerstört.<p>
                  Gruß<p>
                  Wolfgang Rolle

                  Comment


                  • #10
                    Moin Wolfgang,<br>interessante Lösung. Respekt.<br>Clear ist in TList schon virtual. Deshalb würde ich Clear überschreiben (override). Damit sollte Clear so aussehen<br><pre>
                    procedure TJsCustomList.Clear;
                    // Im Gegensatz zu Clear von TList werden hier die Objekte,
                    // die entfernt werden, auch zerstört.
                    var
                    iCnt: Integer;
                    begin
                    for iCnt := Count - 1 downto 0 do
                    TControl(Items[iCnt]).Free;
                    inherited Clear;
                    end; </pre><br>Eine andere Sache ist die Items property. Diese property ist vom Type TControl. D.h. wenn ich auf properties zugreiffen will, die erst in einem TControl Nachfahren deklariert sind muß ich mit Typumwandlung arbeiten. <br>Jens Schuman

                    Comment


                    • #11
                      Hallo Jens,<p>
                      mit dem dem override hast du Recht. Sinnigerweise sollte man die Clear-Methode mit override deklarieren. (Wobei es für das Beispiel-Programm ohne belang ist.)<p>
                      Zu deinem Einwand mit den Properties: Auch da hast du sicherlich Recht, wenn man es unter dem Aspekt betrachtet, daß man, wie in Werners Fall, eigentlich nur mit TEdit-Objekten arbeitet, dann eine Typumwandlung vornehmen muß, wenn man auf Eigentschaften zugreifen will, die nur in TEdit definiert sind.<br>
                      Man kann die Klasse TJsCustomList auch so umschreiben, daß sie eben nur mit TEdit-Objekten umgehen kann. Aber man verletzt dadurch wieder eines der objektorientierten Paradigmen, nämlich die Wiederverwertbarkeit. Was machst du, wenn du das nächste Mal TButton-Objekte benötigst. Eine Möglichkeit ist natürlich eine neue Klasse zu definieren, die genauso arbeitet wie TJsCustomList, aber anstatt mit TEdit-Objekten eben mit TButton-Objekten. Das ist nicht Sinn der Objektorientierung.<br>
                      Wie schon gesagt, im Fall mit den VCL-Klassen, die von TControl abgeleitet sind, kommt am um den einen oder anderen Cast nicht herum. Hat man aber das Klassen-Design selbst in der Hand geht man sinnvollerweise so vor, daß man eine gemeinsame abstrakte Oberklasse definiert die schon alle Methoden als virtuelle und abstrakte Methoden vorhält. Die nachfolgenden Klassen müßen diese dann überschreiben.<br> Hier sei einmal ein Blick über den Java-Zaun erlaubt. Bei Java ist es so, daß alle Methoden einer Klasse implizit virtuell sind und eine Klasse ansich kann als abstrakt deklariert werden. Dadurch wird verhindert, daß Instanzen einer Klasse generiert werden können. Bei Object Pascal geht das leider nicht, obwohl dieses Vorgehen durchaus sinnvoll ist.<p>
                      Geht man auf diese Art und Weise vor, wird eine Typumwandlung unötig. Das ganze läuft unter dem Begriff Polymorphie (oder deutsch: Vielgestaltigkeit). Ich möchte mal ein Beispiel geben das in vielen Kursen zu objektorientierten Sprachen verwendet wird. Man stelle sich Objekte vor die auf einer Zeichenfläche als geometrische Figuren dargestellt werden sollen, also Kreise, Quadrate, Rechtecke, Vielecke etc. Man definiert eine abstrakte Oberklasse namens GeometrischeForm:<pre>
                      GeometrischeForm = class(TObject)
                      private
                      // Die Koordinaten-Geschichte die ich nicht
                      // explizit aufzeigen möchte
                      public
                      procedure ZeichneDich; virtual; abstract;
                      end;

                      Davon abgeleitet die Klassen:

                      Kreis = class(GeometrischeForm)
                      private
                      ...
                      public
                      procedure ZeichneDich; override;
                      end;

                      Rechteck = class(GeometrischeForm)
                      private
                      ...
                      public
                      procedure ZeichneDich; override;
                      end;

                      Quadrat = class(Rechteck)
                      private
                      ...
                      public
                      procedure ZeichneDich; override;
                      end;

                      usw.

                      Die ganzen Objekte können in einem Container vom Typ TList verwaltet werden.

                      GeomFormContainer: TList;

                      Man kann nun sich nun eine Methode vorstellen, die dafür verantwortlich
                      ist, daß die Objekte sich auf dem Bildschirm darstellen.

                      procedure TForm1.ZeichneFiguren;
                      var
                      Figur: GeometrischeForm;
                      I: Integer;
                      begin
                      for I := 0 to GeomFormContainer.Count - 1 do begin
                      Figur := GeometrischeForm(GeomFormContainer.Items[I]);
                      Figur.ZeichneDich;
                      end;
                      end;

                      In dieser Methode wird keine Instanz der "abstrakten" Klasse
                      GeometrischeForm erzeugt sondern lediglich eine Referenz von
                      diesem Typ. Beim Erzeugen der Objekte werden explizit Kreise,
                      Rechtecke usw. erzeugt und in den Container gestellt:

                      GeomFormContainer.Add(Kreis.Create);
                      GeomFormContainer.Add(Rechteck.Create);
                      GeomFormContainer.Add(Quadrat.Create);
                      ...;

                      Dadurch, daß die Methode ZeichenDich in der Oberklasse als
                      virtuell deklariert wird, wird zur Laufzeit dafür gesorgt,
                      daß bei einem Kreis auch die Methode ZeichneDich der Kreis-
                      Klasse ausgeführt wird, obwohl die Referenz über die ich
                      die Methode aufrufe vom Typ GeometrischeForm ist.

                      Fortsetzung folgt!</pre&gt

                      Comment


                      • #12
                        <pre>Auf diese Art und Weise wird keine Typumwandlung benötig.
                        Und das Design ist komfortabel erweiterbar. Angenommen zu
                        einem späteren Zeitpunkt, wenn das Programm schon fertig ist
                        und zu unserer Zufriedenheit läuft kommt noch die Forderung
                        hinzu, das Programm solle auch sechseckige Sterne zeichnen
                        können. Alles was wir tun müssen ist, eine neue Klasse
                        SechseckigerStern hinzuzufügen. (Der schlaue Praktiker würde
                        natürlich zuerst noch eine allgemeine Klasse Stern dazwischen
                        einfügen, denn er weiß, daß wenn jemand nach einem sechseckigen
                        Stern verlangt, dieser wenig später auch nach einem fünfeckigen
                        oder sonst wieviel eckigen Stern schreit.)

                        Die Methode TForm1.ZeichneFiguren bleibt von dieser Änderung
                        völlig unberührt, sorgt aber dennoch dafür, daß nun auch Sterne
                        gezeichnet werden.
                        </pre>
                        Soviel zu abstrakten Klassen und Typumwandlungen.<p>
                        Gruß<p>
                        Wolfgang Rolle

                        Comment


                        • #13
                          Hallo Jens & Wolfgang,

                          ich danke Euch für Eure Hilfe!!! Ich überlege gerade, ob ich noch ein paar Tage warte mit der Implementierung, vielleicht habt Ihr ja noch ein paar Verbesserungsvorschläge .... ;-). Übrigens sollen jetzt auch noch RTF Boxen mit dazu aber ich denke das bekomme ich jetzt hin dank Eurer Hilfe.

                          Werner Ensin

                          Comment

                          Working...
                          X