Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Privat deklarierte Klasse ableiten (https://www.delphipraxis.net/194412-privat-deklarierte-klasse-ableiten.html)

Delbor 17. Nov 2017 13:36

Delphi-Version: XE8

Privat deklarierte Klasse ableiten
 
Hi zusammen
Dieser Thread ist im Grunde die Fortsetzung von hier. Für einen neuen Thread hab ich mich entschlossen, weil das Thema unabhängig vom verlinkten Thread interessant sein könnte.
Der da besprochene TPDFiumFrame deklariert ein Klasse TPDFPage in einem private-Abschnitt - es gibt, mir unverständlich, weshalb, 2 davon. TPDFiumFrame legt in einer TList-Instanz ein Handle auf eine TPDFPage-Instanz, bzw auf die da repräsentierte PDF-Seite ab, Diese Liste ist public deklariert, kann also von aussen angesprochen werden.

Tja, mein erster Ansatz war nun, in der Mainform, die mehrere Instanzen dieses TPDFiumFrames nutzt, eine neue Instanz der Klasse TPDFPage zu erstellen. Das ging aber gründlich schief, da in der von TPDFiumFrame benutzten Unit TSynPDF auch eine Klasse TPDFPage deklariert ist, die aber von TPDFDictonary abgeleitet ist.

Nun bin ich auf die Idee gekommen, im Public-Abschnitt von TPDFiumFrame eine neue Klasse TPDFDocumentPage zu erstellen und die von der privaten Klasse TPDFiumFrame.TPDFPage abzuleiten. Dabei soll TPDFDocumentPage keine neuen Member einführen.

Die Deklaration wäre auf dies Weise sehr einfach:
Delphi-Quellcode:
type
TPDFDocumentPage  = class(TPDFiumFrame.TPDFPage)
  private
  public
end;
TPDFiumFrame.TPDFPage zu schreiben, ist mir jetzt gerade eingefallen - sollte im TPDFiumFrame SynPDF im Uses-Teil aufgeführt sein, könnte es Konflikte geben oder sogtar von einer völlig falschen Klasse abgeleitet werden.

Tja, und jetzt kommt mein eigentliches Problem: Irgendwo hab ich mal mitgekriegt, dass in einer abgeleiteten Komponente/Klasse Member ohne explizite Typangabe aufgeführt werden können, weiss aber nicht mehr, woher ich das habe. Hier, bei Delphi-Treff und in der EntwicklerEcke habe ich dazu nichts gefunden. Auch meine klugen Bücher schweigen sich darüber aus.
Daher wollte ich bei Embarcadero nachsehen, aber wies ausschaut, haben die ihren Server geade heute ins Nirwana geschickt.

Weiss jemand mehr?

Gruss
Delbor

TiGü 17. Nov 2017 14:39

AW: Privat deklarierte Klasse ableiten
 
Zitat:

Zitat von Delbor (Beitrag 1386495)
...dass in einer abgeleiteten Komponente/Klasse Member ohne explizite Typangabe aufgeführt werden können...

Darunter kann ich mir nichts vorstellen?!
Was willst du machen?

Delbor 17. Nov 2017 14:57

AW: Privat deklarierte Klasse ableiten
 
Hi TiGü

Na, zum Bleistift statt:

Delphi-Quellcode:
FPoint : TPoint;


nur:

Delphi-Quellcode:
FPoint;


Ich glaube mich zu erinnern, dass dies bei Erhöhen derSichtbarkeit der Fall ist. Aber sicher bin ich mir eben nicht. Und Embarcareo scheint sich immer noch im Nirwana aufzuhalten..

Gruss
Delbor

TBx 17. Nov 2017 15:15

AW: Privat deklarierte Klasse ableiten
 
Das geht nur bei Properties.
Hast Du diese in einer Klasse protected deklariert:
Delphi-Quellcode:
TFoo = class
private
  fInfo: string;
protected
  property info read finfo write finfo;
end;
Willst du nun in der abgeleiteten Klasse Bar info published machen, ist das so möglich:
Delphi-Quellcode:
TBar = class(Too)
published
  property info;
end;
Die Sichtbarkeit von private deklarierten Properties kannst Du aber nicht erhöhen.

Delbor 17. Nov 2017 15:57

AW: Privat deklarierte Klasse ableiten
 
Hi TBx

Vielen Dank!

Gruss
Delbor

Rollo62 18. Nov 2017 07:00

AW: Privat deklarierte Klasse ableiten
 
Das geht dann vieleicht in den Bereich "nasty hack" :-)

Würde ich nur ein extremen Ausnahmefällen machen und gut Unit-Testen und dokumentieren.

Rollo

Delbor 18. Nov 2017 10:21

AW: Privat deklarierte Klasse ableiten
 
Hi Rollo

Da mein Englisch sehr schlecht ist, hab ich mir die Beiträge unter deinem Link mal von Google übersetzen lassen. Inzwischen kommen mit dem Ding ja tatsächlich verständliche und nachvollziehbare Übersetzungen zustande.

Wenn ich das jetzt richtig verstanden habe, besteht das Problem darin:
Sollte sich die Deklarationsstruktur des TPDFiumFrame bei einem Update des Frames ändern und auch nur ein privates Feld dazukommen, verschiebt das die ganzen nachfolgenden Deklarationen nicht nur im Quelltext-Editor nach unten, sondern sie erhalten auch eine neue Speicheradresse.

Ich seh hier allerdings in diesem Fall kein Problem. Denn wenn es mal ein Update des TPDFiumFrames geben sollte und ich dieses einbauen will, muss ich auch meine Klasse neu einfügen und neu compilieren, wodurch sich das Problem 'voon selbst' erledigen sollte.

Meine Deklaration (wobei ich gerade sehe, dass sie Falsch ist - ich beabsichtige nicht, irgendwas zu veränder oder irgendwelche Methoden zu überschreiben. Ich benötige lediglich in meiner Mainform eine Klassenvariable, die mit TPDFiumFrame.TPDFPage kompatibel ist :
Delphi-Quellcode:
  public
    { Déclarations publiques }
    type
      TPDFCustomDocumentPage = class(TPDFPage)
//        Index   : Integer;
//        Handle  : HPDFPage;
//        Top     : Double;
//        Rect    : TRect;
//        Text    : HPDFTextPage;
//        NoText  : Boolean;
//        Visible : Integer;
//        SelStart : Integer;
//        SelStop : Integer;
//        Selection: TArray<TRectD>;
//        destructor Destroy; override;
//        function HasText: Boolean;
//        function CharIndex(x, y, distance: Integer): Integer;
//        function CharCount: Integer;
//        function Select(Start: Integer): Boolean;
//        function SelectTo(Stop: Integer): Boolean;
//        function ClearSelection: Boolean;
//        procedure DrawSelection(DC, BMP: HDC; const Blend: TBlendFunction; const Client: TRect);    
      end;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

Den ganzen hier auskommentierten Teil kann ich weglassen. War wohl schon etwas spät gestern abend...

Gruss
Delbor

TBx 18. Nov 2017 11:01

AW: Privat deklarierte Klasse ableiten
 
Irgendwie komme ich noch nicht so ganz dahinter, was Du eigentlich vorhast.
Willst Du eine private Typdeklaration ableiten, also sowas:
Delphi-Quellcode:
TFoo = class
private
  type
   TMaker = class
     procedure bulb;
  end;
end;
Dann wird sowas nicht funktionieren:
Delphi-Quellcode:
TBar = class(Too)
public
  type
   TMyMaker = class(TMaker)
  end;
end;
Hast Du hingegen sowas:
Delphi-Quellcode:
TFoo = class
private
  TopSecret: Object;
end;
kannst Du Dir über einen class Helper helfen:
Delphi-Quellcode:
TFooHelper = class helper for TFoo
  function getTopSecret: TObject;
end;

function TFooHelper.getTopSecret: TObject;
begin
  Result := self.TopSecret;
end;

Delbor 18. Nov 2017 13:06

AW: Privat deklarierte Klasse ableiten
 
Hi TBx

So auf den ersten Blick fürchte ich, dass das, was ich vorhabe, deinem ersten Beispiel entspricht, zumal unter dem Nastly-Link auch ein Classhelper eingesetzt wird. Daher mal die Deklaration des PDFiumFrames:
Delphi-Quellcode:
 TPDFiumFrame = class(TFrame)
  private
    { Déclarations privées }
    type
      // One point is 1/72 inch (around 0.3528 mm).
      TPointsSize = record
        cx : Double;
        cy : Double;
      end;

      TRectD = record
        Left  : Double;
        Top   : Double;
        Right : Double;
        Bottom : Double;
      end;

      TPDFPage = class
        Index   : Integer;
        Handle  : HPDFPage;
        Top     : Double;
        Rect    : TRect;
        Text    : HPDFTextPage;
        NoText  : Boolean;
        Visible : Integer;
        SelStart : Integer;
        SelStop : Integer;
        Selection: TArray<TRectD>;
        destructor Destroy; override;
        function HasText: Boolean;
        function CharIndex(x, y, distance: Integer): Integer;
        function CharCount: Integer;
        function Select(Start: Integer): Boolean;
        function SelectTo(Stop: Integer): Boolean;
        function ClearSelection: Boolean;
        procedure DrawSelection(DC, BMP: HDC; const Blend: TBlendFunction; const Client: TRect);
      end;

  private
    FDocument : HPDFDocument;
    ......
Und der durch mich erweiterte Teil:
Delphi-Quellcode:
  public
    { Déclarations publiques }
    type
      TPDFCustomDocumentPage = class(TPDFPage) // Die fragliche Klasse.
        private
        public
      end;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Invalidate; override;
    procedure LoadFromMemory(APointer: Pointer; ASize: Integer);
    procedure LoadFromStream(AStream: TStream);
    procedure LoadFromFile(const AFileName: string);
    procedure ClearSelection;
    function PageLevelZoom: Single;
    function PageWidthZoom: Single;
    property Document: HPDFDocument read FDocument;
    property PageIndex: Integer read FPageIndex;
    property PageCount: Integer read FPageCount;
    property Zoom: Single read FZoom write SetZoom;
    property ZoomMode: TZoomMode read FZoomMode write SetZoomMode;

    // Erweitert durch mich
    Property PDFPageList: TList read FPages; // Dieses Property erlaubt mir von aussen (Mainform) den Zugriff auf die Items(PDF-Seiten und deren Abmessungen)
  end;

Und die Mainform deklariert dann eine kompatible Klassenvariable, zum Beispiel nur Lokal, um auf die von PDFium.PDFPageList zurückgegeben PDFSeite, bzw deren Handle, zugreifen zu können:
Delphi-Quellcode:
procedure TSynpdfMain.PDFiumFrame1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  var SP, FP :TPoint; XF : Integer; PdfPage : TPDFiumFrame.TPDFCustomDocumentPage;
begin
  PdfPage := TPdfPage.Create(Owner);

Mit einem Classhelper würde dies wohl so ausehen:

Delphi-Quellcode:
  public
    { Déclarations publiques }
    type
      TPDFPageHelper = class(TPDFPage)
        private
        public
        function GetPage(Index: Integer) : TPDFPage;
        Property PDFPageList: TList read FPages;
      end;    
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
...
    property Zoom: Single read FZoom write SetZoom;
    property ZoomMode: TZoomMode read FZoomMode write SetZoomMode;
  end;
Wobei dieser Code immer noch im Frame steht. Ausserhalb, also in der Mainform, brauche ich einen kompatiblen Datentyp. Im Falle der Funktion müsste dies eine Klassenvariable (oder eine Instanz?) vom Typ TPDFPage sein. Das ist aber nicht möglich, da in der Unit SynPDF eine Klasse TPDFPage deklariert ist, die aber von TPDFDictionary abgeleitet und somit ganz anders aufgebaut ist.

Gruss
Delbor

TBx 18. Nov 2017 13:37

AW: Privat deklarierte Klasse ableiten
 
Da dir ja offensichtlich der Quelltext vorliegt, warum passt Du die Klasse nicht Deinen Bedürfnissen an?
Die Typdeklaration public machen und eine public Property auf die entsprechende private Variable weisen lassen.

Dann hast du alles, was du für den Zugriff von außen brauchst.
Solche Änderungen kann man über eine Versionsverwaltung gut nachvollziehbar halten. Arbeitest Du mit GIT mit einem geschickten Branching, kannst Du Deine Änderungen in eine neuere Version der Ursprungsquellen über ein Rebase recht einfach wieder einarbeiten.

Delbor 20. Nov 2017 11:36

AW: Privat deklarierte Klasse ableiten
 
Hi TBx

Sorry, dass ich erst jetzt antworte.. Ich hab mich übers Wochende noch etwas durchs Beispielprogramm gewühlt - dasDing hat in zehn Units doch gute 100 000 Zeilen Quelltext. Wieviele Kommentarzeilen davon allerdings noch abgezogen werden müssen, ist mir nicht bekannt, aber es könnte gut und gerne etwa halb soviel sein.

Nun hab ich das mit der public-Klasse mal versucht. Es schlägt fehl, weil da das Wort Class gar nicht bekannt ist - weswegen, entzieht sich meiner Kenntnis.

Laut dem Embarcadoro-Wiki sollte folgende Deklaraion möglich sein:
Delphi-Quellcode:
  TPDFiumFrame = class(TFrame)

      TPDFPage = class
        Index   : Integer;
        Handle  : HPDFPage;
        Top     : Double;
        Rect    : TRect;
        Text    : HPDFTextPage;
        NoText  : Boolean;
        Visible : Integer;
        SelStart : Integer;
        SelStop : Integer;
        Selection: TArray<TRectD>;
        destructor Destroy; override;
        function HasText: Boolean;
        function CharIndex(x, y, distance: Integer): Integer;
        function CharCount: Integer;
        function Select(Start: Integer): Boolean;
        function SelectTo(Stop: Integer): Boolean;
        function ClearSelection: Boolean;
        procedure DrawSelection(DC, BMP: HDC; const Blend: TBlendFunction; const Client: TRect);
      end;
 
  private
    { Déclarations privées }
Aber auch hier wird mir das Wort class als unbekannt markiert.

Gruss
Delbor

TBx 20. Nov 2017 11:46

AW: Privat deklarierte Klasse ableiten
 
Da fehlt das kleine Wörtchen type :-)
Delphi-Quellcode:
  TPDFiumFrame = class(TFrame)

  type // woher soll Delphi sonst wissen, dass Du da eine neue Klasse deklarieren willst?
    TPDFPage = class
        Index   : Integer;
        Handle  : HPDFPage;
        Top     : Double;
        Rect    : TRect;
        Text    : HPDFTextPage;
        NoText  : Boolean;
        Visible : Integer;
        SelStart : Integer;
        SelStop : Integer;
        Selection: TArray<TRectD>;
        destructor Destroy; override;
        function HasText: Boolean;
        function CharIndex(x, y, distance: Integer): Integer;
        function CharCount: Integer;
        function Select(Start: Integer): Boolean;
        function SelectTo(Stop: Integer): Boolean;
        function ClearSelection: Boolean;
        procedure DrawSelection(DC, BMP: HDC; const Blend: TBlendFunction; const Client: TRect);
      end;
 
  private
    { Déclarations privées }

Delbor 20. Nov 2017 13:49

AW: Privat deklarierte Klasse ableiten
 
Hi TBX

Bitte, bitte: wo ist das nächste Mausloch,, damit ich mich verkriechen kann??:oops:

Brr... Sowas dämliches....:shock:

Gruss
Delbor

Delbor 20. Nov 2017 17:17

AW: Privat deklarierte Klasse ableiten
 
Hi TBx

Warum in die Ferne schweifen, denn siehe, das Gute ist doch so nah!

So, oder so ähnlich lautet ein bekannnter Satz aus der klassischen Literatur. Für mich und mein Delphi bedeutet das:
  • TPDFPage als TPDFDocumentPage im public-Abschnitt deklariert:
  • Forward-Deklaration von TPDFDocumentPage einführen, da einige Felder des Frames vom Typ dieser Seite sind
  • Einige Methoden des Frames waren plötzlich unauffindbar für den Compiler
  • Meine erste Reaktion: jetzt muss ich das ganze vermaledeite Beispielprogramm umschreiben, d.h. alle unauffindbaren Methoden löschen und neu anlegen(1)

Nuja - die Seite heisst TPDFPage und nicht etwa FTPDFPage - da hätte ich die einfache Lösung vielleicht früher gefunden, die da heisst:
Property anlegen (nachfolgend alle bisherigen durch mich angelegten Propertys):

Delphi-Quellcode:
    property PDFPageList: TList read FPages;
    property TotalSize: TPointsSize read FTotalSize;
    property PDFSeite: TPDFPage read FCurPage;
Und in meiner Mainform heisst es dann bei PDFiumFrame1.MouseUp:

Delphi-Quellcode:
 
  Memo1.Lines.Add('PDFiumFrame1.TotalSize.cx := ' + FloatToStr(PDFiumFrame1.TotalSize.cx));
  Memo1.Lines.Add('PDFiumFrame1.TotalSize.cy := ' + FloatToStr(PDFiumFrame1.TotalSize.cy));
  Memo1.Lines.Add('PDFiumFrame1.PDFSeite.Index := ' + intToStr(PDFiumFrame1.PDFSeite.Index));
Das gibt mir dies aus:
Zitat:

PDFiumFrame1.TotalSize.cx := 612
PDFiumFrame1.TotalSize.cy := 5544
PDFiumFrame1.PDFSeite.Index := 0
Dabei ändert sich nur die Indexangabe - sie gibt exakt den Index der Seite an, die ich angeklickt habe. Totalsize ändert sich nicht und ist also der Size-Wert der PDF im Speicher...

(1) Ob wohl ein neu erzeugen des Projektes gereicht hätte?

Gruss
Delbor


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:42 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-2025 by Thomas Breitkreuz