Announcement

Collapse
No announcement yet.

Ereignisbehandlung von Unter-Propertys zur Entwicklungszeit

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

  • Ereignisbehandlung von Unter-Propertys zur Entwicklungszeit

    Hallo!
    Ich habe folgendes Problem:
    Ich beschäftige mich im Moment mit Komponenten. Dazu möchte ich Propertys mit Unter-Propertys benutzen. Diese Unter-Propertys zu erstellen ist noch nicht das Problem (Dank diesem Forums). Nun möchte ich aber, dass wenn der Entwickler zur Entwicklungszeit ein Unter-Property ändert, dieses auch sofort bei der Komponente zu sehen ist.
    Z.B.:

    <pre>
    unit GraphRas;

    interface

    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    ExtCtrls;

    type
    TRahmen=class(TPersistent)
    private
    FDarstellen: Boolean;
    FFarbe:TColor;
    published
    property Darstellen:Boolean read FDarstellen write FDarstellen;
    property Farbe:TColor read FFarbe write FFarbe;
    end;

    TGraphRas = class(TImage)
    private
    { Private declarations }
    FRahmen:TRahmen;
    FTest:Integer;
    procedure Set_Test(value:integer);
    protected
    { Protected declarations }
    public
    { Public declarations }
    constructor create(AOwner:TComponent);override;
    destructor destroy; override;
    published
    { Published declarations }
    procedure Graph_Zeichnen;
    property Rahmen:TRahmen read FRahmen write FRahmen;
    property Test:Integer read FTest write Set_Test default 0;
    end;

    procedure Register;

    implementation

    procedure Register;
    begin
    RegisterComponents('Rasmus', [TGraphRas]);
    end;

    constructor TGraphRas.create (AOwner:TComponent);
    begin
    inherited create(AOwner);
    FRahmen:=TRahmen.Create ;
    FRahmen.Darstellen :=false;
    FRahmen.Farbe :=clBlack;
    end;

    destructor TGraphRas.destroy ;
    begin
    inherited destroy;
    end;

    procedure TGraphRas.Graph_Zeichnen ;
    begin
    // Rahmen zeichnen.
    if FRahmen.Darstellen then
    begin
    With Canvas.Pen do
    begin
    Canvas.Pen.Style :=psSolid;
    Canvas.Pen.Mode :=pmCopy;
    Canvas.Pen.Width :=1;
    Canvas.Pen.Color :=FRahmen.Farbe ;
    Canvas.Rectangle (2,2,30,30);
    end; //With Canvas.Pen do
    end; //if FRahmen.Darstellen then
    end;

    procedure TGraphRas.Set_Test (value:integer);
    begin
    FTest:=value;
    Graph_Zeichnen;
    end;
    end.
    </pre>

    Hier wird ein Property mit dem Namen “Rahmen“ erzeugt, das die Unter-Propertys „Darstellen“ und „Farbe“ besitzt. Nun will ich, dass bei der Änderung von „Darstellen“ oder „Farbe“ dieses zur Entwicklungszeit auch durchgeführt wird. Ich habe schon einiges versucht, komme aber nicht zum Ziel.
    Erst wenn ich das Property „Test“ ändere werden auch die Einstellungen von „Darstellen“ oder „Farbe“ übernommen.
    Wie bekomme ich es hin, dass beim Ändern eines der Unter-Propertys „Darstellen“ oder „Farbe“ ein ähnlicher Procedure-Aufruf durchgeführt wird, wie bei dem Property „Test“?

    Ich hoffe ich mein Problem verständlich beschrieben und bedanke mich für Eure Hilfe.
    Gruß
    Rasmus

  • #2
    Hi

    Die Eigenschaften FRahmen und FDarstellen sollten mit Set-Methoden verändert werden.In diesem Fall kann nun der Owner-Komponente mittgeteilt werden das sie sich neuzeichnen muss. Wie machst Du es während der Laufzeit ??

    <pre>

    type
    TRahmen = class
    private
    FRahmen: Integer;
    FOwner: TControl;
    FOnChange: TNotifyEvent;
    procedure SetRahmen(Value: Integer);
    protected
    procedure Changed; dynamic;
    published
    property Rahmen: Integer read FRahmen write SetRahmen;
    end;<br>

    procedure TRahmen.SetRahmen(Value: Integer);
    begin
    if Value <> FRahmen then
    begin
    FRahmen := Value;
    Changed;
    end;
    end;<br>

    procedure TRahmen.Changed;
    begin
    1.) -------
    FControl.Invalidate;<br>

    2.) ------- besser mit Event, so wie TGraphic, TFont etc.
    if Assigned(FOnChange) then
    FOnChange(Self);
    end;

    </pre>

    Gruß Hage

    Comment


    • #3
      Hallo!
      Danke für die Antwort.
      Ich bin gerade in Sonthofen in einem Internetcaffee. Ich werden am Sonntagabend gleich mal versuchen ob es klappt.
      Bis dann
      rasmu

      Comment


      • #4
        Hallo!
        So, ich habe alles???? versucht und bin zu keinem Ergebnis gekommen. Vielleicht kann mir jemand über das ersten Listing zeigen, wie das exakt geht. Z.B.: Wenn das Unter-Property „Darstellen“ geändert wird, dass die Methode „TGraphRas.Graph_Zeichnen“ aufgerufen wird.
        Ich schaffe es einfach nicht!!!!!!
        Bis dann
        rasmu

        Comment


        • #5
          Hi

          Du hast alles so umgeschrieben wie ich es oben gezeigt habe ! Mit einen FOnChange: TNotifyEvent;

          Nun in TGraphRas folgendes:

          <pre>

          type
          TGraphRas = class
          private
          FRahmen: TRahmen;
          function GetRahmen: TRahmen;
          procedure SetRahmen(Value: TRahmen);
          protected
          procedure RahmenChanged(Sender: TObject);
          public
          published
          property Rahmen: TRahmen read GetRahmen write SetRahmen;
          end;<br>

          function TGraphRes.GetRahmen: TRahmen;
          begin
          if FRahmen = nil then
          begin
          FRahmen := TRahmen.Create;
          FRahmen.OnChange := RahmenChanged;
          end;
          Result := FRahmen;
          end;<br>

          procedure TGraphRes.SetRahmen(Value: TRahmen);
          begin
          Rahmen.Assign(Value);
          end;<br>

          procedure TGraphRes.RahmenChanged(Sender: TObject);
          begin
          Invalidate;
          end;<br>

          </pre>

          Gruß Hage

          Comment


          • #6
            Hallo!
            Erst mal Danke für die Hilfe.
            Ich glaube diese Sache erreicht mein Fassungsvermögen. Ich habe nun das Untere Listing. Hab auch schon ein wenig hin und her probiert. Aber wenn ich das Unter-Property „Darstellen“ ändere geschieht nichts.
            Wenn noch ein Tipp zu kriegen ist, würde ich mich freuen, ansonsten verfalle ich wieder dahin, dass eben keine Unter-Propertys benutzt werden.
            Auf jeden Fall vielen Dank für die Hilfe.

            Gruß

            Rasmus

            <pre>
            unit Test;

            interface

            uses
            Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
            ExtCtrls;

            type
            TRahmen=class(TPersistent)
            private
            FDarstellen: Boolean;
            FFarbe:TColor;
            FOnChange:TNotifyEvent;
            procedure SetDarstellen(Value:Boolean);
            protected
            procedure Changed; dynamic;
            published
            property Darstellen:Boolean read FDarstellen write SetDarstellen;
            property Farbe:TColor read FFarbe write FFarbe;
            property OnChange:TNotifyEvent read FOnChange write FOnChange;
            end;

            TTest = class(TImage)
            private
            { Private declarations }
            FRahmen:TRahmen;
            FTest:Integer;
            procedure Set_Test(value:integer);
            function GetRahmen:TRahmen;
            procedure SetRahmen(value:TRahmen);
            protected
            { Protected declarations }
            procedure RahmenChanged(Sender:TObject);
            public
            { Public declarations }
            constructor create(AOwner:TComponent);override;
            destructor destroy; override;
            published
            { Published declarations }
            procedure Graph_Zeichnen;
            property Rahmen:TRahmen read GetRahmen write SetRahmen;
            property Test:Integer read FTest write Set_Test default 0;
            end;

            procedure Register;

            implementation

            procedure Register;
            begin
            RegisterComponents('Rasmus', [TTest]);
            end;

            constructor TTest.create (AOwner:TComponent);
            begin
            inherited create(AOwner);
            FRahmen:=TRahmen.Create ;
            FRahmen.Darstellen :=false;
            FRahmen.Farbe :=clBlack;
            Graph_Zeichnen;
            end;

            destructor TTest.destroy ;
            begin
            inherited destroy;
            end;

            procedure TTest.Graph_Zeichnen ;
            begin
            // Rahmen zeichnen.
            if FRahmen.Darstellen then
            begin
            With Canvas.Pen do
            begin
            Canvas.Pen.Style :=psSolid;
            Canvas.Pen.Mode :=pmCopy;
            Canvas.Pen.Width :=1;
            Canvas.Pen.Color :=FRahmen.Farbe ;
            Canvas.Rectangle (2,2,30,30);
            end; //With Canvas.Pen do
            end; //if FRahmen.Darstellen then
            end;

            procedure TTest.Set_Test (value:integer);
            begin
            FTest:=value;
            Graph_Zeichnen;
            end;

            procedure TTest.SetRahmen(value:TRahmen);
            begin
            Rahmen.Assign (value);
            end;

            function TTest.GetRahmen :TRahmen;
            begin
            if FRahmen=nil then
            begin
            FRahmen:=TRahmen.Create ;
            FRahmen.OnChange :=RahmenChanged;
            end;
            result:=FRahmen;
            end;

            procedure TTest.RahmenChanged (Sender:TObject);
            begin
            Invalidate;
            end;

            procedure TRahmen.SetDarstellen (value:Boolean);
            begin
            if value <> FDarstellen then
            begin
            FDarstellen:=value;
            Changed;
            end;
            end;

            procedure TRahmen.Changed ;
            begin
            if Assigned(FOnChange) then FOnChange(self);
            end;
            end.
            </pre&gt

            Comment


            • #7
              Hi

              Also nochmal:

              <pre>

              type
              TRahmen = class(TPersistent)
              private
              FWidth: Integer;
              FColor: TColor;
              FOnChange: TNotifyEvent;
              procedure SetWidth(Value: Integer);
              procedure SetColor(Value: TColor);
              protected
              procedure Changed; dynamic;
              public
              procedure Assign(Source: TPersistent); override;
              property OnChange: TNotifyEvent read FOnChange write FOnChange;
              published
              property Width: Integer read FWidth write SetWidth;
              property Color: TColor read FColor write SetColor;
              end;<br>

              TTest = class(TControl);
              private
              FRahmen: TRahmen;
              procedure SetRahmen(Value: TRahmen);
              protected
              procedure RahmenChanged(Sender: TObject);
              public
              constructor Create(AOwner: TComponent); override;
              destructor Destroy; override;
              procedure Paint; override;
              published
              property Rahmen: TRahmen read FRahmen write SetRahmen;
              end;<br>

              procedure TRahmen.SetWidth(Value: Integer);
              begin
              if Value <> FWidth then
              begin
              FWidth := Value;
              Changed;
              end;
              end;<br>

              procedure TRahmen.SetColor(Value: TColor);
              begin
              if Value <> FColor then
              begin
              FColor := Value;
              Changed;
              end;
              end;<br>

              procedure TRahmen.Changed;
              begin
              if Assigned(FOnChange) then FOnChange(Self);
              end;<br>

              procedure TRahmen.Assign(Source: TPersistent);
              begin
              if Source is TRahmen then
              begin
              FWidth := TRahmen(Source).FWidth;
              FColor := TRahmen(Source).FColor;
              Changed;
              end else inherited Assign(Source);
              end;<br>

              procedure TTest.SetRahmen(Value: TRahmen);
              begin
              FRahmen.Assign(Value);
              end;<br>

              procedure TTest.RahmenChanged(Sender: TObject);
              begin
              Invalidate;
              end;<br>

              constructor TTest.Create(AOwner: TComponent);
              begin
              inherited Create(AOwner);
              FRahmen := TRahmen.Create;
              FRahmen.OnChange := RahmenChanged;
              end;<br>

              destructor TTest.Destroy;
              begin
              FRahmen.Free;
              FRahmen := nil;
              inherited Destroy;
              end;<br>

              procedure TTest.Paint;
              begin
              Canvas.Pen.Width := FRahmen.Width;
              Canvas.Pen.Color := FRahmen.Color;
              Canvas.Rectangle(0, 0, Width, Height);
              end;<br>

              </pre>

              Gruß Hage

              Comment


              • #8
                Hallo!
                Vielen Dank.
                Aber es klappt immer noch nicht.
                Vielleicht liegt es daran, daß ich noch D3 benutze (Sorry).
                Nach Eingabe des Listings wurde mir gemeldet, dass die Methode "Paint" nich vorhanden ist. Nach Ändern von TControl auf TImage ging es dann.
                Wenn ich nun die neue Komponente auf das Formular lege und das Property "Width" ändere passiert nichts. Wenn ich die Komponente mit der Maus in der Grösse ändere und die Breite größer als 299 oder die Höhe größer als 153 wird, sieht es aus, als ob die Komponente immer wieder neu gezeichnet wird (System reagiert sehr langsam).

                Gruß
                rasmu

                Comment


                • #9
                  Hi

                  Obiger Code demonstriert die Sub-Properties, nicht wie und in welches Control Du zeichnest. Du solltest KEIN TImage nehmen, eher TGraphicControl, TCustomPanel etc.

                  Die "Sub-Properties" funktionieren unter D3 genauso.

                  So ich werde mich nochmal hinsetzen und den Code selber testen, habe ihn nur on the fly eingetippt.

                  Gruß Hage

                  Comment


                  • #10
                    Hi

                    Also, TTest = class(TGraphicControl) und ALLES klappt wie gewünscht. Während der designzeit Test1.Rahmen.Width := 10 und .Color <> clBlack.

                    Vielleicht im constructor noch Width := 20; Height := 20;

                    Gruß Hage

                    Comment


                    • #11
                      Hallo Hagen!
                      Vielen, vielen Dank. Es Klappt. Ich muss mich verneigen vor Deinem wissen und vor allen Dingen vor Deiner Zähigkeit an dieser Sache dran zu bleiben, bis ich es endlich geschafft habe. Werde mir nun mal das Listing zu Gemüte führen, damit ich auch verstehe, was da abläuft.
                      Also noch mal vielen Dank.
                      Bis dann

                      rasmu

                      Comment


                      • #12
                        Hi

                        Die Sache ist einfach:
                        <li>ein Object abgeleitet von TPersistent, so wie TGraphic, TBitmap
                        <li>alle wesentlichen Properties werden mit Set Methoden implementiert
                        <li>diese rufen eine gemeinsame Benachrichtigungs Methode "Changed" auf
                        <li>in .Changed wird ein Event OnChange ausgelösst
                        <li>der Besitzer des Objectes, TTest, muss dieses Event belegen und sich selber, bei eintreffen des OnChange, neuzeichnen

                        Alle Objecte wie TBitmap/ TIcon/ TGraphic/ TFont/ TPen/ TBrush arbeiten nach dieser Methode. Schau also auch mal in die Unit Graphics.pas rein.
                        Die Ableitung von TPersistent ist sinnvoll, weil alle TPersistent Objecte:
                        <li>1. die Basis der Design Zeit Objecte sein sollte, da die Eigenschaftseditoren und die TypInfo Routinen darauf zugreifen
                        <li>2. die Methoden .Assign() und .AssignTo() eingeführt werden, und somit ein TPersistent Object einem anderen zugewiesen werden kann.

                        Desweiteren siehst Du das in TTest mit .SetRahmen() gearbeitet wird. Hier darf NICHT einfach FRahmen auf Value gesetzt werden. Die Eigenschaftseditor-Vorschriften von Borland besagen "der Erzeuger der Resourcen ist für deren Freigabe verantworlich". D.h. bei Änderung des Rahmens zur Design zeit muß entweder:
                        <li>das Rahmenobject von TTest direkt benutzt werden, oder
                        <li>eine Kopie erzeugt werden und mit TTest.Rahmen := MyRahmen zugeordnet und intern eben mit FRahmen.Assign(Value) kopiert werden.

                        Gruß Hage

                        Comment


                        • #13
                          Hallo!

                          Danke. Sehr Hilfreich die Erklärunge.
                          Bis dann

                          rasmu

                          Comment

                          Working...
                          X