![]() |
AW: Seltsames Verhalten der Destruktoren
Hallo,
zeig mal bitte die Zeilen des Erstellens und der Freigabe der beiden Frames. Hast kein VCS, um auf den alten Stand zurückzuspringen? |
AW: Seltsames Verhalten der Destruktoren
Mal ganz platt gefrag:
Kann es sein, das einer der Aufrufe:
Delphi-Quellcode:
noch auf _Document zugreift ?
FPages.Free;
PDFPageClass.Free; FReportList.Free; |
AW: Seltsames Verhalten der Destruktoren
Hi zusammen
Sorry, wenn ich erst jetzt antworte - Hausmannspflichten haben gerufen, bzw. sich schon fast die Seele aus dem Leib geschrien...:) Die beiden Frame-Instanzen werden nicht zur Laufzeit erstellt, sondern per Klick im OI auf Frames und nach Klick auf die Mainform/eine Panelgroupseite zw ein Panel ähnlich wie eine Kompoonwnte an der gewünschten Stelle angelegt. Beide Instanzen erben also nur den Constructor-Code des Basisframes:
Delphi-Quellcode:
Wie ich auch in
constructor TPDFiumFrame.Create(AOwner: TComponent);
begin {$IFDEF TRACK_EVENTS} AllocConsole; {$ENDIF} inherited; ControlStyle := ControlStyle + [csOpaque]; FZoom := 100; FPageIndex := -1; PDFPageClass := TPDFPageClass.Create; FSelBmp := TBitmap.Create; FSelBmp.Canvas.Brush.Color := RGB(50, 142, 254); FSelBmp.SetSize(100, 50); FPages := TList.Create; FReportList := TStringlist.Create; FReportList.Sorted := False; FGetPageAt := 0; try FPDF_InitLibrary; except FStatus := TLabel.Create(Self); FStatus.Align := alClient; FStatus.Parent := Self; FStatus.Alignment := taCenter; FStatus.Layout := tlCenter; FStatus.Caption := sUnableToLoadPDFium; end; end; ![]() ![]() Nach längerer Zeit hab ichs dann geschafft, dass in PDFiumFrame1 für jede angeklickte Seite auch dren korrekter Index, bzw. die Seitennummer, angezeigt wurde:
Delphi-Quellcode:
Obiger Code entstand in den letzten Tagen; an den mit //(1) bezeichneten Stellen befindet sich Code, der mir zum einen die Seitengrössen und Indexe in PDFiumFrame1 in ein Memo ausgibt und zum andern bei (2) den Index und den Klassennamen der angeclickten Seite.
procedure TSynpdfMain.PDFiumFrame1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); var SP, FP,MousePos :TPoint; Index : Integer; Page : TPDFiumFrame.TPDFPageClass; begin Memo1.Lines.Clear; Memo1.Lines.Add('------ PDFiumFrame1MouseUp ------'); //(1) MousePos.X:= X; MousePos.Y:= y; Page := PDFiumFrame1.PageAt[MousePos]; //(2) PDFiumFrame2.PageIndex := Page.Index; // PDFiumFrame2.PDFSelPage.Index := Page.Index; PDFiumFrame2.SetChoosePage(Page.Index); end; Die Methode PDFiumFrame1.PageAt[MousePos]; ist eine vom Basisframe geerbte Funktion. Und Page schliesslich ist ein Property vom Typ TPDFPage des Basisframes. Letztere Klasse ist allerdings im Basisframe privat deklariert und somit eigentlich unsichtbar. Mit DeddyHs Hilfe hab ichs dann doch geschafft. Ein Ausschnitt aus der Deklaration des Basisframes :
Delphi-Quellcode:
Aus dem Constructor des Frames:
procedure SetPageIndex(Value : Integer);
public { Déclarations publiques } type TPDFPageClass = TPDFPage; public PDFPageClass : TPDFPageClass; constructor Create(AOwner: TComponent); override;
Delphi-Quellcode:
... und einer aus der Mainform:
FPageIndex := -1;
PDFPageClass := TPDFPageClass.Create;
Delphi-Quellcode:
Und schliesslich befindet sich die in TSynpdfMain.PDFiumFrame1MouseUp aufgerufene Methode PDFiumFrame2.SetChoosePage(Page.Index) ebenfalls im Basisframe und wird von diesem an seine Instanzen vererbt.:
procedure TSynpdfMain.PDFiumFrame1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); var MousePos :TPoint; Index : Integer; Page : TPDFiumFrame.TPDFPageClass; begin ... ... MousePos.X:= X; MousePos.Y:= y; Page := PDFiumFrame1.PageAt[MousePos];
Delphi-Quellcode:
Die aufgerufene Methode LoadVisiblePages:
procedure TPDFiumFrame.SetChoosePage(Value: Integer);
begin if Self.PageIndex <> Value then Self.PageIndex := Value; Self.LoadVisiblePages; Application.ProcessMessages; end;
Delphi-Quellcode:
Eigentlich hatte ich gehofft, dass ich mit der Übergabe des in PDFiumFrame1 ermittelten Seitenindexes an PDFiumFrame2 hier so die entsprechende Seite anzeigen lassen könnte. Das funktioniert so aber nicht.
procedure TPDFiumFrame.LoadVisiblePages;
var Index, Z, Marge: Integer; Page : TPDFPage; LSelectedPage : TRectD; Top, Scale : Double; LClient, LRect : TRect; begin FPageIndex := -1; FCurPage := nil; for Index := 0 to FPages.Count - 1 do begin Page := FPages[Index]; if Page.Selection = nil then Dec(Page.Visible); else Page.Visible := 0; end; LClient := ClientRect; Top := 0; Z := 0; Marge := PAGE_MARGIN; //const PAGE_MARGIN = 5; // pixel Scale := FZoom / 100 * Screen.PixelsPerInch / 72; for Index := 0 to FPageCount - 1 do begin // compute page position LRect.Top := Round(Top * Scale) + Marge - VertScrollBar.Position; LRect.Left := PAGE_MARGIN + Round((FTotalSize.cx - FPageSize[Index].cx) / 2 * Scale) - HorzScrollBar.Position; LRect.Width := Round(FPageSize[Index].cx * Scale); LRect.Height := Round(FPageSize[Index].cy * Scale); if LRect.Width < LClient.Width - 2 * PAGE_MARGIN then LRect.Offset((LClient.Width - LRect.Width) div 2 - LRect.Left, 0); // visibility test if LRect.IntersectsWith(LClient) then begin if FPageIndex < 0 then FPageIndex := Index; Page := GetPage(Index); Page.Rect := LRect; Page.Visible := 1; end; // don't go below LClient area if LRect.Top > LClient.Bottom then Break; // next page top position Top := Top + FPageSize[Index].cy; Inc(Marge, PAGE_MARGIN); end; // release any page that was not visibile for the last 5 paint events for Index := FPages.Count - 1 downto 0 do begin Page := FPages[Index]; if Page.Visible < -5 then begin Page.Free; FPages.Delete(Index); end; end; end; Vielmehr denke ich, dass hier die eigentliche Quelle des deerzeitigen Problems steckt. Zur Erinnerung:
Delphi-Quellcode:
Hier wird von PDFiumFrame1.PageAt eine Seite zurückgegeben. Deren Index wird in TPDFiumFrame.SetChoosePage dem Property PageIndex des Basisframes zugewiesen. Dmit verfügt der Basisframe über ein Seitenhandle mehr, als in der Liste Pages gespeichert sind. Diese Liste wird bei Programmende freigegeben - nicht aber die Seite, die sich (noch) nicht in der Liste befindet, weshalb das Dokument nicht freigegeben werden kann.
procedure TSynpdfMain.PDFiumFrame1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); var MousePos :TPoint; Index : Integer; Page : TPDFiumFrame.TPDFPageClass; begin ... ... MousePos.X:= X; MousePos.Y:= y; Page := PDFiumFrame1.PageAt[MousePos]; So zumindest meine bisherige Erklärung für das zur Zeit auftretende Problem. Der Basisframe verfügt über ein Boolean-Feld FReload. Dessen Verwendung:
Delphi-Quellcode:
Diese Art der Programmierung mit dauerndem Laden/Entladen der Seitenhandles ist für mich sehr ungewöhnlich, weshalb ich alles andere als sicher bin, die Arbeitsweise des Programms wirklich verstanden zu haben.
procedure TPDFiumFrame.PaintWindow(DC: HDC);
var Index : Integer; Page : TPDFPage; Client: TRect; WHITE : HBrush; SelDC : HDC; Blend : TBlendFunction; begin FInvalide := False; ... // check visibility if FReload or (FPages.Count = 0) then //<== begin LoadVisiblePages; PDFiumFramePaintWindowToMemo1; FReload := False; end; // page background Gruss Delbor |
AW: Seltsames Verhalten der Destruktoren
Einen Wunderschönen Guten Morgen :)
Frame1 stellt also die Thumbnails der Seiten eines Dokumentes dar (als Liste sozusagen) während Frame2 die ausgewählte Seite in einer großen Ansicht präsentiert. D.h. beide Frames arbeiten mit dem gleichen Dokument und damit mit dem gleichen Dokumentenhandel. Beim schließen des Dokumentes passiert nun folgendes: Frame2.Destructor räumt sich auf und gibt das Handel vom Dokument frei. danach Frame1.Destructor räumt sich auf und versucht das Handel des Dokumentes frei zu geben. Da Frame2 das schon gemacht hat, gibts eine AV. Sinnvoller wäre es, das Dokument in der Form zu erzeugen und wieder frei zu geben und das ganze dann an die Frames zu übergeben. |
AW: Seltsames Verhalten der Destruktoren
Hi Ghostwalker
Dir auch einen guten Morgen! Zitat:
Abhilfe schaffen 2 Möglichkeiten:
Nun hast du dem Projekt einen Basisframe hinzugefügt. Auf der Form hingegen befindet sich noch keine Frameinstanz. Nun setze im Projektverzeichnis einen Haltepunkt auf die Mainform - der soeben hinzugefügte Frame ist zwar in der uses-Liste vorhanden, nicht aber zwischen begin/end. Wenn du nun das Projekt startest, wirst du bemerken, dass vor dem Erzeugen der Mainform der Basisframe erzeugt wird. Zumindest, wenn du diesem einen construktor himzugefügt hast und mit F7 durchstepst. Bei Programmende laufen die Prozeduren in umgekehrter Reihenfolgee ab. Erst wird also die Form (mit ihren allfälligen Frameinstanzen) freigegeben und erst dann der Basisframe. Zusammen mit den Frameinstanzen werden auch deren Komponenten, Klassen und Handles freigegeben - _Document ist letzteres. Das _Document des Basisframes wird also erst mit diesem freigegeben (bzw. sollte vor dessen Zerstörung freigegeben werden. Aber da bin ich mir nicht sicher). Vererbung erfolgt immer vom Basisframe zur Frameinstanz, umgekehrt jedoch nicht (wie das in Delphi überall der Fall ist). Wenn die Frameinstanzen der Form zerstört werden, werden also auch allfällige Handles dieser Instanzen zerstört, nicht aber das im Basisframe enthaltene Handle - das verzieht sich erst mit dem Basisframe ins Nirwana. Wenn nun das Dokument 7 Seiten enthält und ich mir, wie oben ausgeführt, von der Prozedur GetPageAT eine Seite zurückgeben lasse, existieren erstmal acht Seiten. - zumindest in einer (oder auch beiden) Frameinstanzen. Dies wird in der Prozedur LoadVisiblePages bereinigt, wo alle nicht sichtbaren Seiten freigegeben werden. Anbei ein Ausschnitt aus PaintWindow:
Delphi-Quellcode:
FReload muss hier also true sein, dass LoadVisiblePages aufgerufen wird.
// check visibility
if FReload or (FPages.Count = 0) then begin LoadVisiblePages; PDFiumFramePaintWindowToMemo1; FReload := False; end; So, wie ich den Programmablauf bisher verstanden habe, wird also ohne Aufraufe von PaintWindow und LoadVisiblePages und dem setzen von FReload auf True gar nichts neu gezeichnet, und es werden auch keine nichtsichtbaren Fenster gelöscht - auch deren Handles nicht. Ich habe bislang noch nie mit Handles direkt gearbeitet, aber ich würde mich wohl schwer irren, wenn Windows ein Handle löschen (lassen) würde, das noch selbst ein gültiges Handle besitzt. Ich weiss nicht, ob ich nun alles richtig verstanden habe, aber - weitermachen zeigt, was Sache ist. Gruss Delbor PS: Zitat:
|
AW: Seltsames Verhalten der Destruktoren
Hi Ghostwalker
Zitat:
FPages ist ein TListobjekt des Basisframes, in dem die Handles der Seiten gespeichert werden. PDFPageClass ist eine Instanz der TPDFPageClass , die von der im Basisframeprivat deklarierten Klasse PDFPage abgeleitet ist und ausser eine einzige Instanz zu Erzeugen nichts tut. Im Verlaufe des Programmes deklarire ich eine Variable diese Typs (der eine meiner Änderungen ist), die nun in der Lage ist, eine Instanz des Vorfahren aufzuehmen. Ob ich da wirklich eine Instanz des Typs PDFPageClass brauche, bin ich mir im Moment jedoch nicht so klar. Gruss Delbor |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:27 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