Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   DBGrid, ausdrucken über mehrere Seitenbreite hinaus (https://www.delphipraxis.net/190413-dbgrid-ausdrucken-ueber-mehrere-seitenbreite-hinaus.html)

waldforest 30. Sep 2016 16:50

DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Hallo,

ich möchte mich etwas intensiver mit dem Drucken, ohne Reportgenerator beschäftigen.

Mit anliegend auf DBGRID angepasstem Code drucke ich ein DBGrid, welche in der Breite über mehrere Blätter geht, aus.

Soweit klappt alles. Mich stört allerdings, dass die Abarbeitung so lange braucht.
Dies liegt sicher einerseits daran, dass jeder Datensatz durchlaufen wird, was ich erst einmal erforderlich ist, anderseits am Erneuten durchlaufen aller Datensätze für das weiter Blatt in der Breite.

Wie könnte man den Code optimieren, z.B. dass nicht für jede neue Seite, welche über die Seitenbreite hinaus erstellt wird, alle Datensätze noch einmal durchlaufen werden müssen.

Delphi-Quellcode:
procedure GridDruckNeu(Grid:tdbgrid; links, oben: Integer; scal:double; DTitle : string; farbig:boolean);
var
  x, y, li, ob, re, un, waag, senk, a, vSpalte, bSpalte, vZeile, bZeile: integer;
  fix, grund, schrift: TColor;
  r: TRect;
  fertig:boolean;
  i,breite,waagseiten:integer;

  function rech(i,j:integer):integer;
  begin
     result:=round(((i*j) / 72) * scal);
  end;

begin
  if dlgPnt1.Execute then
  begin
    Printer.Copies := dlgPnt1.Copies;
    Printer.Orientation := poLandscape;
    vZeile := 0;
    vSpalte := 0;
    bZeile := Grid.DataSource.DataSet.RecordCount;
    bSpalte := grid.Columns.Count;
    waag := GetDeviceCaps(Printer.Handle, LogPixelSX);
    senk := GetDeviceCaps(Printer.Handle, LogPixelSY);
    SetWindowOrgEx(printer.Handle, 0, 0, nil);

    breite:=0; // breite des Ausdrucks, wird gebraucht um ggfs. viewport zu verschieben
    for i := vSpalte to bSpalte-1 do
       if (Grid.Columns.Items[i].Visible) then
         breite:=breite + rech(Grid.Columns[i].Width+1, waag);

    waagseiten:=0;

    if (scal > 0) and
       (vZeile < Grid.DataSource.DataSet.RecordCount) and
       (vSpalte < grid.Columns.Count) then
    begin
       if farbig then
       begin
          fix      := grid.fixedcolor;
          grund    := grid.color;
          schrift  := grid.font.color;
       end
       else
       begin
          fix      := clsilver;
          grund    := clwhite;
          schrift  := clblack;
       end;
       links       := rech(links, waag);
       oben        := rech(oben, senk);
       li          := GetDeviceCaps(Printer.Handle, PhysicalOffsetX) + 1 + links;
       a           := rech(3, waag);
       with Printer do
       begin

          Title := DTitle;
          BeginDoc;
           Canvas.Pen.Style := psClear;
          Canvas.Font      := Grid.Font;
          Canvas.Font.Color := Schrift;
          Canvas.Font.Size := round((Grid.Font.Size / 0.72) * scal);

          fertig:=false;
          while (not fertig) and (not Printer.Aborted) and Printer.Printing do begin
            ob := GetDeviceCaps(Printer.Handle, PhysicalOffsetY) + 1 + oben;
            un := ob + round(Printer.Canvas.TextHeight('A')*scal)+15;
            for x := 0 to Grid.Columns.Count - 1 do
            begin
              if (Grid.Columns.Items[x].Visible) then
              begin
                re := li + rech(Grid.Columns[x].Width + 4, waag);
              // Canvas.Rectangle(li, ob, re + 2, un + 2); // zeichnet grauen Rahmen um das Grid
                r := rect(li + a, ob + 1, re - a, un - 2);
                DrawText(Canvas.Handle, pchar( Grid.Columns.Items[x].Title.Caption), Length(Grid.Columns.Items[x].Title.Caption), r, DT_SINGLELINE or DT_VCENTER);
                li := re;
              end;
            end;
            li := GetDeviceCaps(Printer.Handle, PhysicalOffsetX) + 1 + links;
            ob := un;

            Grid.DataSource.DataSet.first;
            while (not Printer.Aborted) and (not Grid.DataSource.DataSet.Eof) and Printer.Printing do
            begin
                un := ob + round(Printer.Canvas.TextHeight('A')*scal)+15; // aufaddieren des Unterrandes
               //neue Seite + Kopf
               if (un > Printer.PageHeight) and
                  (Printing) then
               begin
                  printer.NewPage;
                  SetWindowOrgEx(printer.Handle,printer.pageWidth*waagseiten, 0, nil);
                  ob := GetDeviceCaps(Printer.Handle, PhysicalOffsetY) + 1 + oben;
                  un := ob + round(Printer.Canvas.TextHeight('A')*scal)+15;
                  for x := 0 to Grid.Columns.Count - 1 do
                  begin
                    if (Grid.Columns.Items[x].Visible) then
                    begin
                      re := li + rech(Grid.Columns[x].Width + 4, waag);
                    // Canvas.Rectangle(li, ob, re + 2, un + 2); // zeichnet grauen Rahmen um das Grid
                      r := rect(li + a, ob + 1, re - a, un - 2);
                     DrawText(Canvas.Handle, pchar( Grid.Columns.Items[x].Title.Caption), Length(Grid.Columns.Items[x].Title.Caption), r, DT_SINGLELINE or DT_VCENTER);
                     li := re;
                    end;
                  end;
                  ob := un;
                  li := GetDeviceCaps(Printer.Handle, PhysicalOffsetX) + 1 + links;
               end;
               un := ob + round(Printer.Canvas.TextHeight('A')*scal)+15;
               for x := 0 to Grid.Columns.Count - 1 do
               begin
                  if (Grid.Columns.Items[x].Visible) then
                  begin
                    re := li + rech(Grid.Columns[x].Width + 4, waag);
                  // Canvas.Rectangle(li, ob, re + 2, un + 2); // zeichnet grauen Rahmen um das Grid
                    r := rect(li + a, ob + 1, re - a, un - 2);
                    IF Grid.Columns[x].Alignment = taRightJustify then
                       DrawText(Canvas.Handle, PWChar( Grid.Columns.Items[x].Field.AsString), Length(Grid.Columns.Items[x].Field.AsString), r, DT_SINGLELINE or DT_RIGHT)
                    else if Grid.Columns[x].Alignment = taLeftJustify then
                       DrawText(Canvas.Handle, PWChar( Grid.Columns.Items[x].Field.AsString), Length(Grid.Columns.Items[x].Field.AsString), r, DT_SINGLELINE or DT_LEFT)
                    else
                       DrawText(Canvas.Handle, PWChar( Grid.Columns.Items[x].Field.AsString), Length(Grid.Columns.Items[x].Field.AsString), r, DT_SINGLELINE or DT_VCENTER);

//                    DrawText(Canvas.Handle, PWChar( Grid.Columns.Items[x].Field.AsString), Length(Grid.Columns.Items[x].Field.AsString), r, DT_SINGLELINE or DT_VCENTER);

                    li := re;
                  end;
                end;
                ob := un;
                li := GetDeviceCaps(Printer.Handle, PhysicalOffsetX) + 1 + links;
                Grid.DataSource.DataSet.Next;
            end;
            // jetzt Prüfung, ob der Ausdruck zu breit ist und ggfs, neue Serie mit verschobenem Viewport
            inc(waagseiten); // anzahl der waagerechten nebeneinanderliegen seiten, die ausgedruckt wurden
            if (breite > (Printer.PageWidth*waagseiten)) then fertig:=false else fertig:=true;
            if not fertig then begin
              printer.NewPage;
              SetWindowOrgEx(printer.Handle,printer.pageWidth*waagseiten, 0, nil); // viewport um Seitengröße verschieben
            end;
          end; // von while not fertig...
          if Printing then EndDoc;
       end; // von WITH PRINTER
    end;
  end;
end; //GridDruckNeu
Ist es vielleicht sinnvoller im DBGRID angezeigten Daten einfacher auszudrucken, wenn ja, wie bekomme ich diese schnell in ein Stringlist ?

haentschman 30. Sep 2016 17:19

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Hallöle... :P
Zitat:

ohne Reportgenerator
...da wirst du nicht glücklich. :zwinker: Wenn du am Design deines Ausdrucks schraubst mußt du am Code schrauben. Wenn du mal die Komponenten austauschst da funktioniert nichts mehr. :?

Nutze die Zeit um dich in einen Reportgererator einzuarbeiten. (imho ist bei XE3 Fastreport dabei) 8-)

waldforest 30. Sep 2016 19:17

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Hallo,

danke für die Empfehlung, möchte dennoch die Logik verstehen.
Aber dennoch habe ich mir dies einmal mit Quickreport angesehen, wie kann man denn hier über die Seitenbreite hinaus die Liste erstellen ?

haentschman 1. Okt 2016 06:01

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Moin...8-)

Ist nicht bei deiner Delphi Version Fastreport dabei? :gruebel:
Zitat:

möchte dennoch die Logik verstehen
...ich möchte die Logik eines Reportgenerators nicht verstehen. 8-) Der druckt das das was ich möchte das die Stelle wo ich es hinhaben will. Da bleibt mehr Zeit für die creativen Seiten...:P
Zitat:

wie kann man denn hier über die Seitenbreite hinaus die Liste erstellen
Mit Quickreport habe ich keine Erfahrungen. Aber alle Reportgeneratoren arbeiten nach dem gleichen Prinzip. Die Daten kommen aus einer Liste (DataSet in deinem Falle, welches am Grid hängt). Die Daten kommen niemals aus den visuellen Controls. :P Der Report ist dann quasi die Vorlage. Der Report stellt die Daten dann visuell, je nach Menge, zusammen... mit den Seitenvorschüben die du brauchst. :P

Nachtrag:
Zitat:

FastReport has been present in Delphi and C++Builder since XE2 and it’s part of XE3
...dann gibt es keine Frage für den Generator. :P Tutorials Teil 1-4: https://www.youtube.com/watch?v=VDTSGf4oIFA

Ungeübt tippe ich darauf das der (einfache) Report in 1 Stunde (ohne Tutorial) fertig ist. :P

Einschränkungen zum Tutorial:
* In der Embarcardero Edition gibt es den ReportDesiger, welcher aus dem Code aufrufbar ist, nicht.

waldforest 1. Okt 2016 14:16

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Hallo,
ich habe es einmal mit Fastreport nachgebaut. Auch hier sehe ich keine Möglichkeit in der Breite über den normalen Bereich (sprich auf neuer Seite) zu drucken.

page.EndlessWidth hat keinen Einfluss.


Delphi-Quellcode:
procedure GridPreview(Grid: TDBGrid);
var
  page: TfrxReportPage;
  band: TfrxBand;
  memo: TfrxMemoView;
//  cross: TfrxCrossView;
  masterBand: TfrxMasterData;
  i, x: Integer;
  CurrentLeft, CurrentTop : integer;
  BMark: TBookmark;

begin
  // Make sure that report is clean.
  GridRep.Clear;

  // Set dataset range properties
  dataset.RangeEnd:= reCount;
  dataset.RangeEndCount:= grid.DataSource.DataSet.RecordCount;

  // Add dataset to report
  GridRep.DataSets.Add(dataset);

  // Add a page
  page:= TfrxReportPage.Create(GridRep);
  page.CreateUniqueName;
  page.SetDefaults;
  page.EndlessWidth := True;
  page.Orientation:= poLandscape;

  // Add a report title band
  band:= TfrxReportTitle.Create(page);
  band.CreateUniqueName;
  band.Top:= 0;
  band.Height:= Abs(Grid.Font.Height) + 10;

  // Add object to the report title band
  memo:= TfrxMemoView.Create(band);
  memo.CreateUniqueName;
  memo.Text:= 'Test';
  memo.Height:= Abs(Grid.Font.Height) + 10;
  memo.Align := baWidth;

  // Add masterdata band
  masterBand:= TfrxMasterData.Create(page);
  masterBand.CreateUniqueName;
  masterBand.DataSet:= dataset;
  masterBand.Top:= band.Top+band.Height+1;
  masterBand.Height:= (Canvas.TextHeight('A') + 10);

  // Add objects on master data
  x:= 0;
  for I := 0 to Grid.Columns.Count - 1 do
   begin
//        ShowMessage(IntToStr(i)+'___'+Grid.Columns.Items[I].Field.FieldName);
     if (Grid.Columns.Items[I].Visible) then
    begin
      memo:= TfrxMemoView.Create(masterBand);
      memo.CreateUniqueName;
      // Connect to data
      memo.DataSet:= dataset;
      memo.DataField:= Grid.Columns.Items[I].FieldName;
      memo.SetBounds(x, 0, Grid.Columns[I].Width, (Canvas.TextHeight('A') + 10));
      x:= x+grid.Columns[I].Width;
      memo.Frame.Typ:= [ftLeft, ftRight, ftTop, ftBottom];
      memo.GapX:= 3;
      memo.GapY:= 2;
    end;
  end;

  GridRep.Showreport; {or Preview if you prefer}


end;

haentschman 1. Okt 2016 15:26

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Moin...:P

Warum benutzt nicht den Designer? Das TfrxReport Objekt auf die Form... Doppelklick drauf und den Report designen. :gruebel: Du machst dir mehr Arbeit als nötig.
Später kann man das optimieren... Reports und Datenbank etc.

PS: Hänge mal ein PDF an wie das Ergebnis ausschauen soll.

Delphi-Quellcode:
// Add objects on master data
  x:= 0;
  for I := 0 to Grid.Columns.Count - 1 do
   begin
// ShowMessage(IntToStr(i)+'___'+Grid.Columns.Items[I].Field.FieldName);
     if (Grid.Columns.Items[I].Visible) then
    begin
      memo:= TfrxMemoView.Create(masterBand);
      memo.CreateUniqueName;
      // Connect to data
      memo.DataSet:= dataset;
      memo.DataField:= Grid.Columns.Items[I].FieldName;
      memo.SetBounds(x, 0, Grid.Columns[I].Width, (Canvas.TextHeight('A') + 10));
      x:= x+grid.Columns[I].Width;
      memo.Frame.Typ:= [ftLeft, ftRight, ftTop, ftBottom];
      memo.GapX:= 3;
      memo.GapY:= 2;
    end;
  end;
Du hast doch das Dataset. Warum vermischt du das mit den Columns? Ich denke das du dich von den visualen Controls nicht lösen kannst. :P

waldforest 1. Okt 2016 16:07

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich nutze das Grid, damit ich hier ggf. Spaltenbreite, sowie Spalten ausblenden kann, damit habe ich einen Einfluss auf die auszugebenden Felder.

Das Grid geht über eine Seitenbreite hinaus !!
Anhang 45951

haentschman 1. Okt 2016 17:57

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Liste der Anhänge anzeigen (Anzahl: 3)
Soo...:P

2 Varianten als Muster:


1. Header 2 zeilig + Daten 2 zeilig
2. Header 1 zeilig + Daten 1 zeilig + Fortsetzung auf neuer Seite

... ich bitte die Darstellung zu entschuldigen. 8-) Ich habe meinen Report ausgedünnt um das zu verdeutlichen. Normalerweise hat man keinen Stress die Datenfelder auszurichten. :P


PS: Bis auf die Codezeilen für das Laden des Reports, Report.Preview und Füllen des DataSets (bei dir ist das schon fertig) gibt es keinen Code. Wenn die Daten der ersten Seite das Blatt übersteigen, wird auf der nächsten Seite weitergemacht... usw.

Nachtrag:
Wenn du die Spalten dynamisch ausblenden willst, kommst du wahrscheinlich um die Standard Version nicht rum. Da kannst du mit Events für jedes einzelne Control arbeiten. (Größe, Position etc.). Die 199$ war die beste Investion ever... Ob das mit der Embarcadero Version andersweitig geht, habe ich nicht ausprobiert. :P

waldforest 1. Okt 2016 19:33

AW: DBGrid, ausdrucken über mehrere Seitenbreite hinaus
 
Hallo,
vielen Dank, wenn man weiß wie es geht ist es wirklich ganz einfach.
Delphi-Quellcode:
procedure GridPreview(Grid: TDBGrid);
var
  page_wide : Integer;
  page: TfrxReportPage;
  band: TfrxBand;
  memo: TfrxMemoView;
//  cross: TfrxCrossView;
  masterBand: TfrxMasterData;
  i, x: Integer;
  CurrentLeft, CurrentTop : integer;
  BMark: TBookmark;

 Procedure AddPage();
  begin
    // Add a page
    page:= TfrxReportPage.Create(GridRep);
    page.CreateUniqueName;
    page.SetDefaults;
    page.Orientation:= poLandscape;
 
    // Add a report title band
    band:= TfrxReportTitle.Create(page);
    band.CreateUniqueName;
    band.Top:= 0;
    band.Height:= Abs(Grid.Font.Height) + 10;

    // Add object to the report title band
    memo:= TfrxMemoView.Create(band);
    memo.CreateUniqueName;
    memo.Text:= 'Test';
    memo.Height:= Abs(Grid.Font.Height) + 10;
    memo.Align := baWidth;

    // Add masterdata band
    masterBand:= TfrxMasterData.Create(page);
    masterBand.CreateUniqueName;
    masterBand.DataSet:= dataset;
    masterBand.Top:= band.Top+band.Height+1;
    masterBand.Height:= (Canvas.TextHeight('A') + 10);

  end ;


begin
  // Make sure that report is clean.
  GridRep.Clear;

  // Set dataset range properties
  dataset.RangeEnd:= reCount;
  dataset.RangeEndCount:= grid.DataSource.DataSet.RecordCount;

  // Add dataset to report
  GridRep.DataSets.Add(dataset);

  AddPage;


  // Add objects on master data
  x:= 0;
  page_wide :=0;
  for I := 0 to Grid.Columns.Count - 1 do
   begin
//        ShowMessage(IntToStr(i)+'___'+Grid.Columns.Items[I].Field.FieldName);
    if (Grid.Columns.Items[I].Visible) then
    begin
      if (page_wide+ Grid.Columns[I].Width+5) > page.Width then
      begin
         AddPage;
         page_wide :=0;
         x:= 0;
      end;

      memo:= TfrxMemoView.Create(masterBand);
      memo.CreateUniqueName;
      // Connect to data
      memo.DataSet:= dataset;
      memo.DataField:= Grid.Columns.Items[I].FieldName;
      memo.SetBounds(x, 0, Grid.Columns[I].Width, (Canvas.TextHeight('A') + 10));
      x:= x+grid.Columns[I].Width;
      memo.Frame.Typ:= [ftLeft, ftRight, ftTop, ftBottom];
      // Aufsummieren der Columsbreiten
      page_wide := page_wide + ROUND(memo.Width);
      memo.GapX:= 3;
      memo.GapY:= 2;
    end;
  end;

  GridRep.Showreport;

end;
@ich fange an, an Fastreport gefallen zu finden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:33 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz