Einzelnen Beitrag anzeigen

Benutzerbild von runningsoft
runningsoft

Registriert seit: 8. Okt 2004
Ort: Bernau
108 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Eigene Druckvorschau mit TMetafile und TImage

  Alt 5. Jan 2021, 10:15
Vielen Dank für die Hinweise und Denkanstöße. es hat mich noch mal 2 Stunden gekostet, aber jetzt funktioniert es.

@DeddyH: Ich war der Meinung, dass man erst das "gefüllte" Metafile, also nachdem die Seite geschrieben wurde, der Objektliste anhängen kann, deshalb hatte ich das nicht sofort in der CreateMetaFile - Prozedur gemacht.

Der entscheidende Hinweis war aber dann der von haentschman
Zitat:
Warum erst in die Liste aufnehmen und gleich wieder freigeben? Erst am Ende die Liste komplett freigeben!
Genau da lag mein Fehler. Man kann letztlich beliebig viele Objekte vom gleichen Typ (hier TMetafile) erzeugen und der Liste hinzufügen. Freigegeben werden Sie erst wieder mit der Freigabe der kompletten Liste. Dies passiert, wenn ich das richtig verstanden habe, automatisch, wenn die generische Objektliste Owner der Objekte ist

MFList.OwnsObjects := true; oder gleich
MFList := TObjectList<TMetafile>.Create(true);
Falls mal jemand ein ähnliches Problem hat, hier noch die entscheidenden Punkte des Quelltextes mit ein paar Kommentaren:
Delphi-Quellcode:
private
    { Private-Deklarationen }
    var AktPage, PWidth, PHeight : integer;
        FScale : real;
        MFList : TObjectList<TMetaFile>; //generische Objektliste zur Speicherung der Metafiles
        PrevListMeta : TMetaFile; //Metafile, das in die Objektliste eingefügt wird
        PrevMetaCanvas : TMetaFileCanvas; //MetaCanvas, auf dem gezeichnet wird
        ZoomManuell: Boolean;

procedure TfmVorschau.FormCreate(Sender: TObject);
var I : integer;
begin
AktPage := 1;
MFList := TObjectList<TMetafile>.Create(true);
end;

procedure TfmVorschau.FormShow(Sender: TObject);
begin
//Ausgehend von der Pixeldichte des Monitors die Größe des Panels bei 100% Darstellung berechnen
// z.B. 96ppi / 25.4 (=ppm) * 210 mm
PWidth := trunc(Screen.PixelsPerInch / 25.4 * AktFormatArr[1]);
PHeight := trunc(Screen.PixelsPerInch / 25.4 * AktFormatArr[2]);
InitPreview(AktFormatArr[1],AktFormatArr[2]);
CreateMetafile;
end;

procedure TfmVorschau.CreateMetaFile;
begin
PrevListMeta := TMetafile.Create;
PrevListMeta.Enhanced := true;
PrevListMeta.SetSize(PWidth,PHeight); //Größe des Metafiles, je nach Papierformat
MFList.Add(PrevListMeta); //uch wenn das Metafile noch leer ist, kann es schon der Liste hinzugefügt werdena

//Canvas erzeugen, auf dem gezeichnet wird
PrevMetaCanvas := TMetafileCanvas.Create(PrevListMeta,0);

//als aktuellen Canvas an unit PrintUtils geben
//für realen Druck wird in anderer Prozedur Printer.Canvas als AktCanvas festgelegt
PrintUtils.AktCanvas := PrevMetaCanvas;
SetMapMode(AktCanvas.Handle,MM_TEXT);
SetTextAlign(AktCanvas.Handle,TA_BaseLine);
end;

procedure TfmVorschau.NewPage;
begin
//MetaCanvas der vorherigen Seite freigeben
//erst nach Freigabe des MetaCanvas werden die darauf enthaltenen Daten an das
//Metafile übergeben
PrevMetaCanvas.Free;

//PrevMeta.Free; //--> das war der Fehler, weshalb die Objekte in der Objektliste leer waren
                  // die erzeugten Metafiles dürfen nicht sofort wieder freigegeben werden
                  // sondern erst mit der Freigabe der Objektliste beim dem Schließen der Form

//neues Metafile für nächste Seite erzeugen
//dort wird dann auch wieder ein neuer MetaCanvas erzeugt, auf dem gezeichnet wird
CreateMetafile;
end;

procedure TfmVorschau.LastPage;
var i: integer;
    Temp: TComponent;
begin
//siehe Kommentar NewPage
PrevMetaCanvas.Free;
end;

...

procedure TfmVorschau.ShowAktPage;
var PrevIMGMeta : TMetaFile;
begin
//Eintrag aus Objektliste in Metafile übernehmen
PrevIMGMeta := MFList.Items[AktPage-1];
//Seitengröße auf aktuelle Zoomstufe anpassen
PrevIMGMeta.SetSize(PageP1.Width,PageP1.Height);
//TImage.Picture mit Metafile verbinden
PrevIMG.Picture.Assign(PrevIMGMeta);

Label1.Caption := 'Seite ' + IntToStr(AktPage);
end;
Vielen Dank für eure Hilfe

Geändert von runningsoft ( 5. Jan 2021 um 10:21 Uhr)
  Mit Zitat antworten Zitat