Druckvorschau - (jahaaa - mal wieder ...)

Für Fragen von Einsteigern und Programmieranfängern...
klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von klaros »

Ich habe nach sehr langer Abstinenz mal wieder mit dem Programmieren angefangen.
Bin ziemlich eingerostet und eigentlich damals auch nicht weit gekommen ... :roll:

Nun möchte ich gerne einen "Arbeitsblattgenerator" für einfache Rechenaufgaben basteln.
(Zahlenraum bis 20 beginnend bei Aufgaben zum Erfassen (Abzählen, Vergleichen) von Mengen.

Die Aufgaben sollen über Zufallsgenerator erzeugt werden.

Dazu hätte ich gerne eine Preview, damit man vor dem Ausdruck schauen kann, ob einem die generierten Aufgaben sinnvoll erscheinen.

Ich habe nun einige Tage gegoogled und im Forum gelesen bin aber noch nicht fündig geworden.
Lazreport, NicePreview, KControls, Preview (aus der Delphiarea) und PowerPDF - als alternativen Weg - habe ich mir angeschaut, aber noch nicht alles als laufendes Package oder Unit konvertieren oder direkt nutzen können.

Eigentlich würde mir die Basis im gepostet Source-Code reichen.
(Quelle: Borland Delphi 3 für Profis - ein bisschen auf Lazarus angepasst.)
Da würde ich mir zutrauen den Rest prozedural dazu zu pfuschen.


Leider ist da ein Fehler drin, den ich nicht finden kann.

Beim Start des Programmes (siehe unten), wird die Zeichenfläche zunächst grau angezeigt.
Wenn man dann das Fenster in der Breite aufzieht, flackert es und mit ein bisschen Glück sieht man dann auf weißer Fläche den Probetext und eine Testlinie ...
Ich nutze Lazarus 1.0.4 auf einem Win 8, 32Bit-System.


Vielleicht kann mir hier jemand einen Tipp geben.

(Ansonsten muss ich euch mit Fragen zu den oben erwähnte Komponenten nerven. :twisted: )

Code: Alles auswählen

 
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, PrintersDlgs, Forms, Controls, Graphics, Dialogs,
  LCLIntf, LCLType, Printers, ExtCtrls, Buttons, StdCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Shape1: TShape;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
  blatt: TCanvas;
  dc: HDC;
  druckbreite, druckhoehe: integer;
  panelx: TWinControl;
 
  wanze: integer;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure blattanpassen;
var
  prnxy,
  formxy           : single;
  dx, dy, x, y     : integer;
  blattbreite,
  blatthoehe       : integer;
  scale            : single;
  xofs,yofs        : integer;
  MMproPixelX,
  MMproPixelY      : real;
 
begin
  // Bestimmen der Blattabmessungen (in Millimeter)
  MMproPixelX := 25.4 / printer.XDPI; // GetDeviceCaps( printer.handle, LOGPIXELSX);
  MMproPixelY := 25.4 / printer.YDPI; // GetDeviceCaps( printer.handle, LOGPIXELSY);
  blattbreite := Round(printer.PaperSize.Width * MMproPixelX); // Round(GetDeviceCaps(printer.handle,PHYSICALWIDTH) * MMproPIXELX);
  blatthoehe := Round(printer.PaperSize.Height * MMproPixelY); // Round(GetDeviceCaps(printer.handle,PHYSICALHEIGHT) * MMproPIXELY);
 
  // Bestimmen des Offsets für den bedruckbaren Bereich
  xofs := Round(printer.PaperSize.PaperRect.WorkRect.Left * MMproPixelX); // Round(GetDeviceCaps(printer.handle,PHYSICALOFFSETX) * MMproPIXELX);
  yofs := Round(printer.PaperSize.PaperRect.WorkRect.Top * MMproPixelX); // Round(GetDeviceCaps(printer.handle,PHYSICALOFFSETY) * MMproPIXELY);
 
  // Bestimmung der Seitenabmessungen in Millimetern
  druckbreite := Round(printer.PageWidth * MMproPixelX); // GetDeviceCaps(printer.handle, horzsize);
  druckhoehe := Round(printer.PageHeight * MMproPixelY); // GetDeviceCaps(printer.handle, vertsize);
 
  // ?? (Scrollbar)Ränder als Vorgabe?
  y := 35;
  x := 10;
 
  // Das Höhen-/Seitenverhältnis des Formulars ermitteln
  formxy := (form1.clientWidth - x) / (Form1.clientHeight - y);
  // Das gleiche für den Drucker
  prnxy := blattbreite / blatthoehe;
 
  // Maximale Anzeigengröße abhängig von Blattbreite oder Blatthöhe
  if formxy < prnxy then
    begin {Breite dominiert}
      dx := form1.clientWidth - 20;
      dy := round(dx / prnxy);
      y := round((Form1.ClientHeight / 2 + 8) - (dy / 2));
    end else
    begin {Höhe dominiert}
      dy := form1.clientHeight - y - 10;
      dx := round(dy * prnxy);
      x := round((form1.ClientWidth / 2) - (dx / 2));
  end;
 
  // "Blatt" skalieren
  form1.shape1.setbounds(x,y,dx,dy);
  scale := dy / blatthoehe;
  panelx.setbounds(x+Round(xofs*scale),y+Round(yofs*scale),
                   Round(druckbreite*scale),Round(druckhoehe*scale));
 
  // Skalierfaktoren über API-Funktionen
  SetMapMode(blatt.handle, mm_anisotropic);
  SetViewPortExtEX(blatt.handle, dx, dy, nil); // Skalierung
  SetWindowExtEX(blatt.handle,druckbreite * 10,-druckhoehe * 10,nil);
  SetBKmode(blatt.handle, TRANSPARENT);
  blatt.Brush.Style := bssolid;
  blatt.Brush.Color := clwhite;
  blatt.Pen.Color := clblack;
 
  // Das "Blatt" wird weiß "gestrichen"
  blatt.fillRect(bounds(0,0,druckbreite*10,-druckhoehe*10));
 
  // Test-Ausgaben
 
end;
 
procedure ausgabe(ziel : TCanvas);
var
  breite,hoehe : integer;
begin
  with ziel do begin
    breite := druckbreite*10;
    hoehe:=druckhoehe*10;
    moveto(0,-10);LineTo(breite,-10);
    // in 1/10 Millimeter
    font.Height:=50;
    font.Name:='Arial';
    textOut(breite div 2, -(hoehe div 2),'Hallo Welt!');
  end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  panelx := TWinControl.Create(self);
  panelx.parent := Form1;
  blatt := TCanvas.Create;
  blatt.handle := GetDC(panelx.handle);
  setmapmode(blatt.handle,mm_anisotropic);
end;
 
procedure TForm1.FormResize(Sender: TObject);
begin
  blattanpassen;
  ausgabe(blatt);
end;
 
 
end.
 
 

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von theo »

Hallo

Drucken kannst du, nur mit der Vorschau hapert's? Oder wie muss man das verstehen?

Auf den Canvas wird nur im OnPaint Ereignis gezeichnet.

klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von klaros »

theo hat geschrieben: Drucken kannst du, nur mit der Vorschau hapert's? Oder wie muss man das verstehen?

Auf den Canvas wird nur im OnPaint Ereignis gezeichnet.
Das Drucken klappt tatsächlich immer - auch wenn man die (Text)ausgabe auf dem Bildschirm nicht sieht, weil blatt grau angezeigt wird.

Drucken mit:

Code: Alles auswählen

 
procedure TForm1.Button1Click(Sender: TObject);
begin
  printer.begindoc;
  SetMapMode(printer.canvas.handle,MM_LOMETRIC);
  ausgabe(printer.canvas);
  printer.enddoc;
end; 
 
Das Zeichnen auf blatt klappt ja im Prinzip auch, nur leider muss man das Fenster der (kompilierten) Anwendung in die Breite ziehen.
Bei "bestimmten" Werten für die Fensterbreite wird blatt mit Inhalt auf weißem Hintergrund gezeigt oder eben nicht (graue Fläche).
Das ist vielleicht ein Rundungsfehler, aber ich weiß nicht wie und warum ...

Grüße,
klaros

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von theo »

Hast du alle meine zwei Zeilen (nebst Hallo) gelesen?

klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von klaros »

theo hat geschrieben:Hast du alle meine zwei Zeilen (nebst Hallo) gelesen?
Mit dem "Hallo" sind es 3 Zeilen. So weit kann ich noch zählen (und lesen). :wink:

Es wird nichts mit OnPaint zu tun haben ...
Erstens habe ich ausgabe() dort mal eingesetzt; das hilft auch nicht weiter.
Zweitens wird ja auf den canvas gezeichnet! Nur nicht systematisch! Irgendetwas verhindert dies oder überschreibt die Ausgabe - je nach Breite des Fensters ...
(Wenn also OnResize ausgelöst wird, sieht man die Ausgabe unter "bestimmten" Fensterbreiten.)

Viele Grüße,
klaros

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von pluto »

Ich habe mir dein Code mal genauer angesehen. Mir ist aufgefallen: Du zeichnest nirgendwo in das Sichtbare Canvas. Immer nur nach Canvas und Canvas scheint in diesen Fall Nicht Sichtbar zu sein. Versuch doch einfach mal folgendes:
im Form1.OnPaint Event:
Canvas.Draw(0,0,blatt);

Dann müsstest du etwas sehen können.

Edit01:
Mir ist eben noch diese Zeile " blatt.handle := GetDC(panelx.handle);" aufgefallen.... kommentiere das mal aus und versuch mal mein Vorschlag um zusetzten.

Edit02: Du könntest auch statt Blatt einfach das canvas von PanelX nutzen bzw. ein Buffer einsetzten. schau dir mal das HTML Panel ein. Dort gibt es eine Druckvorschau.
MFG
Michael Springwald

klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von klaros »

pluto hat geschrieben: Dann müsstest du etwas sehen können.
Hmm ...
Ich kann das jetzt nur noch zum dritten (oder vierten?) Mal schreiben.
Ich kann ja, so wie es in den Routinen steht (mit dem handl-Gedöns), auf den Canvas schreiben!
Es ist ja kein grundsätzliches Problem, weil ich nicht OnPaint benutze.
OnResize löst ja mal ein gelungenes Schreiben und mal eben nicht aus.

Vielleicht probiert ihr das mal aus.
Man braucht ja neben obigen Quellcode nur eine automatisch generierte Standapplikation (Neu), ein TShape und (einen TButton, wenn man auch mal drucken will).
Das ganze Compilieren und dann das Programmfenster in der Breite variieren ...
(Das macht Spaß. Das ist fast wie ein Zaubertrick: Jetzt isses weg. Jetzt isses wieder da! 8)

Grüße,
Klaros

klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Druckvorschau - (jahaaa - mal wieder ...) - Schubs

Beitrag von klaros »

Ich schubse den Beitrag noch mal nach oben.

Hat niemand eine Idee, warum nicht konstant eine Ausgabe angezeigt wird?
Zur Not verschicke ich auch das komplette Projekt mal ...
(Die unter Delphi kompilierte Anwendung - auf der CD kompiliert und mit Quelltext vorhanden - läuft übrigens problemlos ...)

Ich habe in letzter Zeit versucht, Delphi-Komponenten auf Lazarus hin anzupassen, aber das ist müheselig und strandete immer wieder an Wissensbarrieren.
Gibt es denn nirgendwo eine Anpassung / eine Lazarus-Komponente die eine simple Druckvorschau ermöglicht?

Mit dem Report-Gedöns kann ich mich ((noch)) nicht anfreunden, da ich sie für meine Zwecke für zu unflexibel halte.
Zumindest verstehe ich das bis jetzt so, dass man dort Bänder mit konkreten "Feldern" - ich nenne die Platzhalter jetzt mal so - definieren muss.
Ich müsste dann für jedes Rechen-Arbeitsblatt solch einen Report konstruieren.
Da ich an viele unterschiedliche Layouts für die Arbeitsblätter denke, halte ich das für umständlich und unflexibel.

Grüße,
klaros

(Ach ja ... :twisted:
Wenn ich die ausgabe() in OnPaint lege (Ich bin jetzt wieder bei obigen Anfangsfred.), kann ich sogar das Fenster der kompilierten Anwendung kräftig mit der Maus hin- und herschleudern und irgendwann erscheint dann die Ausgabe. Kein Witz!)

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von pluto »

Hat niemand eine Idee, warum nicht konstant eine Ausgabe angezeigt wird?
Ich glaube, du hast nicht verstanden, auf was ich hinauswollte. Lese dir den Beitrag noch mal durch. Ich weiße noch mal darauf hin:
Schau dir an, wie es andere machen, z.b. das HTML Panel. Man kann viel Lernen von anderen.
Gut, die Druckvorschau im HTML Panel hat Fehler. Ob drucken geht weiß ich nicht, aber die Druckvorschau geht jedenfalls nicht. Statt zwei Seiten, werden um die 1000 Seiten angezeigt. Warum auch immer. Aber es wird was angezeigt.

Vielleicht hilft dir noch folgende Idee: Wenn du ein Problem hast und keine Lösung findest, muss du dir überlegen, wer könnte das Problem schon mal gelöst haben? Vielleicht nicht genau das Problem, aber ein ähnliches. Das hat mir in der Vergangenheit sehr oft geholfen.
Lösungen Fallen nicht vom Baum. Leider. Kann SynEdit nicht auch drucken? Da müsste es auch eine Druckvorschau geben. Da könntest du auch mal schauen, wie die es machen.

Vorschlag: Versuch das Problem in einem kleinen Test Projekt auszulagern, welches du hier problemlos anhängen kannst. Dann kann sich das einer von uns mal anschauen.
MFG
Michael Springwald

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Re: Druckvorschau - (jahaaa - mal wieder ...) - Schubs

Beitrag von theo »

klaros hat geschrieben:Ich schubse den Beitrag noch mal nach oben.

Hat niemand eine Idee, warum nicht konstant eine Ausgabe angezeigt wird?

Ich verstehe diesen Code überhaupt nicht.

Wozu ist die Shape gut?

Warum benützt du "printer" auf dem screen?

Was soll das sein:

Code: Alles auswählen

  panelx := TWinControl.Create(self);
  panelx.parent := Form1;
  blatt := TCanvas.Create;
  blatt.handle := GetDC(panelx.handle);
Warum nicht ein TCustomControl nehmen, das hat einen Canvas?

Und nochmal: OnResize painted man nicht.

Ich kann dir leider nicht helfen, weil ich das alles nicht verstehe.

Willst du das nicht nochmal in Ruhe und schrittweise neu entwickeln?

klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Re: Druckvorschau - (jahaaa - mal wieder ...) - Schubs

Beitrag von klaros »

theo hat geschrieben:
Ich verstehe diesen Code überhaupt nicht.
Das ist die erste brauchbare Aussage hier im Thread. (:wink: Nix für ungut.)
Ich verstehe es auch nicht und wollte die Routinen als Fire&Forget-Teil nutzen.
Wenn es funktionieren würde, könnte ich mit meinen Schmalsspurfähigkeiten den Rest dazu friemeln.
Der Code ist 1:1 bis auf die Anpassungen auf Lazarus / Freepascal aus einem Buch (s. o.).
Die werden da ja nicht nur Müll geschrieben haben (kompiliertes Codebeispiel von der CD läuft (s. o.).
theo hat geschrieben:
Was soll das sein?

Code: Alles auswählen

  panelx := TWinControl.Create(self);
  panelx.parent := Form1;
  blatt := TCanvas.Create;
  blatt.handle := GetDC(panelx.handle);
Warum die neue Komponente für die Druckansicht so gebaut wird, weiß ich leider nicht.
Dies und die Skalierungfunktionen führen dazu, dass man nur eine Ausgaberoutine schreiben muss und entweder blatt (das ist ja ein Canvas) oder Printer.canvas übergibt.
theo hat geschrieben:
Willst du das nicht nochmal in Ruhe und schrittweise neu entwickeln?
So wird es wohl laufen.
Mit dem Arbeitblatt-Genrator-Projekt wollte ich nach ein bisschen PHP usw. nach langer Zeit wieder "Rumprogrammieren".
Da wird wohl die Druckvorschau der erste Lerngegenstand.

Jetzt hört mir auf mit: Mach was Leichteres. 8)
Ich habe noch kein Buch gefunden, dass mir hier gefallen hat.
Nach dem Hello World kommen gerne irgendwelche Beispiele zu denen ich keinen Bezug habe und die oft ganz schnell hinsichtlich der Komplexizität abdriften.
Also kann ich direkt Tutorials, Api-Dokus und am häufigsten Tips zu nötigen Workarounds wegen Bugs oder fehlender Feature lesen ... :)

Ein Vorredner schrieb hier:
Schau wie andere es machen.
Das habe ich getan. (Woher sollte ich aber z. B. wissen, dass dieses HTML-Panel irgendetwas ähnliches (nicht funktionierendes!) wie eine Druckvorschau enthält?
Wer sind denn die anderen? Um Tipps von anderen gabe ich doch mannigfaltig gebeten ...

Bei Delphi-Tipps ist die Schwierigkeit immens groß, dass Lazarus hier aufgrund der Plattformunabhängigkeit "Lücken" hat.
Es ist ausgesprochen mühselig herauszufinden, warum es unter Lazarus so nicht geht und ob es eine Ersetzung / Alternative für die ausschließliche WIN-Plattform gibt.

Deswegen überlege ich so langsam tatsächlich, das ganze mit Lazarusbordmitteln selber anzugehen.
(Obwohl ich im Moment auch die Dokumentation für Lazarus und Freepascal noch für gewöhnungsbedürftig halte. Ich hoffe das kommt noch.)

Falls jemand - nach der Meckerei (ist nicht böse gemeint und kommt hoffentlich nicht in falsche Hälse) - noch Tipps für eine Lazarusumsetzung hat, oder sich das Beispielprojekt (s.o.) mal in Ruhe naschauen will, kann er sich gerne melden.
Dann hänge ich das Projekt demnächst mal an.

Grüße,
klaros

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von Michl »

Ich hatte mal ein ähnliches Problem. Bei mir wurde auch mal eine Objekt mal angezeigt und mal nicht. Dies hatte damals eine ganz einfache Ursache. Ich hatte damals in der falschen Form ein Ereignis zum zeichnen ausgewählt, das dann mal und mal eben nicht von einer anderen dann überschrieben wurde (war auch wie Zauberei)!

Evtl. ist das bei Dir ein ähnlich gelagertes Problem, habe mir Deinen Code allerdings im einzelnen nicht durchgesehen.

Grüße
Michl

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

creed steiger
Beiträge: 958
Registriert: Mo 11. Sep 2006, 22:56

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von creed steiger »

http://www.tkweb.eu/en/delphicomp

könntest du dir mal anschauen

klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von klaros »

creed steiger hat geschrieben:http://www.tkweb.eu/en/delphicomp

könntest du dir mal anschauen
Danke für dien Tipp. :D
Aber den kenne ich schon.
Die Beispiele fand ich (unnötig) komplex, so dass ich erst mal anderweitig gesucht hatte.
Aber manchmal macht es ja Sinn, nochmals hinzuschauen, weil sich zwischenzeitlich andere Erkenntnisse eingestellt haben ...

Hast du selber Erfahrungen mit den Komponenenten?

Grüße,
klaros
Zuletzt geändert von klaros am Sa 2. Feb 2013, 15:29, insgesamt 1-mal geändert.

klaros
Beiträge: 10
Registriert: Mi 16. Jan 2013, 20:17

Re: Druckvorschau - (jahaaa - mal wieder ...)

Beitrag von klaros »

@Michi:
Danke für den Hinweis.
Das Programm ist eigentlich so simpel (eine einzige Form), dass ich nicht glaube, dass an den falschen Ort gezeichnet wird.

Antworten