![]() |
Eigene Druckvorschau mit TMetafile und TImage
Hallo zusammen,
ich bin gerade dabei eine eigene Druckvorschau zu erstellen (ich weiß, dafür gibts fertige Komponenten, die möchte ich aber nach Möglichkeit nicht nutzen). Ich gehe dabei für jede einzelne Druckseite folgendermaßen vor: -TMetafile erstellen -auf TMetafileCanvas schreiben / Zeichnen, was auch immer wenn Seitenende erreicht: -unsichtbares TImage für die spätere Anzeige auf einem Panel erzeugen -Inhalt des MetaFiles per StretchDraw in Image kopieren -TMetafile wieder freigeben -für neue Seite neues TMetaFile erstellen usw. Das funktioniert soweit wunderbar, ich hab testweise 200 Druckseiten erzeugt (reiner Text), durch die ich dann ohne sichtbare Zeitverzögerung blättern konnte, indem ich einfach die betreffenden TImages sichtbar gemacht habe. Was nicht funktioniert ist ein nachträglices Zoomen. Die ursprünglichen Metafiles, die man beliebig Zoomen könnte, hab ich nicht mehr. Wenn man die Images zoomt, wirds natürlich pixelig. Deshalb meine Frage: Kann man die MetaFiles jeder einzelnen Seite irgendwie im Arbeitsspeicher halten, so dass ich jede einzelne TImage nach dem zoomen mit dem neuen Zoomfaktor neu schreiben kann? Meine Idee war, beliebig viele Metafiles zur Laufzeit zu erzeugen (für jede Druckseite eines). Leider gibt es jedoch keine Eigenschaft TMetafile.Name, so dass ich daran bisher gescheitert bin. Was könnte ich noch machen? Könnte man eine Art "MetaFileListe" (TList ???) erstellen, der ich nach dem Erzeugen einer Seite die Daten des MetaFiles hinzufügen kann, so dass man beim Zoomen auf die Einträge in der MetafileListe zugreifen kann? |
AW: Eigene Druckvorschau mit TMetafile und TImage
Hallo,
solltes du Zugriff auf die Quickreport Quellen haben, kannst du dir da sicher was abschauen. Da gibt es z.B. in der Unit QRPrntr die TQRPageList und dazu passend Units zum Anzeigen und Drucken. Gruß Bernd |
AW: Eigene Druckvorschau mit TMetafile und TImage
Oder vielleicht auch mal hier schauen:
![]() |
AW: Eigene Druckvorschau mit TMetafile und TImage
Mit Sydney hast du doch Generics. Warum nicht eine
TObjectList<TMetaFile>? Die kann dann auch die Referenz freigeben, da OwnsObject Semantik eingebaut ist. |
AW: Eigene Druckvorschau mit TMetafile und TImage
Der Ansatz von TurboMagic ist glaub ich das, was ich möchte, allein: es funktioniert leider noch nicht :evil:
Ich habe bisher folgendes:
Delphi-Quellcode:
Wie schon im Quelltext angemerkt, funktioniert das Ganze, wenn ich jede einzelne Druckseite als Datei auf Festplatte abspeichere und für die Anzeige wieder einlese. Das will ich natürlich nicht.
var
fmVorschau: TfmVorschau; AnzPages, AktPage : integer; PrevMeta : TMetaFile; PrevMetaCanvas : TMetaFileCanvas; MFList : TObjectList<TMetaFile>; procedure TfmVorschau.FormCreate(Sender: TObject); var I : integer; begin AnzPages := 1; AktPage := 1; MFList := TObjectList<TMetafile>.Create; end; procedure TfmVorschau.CreateMetaFile; begin PrevMeta := TMetafile.Create; PrevMeta.Enhanced := true; PrevMeta.SetSize(PWidth,PHeight); //Größe des Metafiles, je nach Papierformat PrevMetaCanvas := TMetafileCanvas.Create(PrevMeta,0); //Canvas erzeugen PrintUtils.AktCanvas := PrevMetaCanvas; //aktuellen Canvas für Unit PrintUtils festlegen, diese enthält die Basisdruckroutinen SetMapMode(AktCanvas.Handle,MM_TEXT); SetTextAlign(AktCanvas.Handle,TA_BaseLine); end; ... procedure TfmVorschau.NewPage; begin //Freigabe des MetafileCanvas der VORHERIGEN Druckseite PrevMetaCanvas.Free; //PrevMeta.SaveToFile('D:\Test_Firebird_Server\' + IntToStr(AnzPages) + '.emf'); //diese Variante funktioniert //Metafile der VORHERIGEN Druckseite in Objektliste ablegen und freigeben MFList.Add(PrevMeta); PrevMeta.Free; //neue Seite erzeugen Inc(AnzPages); CreateMetafile; //neues Metafile für nächste Seite erzeugen end; //Abschlussprozedur nach dem Erzeugen der letzten Druckseite procedure TfmVorschau.FinishPreview; begin PrevMetaCanvas.Free; //PrevMeta.SaveToFile('D:\Test_Firebird_Server\' + IntToStr(AnzPages) + '.emf'); //siehe oben MFList.Add(PrevMeta); PrevMeta.Free; end; ... //die Anzeigeprozedur produziert nur leere Seiten //die Liste weist genau so viele Einträge auf, wie Seiten vorher gedruckt und in der Liste abgelegt wurden procedure TfmVorschau.ShowAktPage; var CurrMetaFile : TMetafile; begin CurrMetaFile := TMetafile.Create; //CurrMetaFile.LoadFromFile('D:\Test_Firebird_Server\' + IntToStr(AktPage) + '.emf'); //Anzeige funktioniert auf diese Art und Weise //Eintrag der gewünschten Seite auf Metafile-Liste holen --> ist das richtig so ??? CurrMetafile := MFList.Items[AktPage-1]; //Seitengröße entsprechend der gewählten Zoomstufe einstellen CurrMetaFile.SetSize(PageP1.Width,PageP1.Height); //mit dem Vorschauimage verbinden PrevIMG.Picture.Assign(CurrMetaFile); //Freigabe CurrMetafile.Free; Label1.Caption := 'Seite ' + IntToStr(AktPage); end; Hab ich einen Fehler in der Prozedur des Ablegens der Metafiles in der Objektliste oder in der Prozedur für das Auslesen aus dieser? |
AW: Eigene Druckvorschau mit TMetafile und TImage
In CreateMetaFile vermisse ich das Hinzufügen der angelegten Instanz zur Liste.
|
AW: Eigene Druckvorschau mit TMetafile und TImage
Moin...:P
Delphi-Quellcode:
Unklarheiten:procedure TfmVorschau.CreateMetaFile; begin PrevMeta := TMetafile.Create; PrevMeta.Enhanced := true; PrevMeta.SetSize(PWidth,PHeight); //Größe des Metafiles, je nach Papierformat PrevMetaCanvas := TMetafileCanvas.Create(PrevMeta,0); //Canvas erzeugen PrintUtils.AktCanvas := PrevMetaCanvas; //aktuellen Canvas für Unit PrintUtils festlegen, diese enthält die Basisdruckroutinen SetMapMode(AktCanvas.Handle,MM_TEXT); SetTextAlign(AktCanvas.Handle,TA_BaseLine); end; ... procedure TfmVorschau.NewPage; begin //Freigabe des MetafileCanvas der VORHERIGEN Druckseite PrevMetaCanvas.Free; //PrevMeta.SaveToFile('D:\Test_Firebird_Server\' + IntToStr(AnzPages) + '.emf'); //diese Variante funktioniert //Metafile der VORHERIGEN Druckseite in Objektliste ablegen und freigeben MFList.Add(PrevMeta); PrevMeta.Free; //neue Seite erzeugen Inc(AnzPages); CreateMetafile; //neues Metafile für nächste Seite erzeugen end; //Abschlussprozedur nach dem Erzeugen der letzten Druckseite procedure TfmVorschau.FinishPreview; begin PrevMetaCanvas.Free; //PrevMeta.SaveToFile('D:\Test_Firebird_Server\' + IntToStr(AnzPages) + '.emf'); //siehe oben MFList.Add(PrevMeta); PrevMeta.Free; end; Ich verstehe das so...Jede Seite besteht aus einem PrevMeta und immer einem PrevMetaCanvas? 1. Der MetaCanvas ist imho ein Teil des PrevMeta. Warum ist PrevMetaCanvas dann keine Property von PrevMeta? Das macht die Freigabe einfacher...:zwinker: 2. Warum nicht alle Druckseiten erzeugen und in die Liste legen? Und dann die Liste durchiterieren und drucken bzw. anzeigen? 3.
Delphi-Quellcode:
Warum erst in die Liste aufnehmen und gleich wieder freigeben? :gruebel: Erst am Ende die Liste komplett freigeben!
procedure TfmVorschau.FinishPreview;
begin PrevMetaCanvas.Free; // Freigabe des Canvas MFList.Add(PrevMeta); // MetaData in die Liste packen PrevMeta.Free; // MetaData freigeben end; 4. Bitte keine globalen Variablen. :? Vorschlag (nur das Wichtigste):
Delphi-Quellcode:
interface
// Muster TMetaFileOwn = class(TMetaFile) // oder so strict private FMetaFileCanvas: TMetaFileCanvas; public constructor Create; destructor Destroy; override; property MetaFileCanvas: TMetaFileCanvas read FMetaFileCanvas write FMetaFileCanvas end; // Muster TfmVorschau = class(TForm) strict private FAnzahlPages: Integer; FAktPage: Integer; FCurrentMetaData: TMetaData; // die aktuell gewählten Daten aus der Liste (Previous / Prior über Buttons etc.) FMFList: TObjectList<TMetaFileOwn>; public end; var fmVorschau: TfmVorschau; implementation constructor TMetaFileOwn.Create; begin inherited; FMetaFileCanvas := TMetaFileCanvas.Create(Self, 0); //Canvas erzeugen, Self = TMetaFile; end; destructor TMetaFileOwn.Destroy; override; begin FMetaFileCanvas.Free; end; procedure TfmVorschau.FormCreate(Sender: TObject); begin AktPage := 1; FMFList := TObjectList<TMetaFileOwn>.Create; end; procedure TfmVorschau.FormDestroy(Sender: TObject); begin FinishPreview; // Liste leeren nicht nötig FMFList.Free; // Liste leeren macht Free sowieso...nur als Erklärung end; procedure TfmVorschau.CreateMetaFile; begin FCurrentMetaData := TMetaFileOwn.Create; FCurrentMetaData.Enhanced := true; FCurrentMetaDataSetSize(PWidth, PHeight); //Größe des Metafiles, je nach Papierformat PrintUtils.AktCanvas := FCurrentMetaData.MetaFileCanvas; //aktuellen Canvas für Unit PrintUtils festlegen, diese enthält die Basisdruckroutinen SetMapMode(AktCanvas.Handle, MM_TEXT); SetTextAlign(AktCanvas.Handle, TA_BaseLine); FMFList.Add(FCurrentMetaData); // eine nach der Anderen in die Liste end; procedure TfmVorschau.NewPage; begin CreateMetafile; //neues Metafile für nächste Seite erzeugen FAnzahlPages := FMFList.Count; end; procedure TfmVorschau.ShowPreview; // irgendwo müssen die Seiten auch angezeigt werden begin Show(FMFList); // der Anzeigeprocedure die Liste übergeben end; procedure TfmVorschau.FinishPreview; begin FMFList.Clear; // alle Objekte freigegeben end; |
AW: Eigene Druckvorschau mit TMetafile und TImage
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:
Delphi-Quellcode:
oder gleich
MFList.OwnsObjects := true;
Delphi-Quellcode:
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:
Vielen Dank für eure Hilfe :-D
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; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:33 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