Höhe wird Falsch ausgerechnet. Es wird zuviel genommen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
pluto
Lazarusforum e. V.
Beiträge: 7194
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Höhe wird Falsch ausgerechnet. Es wird zuviel genommen

Beitrag von pluto »

Hallo,
seit Tagen kämpfe ich mit einem Fehler in meiner "Text Engine": Für das Scrollen brauche ich die genaue Angabe wie hoch das Document in Pixeln ist.
An sich klappt das, aber sobald ich Grafiken einbinde, wird zu viel zurück geben.

Einige Infos über die Verwaltung der Objekte:
In einer Zeile können: Unterschiedliche "Text Objekte" sich befinden, sie werden nach der Baseline ausgerichtet, die für diese Zeile gilt.
Pro Zeile kann im Moment nur eine Grafik angezeigt werden
Pro Zeile kann im Moment nur eine Horizontale Line angezeigt werden.
Tabellen und Verschachtelte Listen gibt es zwar auch schon, aber die lasse ich mal außen vor.
Hier einige Funktionen, wo ich den Fehler vermute:
Das hier ist die besagte Haupt Funktion, für das Berechnen der Dokumenten Höhe in Pixeln.
Zu Testen zwecken werden die Bilder und die Zeilen in zwei Unterschiedlichen Variablen zusammen gezählt und zum Schluss Addiert. Dabei kam raus das es in etwa der gleiche bereich der für die Grafiken genommen wird, auch zu viel ist hinterher oder anders ausgedrückt, es werden ungefähr 10 Zeilen unterschlagen, wenn ich die Grafiken nicht mit berechne, warum ?
Der unterschied müsste doch sehr viel größer sein.

Code: Alles auswählen

function TPlTextEngine_Container_Default.GetCalcTotalHeight: Integer;
var
  i,FirstObject, LineIndex,ph,z,bph:Integer;
  mh:TPLTextEngine_MHAD;
begin
  LineIndex:=0; ph:=0; z:=1; bph:=0;
  MH.Max_Descent:=0; MH.Max_Ascent:=0; MH.Max_Height:=0;
  MH.eh:=0; MH.ExtraRect:=Rect(0,0,0,0);
  for i:=0 to fObjects.Count-1 do begin
    if (items[i] is TPLTextEngine_ObjectImage) then begin
      bph:=bph+Items[i].Height;
      inc(z);
    end;
 
    if (items[i] is TPLTextEngine_objectLine) then begin
      ph:=ph+1;
    end;
 
    if (items[i] is TPlTextEngine_ObjectNewLine) or (i = 0) then begin
      mh:=GetObjectLineHeight(LineIndex);
      if mh.Max_Ascent+mh.Max_Descent > 0 then begin
        ph:=ph+mh.Max_Ascent+mh.Max_Descent;
      end;
      inc(LineIndex);
    end;
  result:=ph+bph;
  //+bph;
end; // TPlTextEngine_Container_Default.GetCalcTotalHeight
Diese Funktion ermittelt in einer Zeile das höchste Text Objekt. Im Moment gibt es noch keine "Automatische Zeilenumbruch" Funktion, eine Idee hätte ich allerdings schon.

Code: Alles auswählen

function TPlTextEngine_Container_Default.GetObjectLineHeight(const aIndex: integer
  ): TPLTextEngine_MHAD;
var
  i,FirstLineObjekt:Integer;
  TM: TTextMetric;
  MHAD:TPLTextEngine_MHAD;
begin
  FirstLineObjekt:=GetFirstLineObjekt(aIndex);
  MHAD.Max_Descent:=0; MHAD.Max_Ascent:=0; MHAD.Max_Height:=0;
  MHAD.eh:=0; MHAD.ExtraRect:=Rect(0,0,0,0);
  if FirstLineObjekt > -1 then begin
    for i:=FirstLineObjekt to fObjects.Count-1 do begin
//      if items[i] is TPLTextEngine_ObjectImage then
  //    continue;
      if fObjects[i] is TPlTextEngine_ObjectText then begin
        ObjectText[i].Style_Brush.ToCanvas(Canvas);
        ObjectText[i].Style_Pen.ToCanvas(Canvas);
        ObjectText[i].Style_Font.ToCanvas(Canvas);
        GetTextMetrics(Canvas.Handle, tm);
        if tm.tmAscent > MHAD.Max_Ascent then MHAD.Max_Ascent:=tm.tmAscent;
        if tm.tmDescent > MHAD.Max_Descent then MHAD.Max_Descent:=tm.tmDescent;
        if tm.tmHeight > MHAD.Max_Height then MHAD.Max_Height:=tm.tmHeight;
 
        if ObjectText[i].Style_Brush.InternalSpace.Top+ObjectText[i].Style_Brush.ApartSpace.Top > mhad.ExtraRect.top then
          mhad.ExtraRect.top:=ObjectText[i].Style_Brush.InternalSpace.Top+
                              ObjectText[i].Style_Brush.ApartSpace.Top
          ;
 
        if ObjectText[i].Style_Brush.InternalSpace.Bottom+ObjectText[i].Style_Brush.ApartSpace.Bottom > mhad.ExtraRect.Bottom then
          mhad.ExtraRect.Bottom:=ObjectText[i].Style_Brush.InternalSpace.Bottom+
                                 ObjectText[i].Style_Brush.ApartSpace.Bottom
          ;
      end; // TPlTextEngine_ObjectText
 
      if (fObjects[i] is TPlTextEngine_ObjectNewLine) then begin
        break;
      end;
    end; // for i
//    if ((MHAD.Max_Ascent > 0) and (MHAD.Max_Descent > 0))  or (MHAD.Max_Height > 0) then begin
      for i:=FirstLineObjekt to fObjects.Count-1 do begin
        if fObjects[i] is TPlTextEngine_ObjectText then begin
          ObjectText[i].Style_Brush.ToCanvas(Canvas);
          ObjectText[i].Style_Pen.ToCanvas(Canvas);
          ObjectText[i].Style_Font.ToCanvas(Canvas);
          if PFS_Underline in ObjectText[i].Style_Font.Style then begin
            GetTextMetrics(Canvas.Handle, tm);
//            writeln(MHAD.Max_Ascent-tm.tmAscent,'\',ObjectText[i].Text);
            if abs(MHAD.Max_Ascent-tm.tmAscent) = 0 then begin
              MHAD.eh:=3;
            end;
          end;
        end;
        if fObjects[i] is TPlTextEngine_ObjectNewLine then begin
          break;
        end;
      end; // TPlTextEngine_ObjectText
      result:=MHAD;
  //  end;
  end;
//  else
//    result:=-1;
end; // TPlTextEngine_Container_Default.GetObjectLineHeight
Diese Funktion ermittelt in einer Zeile das erste Objekt, sie wird sehr oft genutzt. AIndex ist die Zeile.

Code: Alles auswählen

function TPlTextEngine_Container_Default.GetFirstLineObjekt(const aIndex: Integer
  ): Integer;
var
  i,aLine,z:integer;
begin
  z:=-1; aLine:=0;
  for i:=0 to fObjects.Count-1 do begin
    if (fObjects[i] is TPlTextEngine_ObjectNewLine) or (fObjects[i] is TPLTextEngine_ObjectImage) then begin
      if (aLine+1 >=aIndex) or (aIndex = 0) then begin
        if aindex = 0 then
          z:=0
        else begin
          if (fObjects[i] is TPLTextEngine_ObjectImage) then
            z:=i+2
          else
            z:=i+1
        end;
        break;
      end
      else
        inc(aLine);
    end;
  end; // for i
  if z = -1 then
    z:=0;
  result:=z;
end; // TPlTextEngine_Container_Default.GetFirstLineObjekt
Sieht hier jemand einen Fehler im Code ? Bei bedarf kann ich auch das ganze Projekt Zeitweise hochladen. Allerdings ist es jetzt schon äußerst kompliziert und umfangreich was den Sorce-Code angeht.
Diese drei Funktionen habe ich in verdacht. Wie gesagt, sobald ich die Grafiken raus nehme, dass heißt, wenn ich keine Grafiken im Dokument habe, wird die Höhe scheinbar Richtig ermittelt. Es muss sich um ein Logischen Fehler handeln. Ich sehe ihn leider nicht.
MFG
Michael Springwald

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

Re: Höhe wird Falsch ausgerechnet. Es wird zuviel genommen

Beitrag von pluto »

Weiß keiner woran es liegen könnte ?
MFG
Michael Springwald

Antworten