PL Text Engine: Automatischen Zeilenumbruch(gelöst)

Rund um die LCL und andere Komponenten
Antworten
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)

PL Text Engine: Automatischen Zeilenumbruch(gelöst)

Beitrag von pluto »

Hallo,
schon seit Tagen versuche ich einen "Automatischen Zeilenumbruch Funktion" in meine "Text Engine" einzubauen. Aber alle meine versuche bisher waren nicht erfolgreich. Das Konzept habe ich mir grob gesehen so vorgestellt:
01) Ich erzeuge im Moment per Default einen Extra "Default Container" in jeder Zeile, später kann das noch optimiert werden.
02) Wenn es schon ein "Default Container" gibt, und dort Einträge vorhanden sind, werden sie gelöscht
03) Jetzt wird geschaut, ob das Objekt in die Zeile passt oder nicht. Wenn ja, wird es in die Zeile hinzugefügt, wenn nein wird es umgebrochen, dabei
04) wird geschaut, wie viel vom Objekt noch in die Aktuelle Zeile passt.
05) Später: Soll hier noch geschaut werden, wenn das Word nicht mehr rein passt in die Zeile, wie viel Buchstaben vom Aktuellen Word noch rein gehen.

Im Moment erkenne ich ein Word nur daran, das es mit einem "Leerzeichen" endet, später kann das noch verbessert werden.
Das Problem ist jetzt folgendes: Ob einer gewissen Größe, wird Falsch Umgebrochen, gerade bei mehren Objekten in der Zeile.
Es sind im Prinzip nur zwei arten von Objekten betroffen: Das "Text Objekt" und später das "Link Objekt".

Sollte jemand Probleme haben, das zu verstehen, was ich hier geschrieben habe einfach nach Fragen. Das Konzept ist etwas Kompliziert, aber bietet Praktische Vorteile.
Eventuell hilft auch dieses Bild weiter: http://forge.lazarusforum.de/wiki/textengine/imagelist3" onclick="window.open(this.href);return false;
Dort versuche ich den Groben Aufbau eines Dokumentes, in meiner "Text Engine" zu erklären.

Bevor ich es Vergesse hier ein noch der Komplette Soruce-Code der Funktion:

Code: Alles auswählen

procedure TPLTE_Container_Line.InitPosSizeItems(const NewSize:Boolean = True);
var
  i, x,x1,x2, px, py,px2,m,pw,pw2,pw3,pw4,c:Integer;
  str,LineText,LineText1,LineText2:String;
  df2:TPLTE_Container_Default;
  Line:TPLTE_Container_Line;
  Obj:TPLTE_ObjectSTD_Text;
  AutoBreakLine:Boolean;
  procedure iAddContainer;
  begin
    if (not Assigned(df)) and (Visible) then begin
      Name:='Line0';
      df:=df2.AddNewDefaultContainer;
      df.Style.Assign(df2.Style);
      df.Style.Border.B.Color:=pl_red1;
      df.Align:=CA_None;
      df.VS.Visible:=False; df.HS.Visible:=False;
      df.Visible:=False;
      df.Left:=Left;
      df.Top:=py;
      df.Name:='DF';
      df.Width:=Width;
      df.Visible:=False;
      Visible:=False;
    end
    else
      df.Visible:=False;
  end; // iAddContainer
begin
  df2:=TPLTE_Container_Default(Parent);
  pw:=0; LineText:='';
  px:=Left+2; py:=Top+3; Height:=GetLineHeight+5; x:=0; x2:=1; m:=0; px2:=0;
  // Vorhandene Objekte im Temp. Continaer Löschen, aber nur
  // wenn sich die Anwendung nicht im Lade zustand befindet oder
  // der Temp Container(df) nicht installisiert ist.
  if (not df2.NoLoad) and (Assigned(df)) then begin
    df.Visible:=False;
    df.fContainerList.OwnsObjects:=False;
    for i:=df.Count-1 downto 0 do begin
      if TObject(df.fContainerList[i]) is TPLTE_Container_Line then begin
        df.fContainerList.Remove(df.Items_Line[i]);
//        df.Items_Line[i].Destroy;
      end;
  //    df.fContainerList.Delete(i);
    end;
    df.fContainerList.Clear;
  end;
  // Zunächst wird alles in eine Zeile gepackt bis sie "voll" ist
  // dann wird sie zum Temp. Conatiner(DF) hinzugefügt und eine neue
  // wird erzeugt
  if Name <> 'Test' then begin
    iAddContainer;
    Line:=df.AddNewLine;
    Line.df:=df;
    Line.Name:='Test';
//    Line.Visible:=True;
  end;
 
  if df2.ClientWidth > 0 then begin
    LineText2:='';
    for i:=0 to Count-1 do begin
      if items[i] is TPLTE_ObjectSTD_Text then begin
        LineText:=''; str:=''; LineText1:=''; x1:=0; str:=''; LineText2:='';
        items[i].Left:=px; items[i].Top:=py;
        Items_Text[i].Style.ToCanvas(Canvas); x:=0;
        pw:=Canvas.TextWidth(Items_Text[i].Text);
        if Name <> 'Test' then begin
          if (px+pw+10 >=df2.ClientWidth) then begin
            pw2:=0; x:=0; px2:=px; pw:=0; x2:=0; LineText:='';
            LineText1:=Items_Text[i].Text; pw4:=0;
            repeat
              x1:=PosEx(' ',LineText1,x+1);
              str:=Copy(LineText1,x+1,(x1-(x)));
              pw2:=Canvas.TextWidth(str);
              //  Der Rest, wird in eine Extra Variable kopiert. Damit das in eine Schleife wider holt werden kann.
              LineText2:=Copy(LineText1,x,Length(LineText1)-x);
              pw3:=Canvas.TextWidth(LineText2);
//              writeln(str,'|',px2+pw2,'|',Width,'|',LineText2,'|',x,'|',x1,'|',LineText1);
              if x1 = 0 then writeln(LineText);
              if ((px2+pw2 >= Width) and (LineText <> '')) or (x1 = 0) then begin
                pw4:=Canvas.TextWidth(LineText);
                if (px2 >=Width) or (x1=0) then begin
                  Line:=df.AddNewLine;
                  Line.Name:='Test';
                  Line.df:=df;
                  pw4:=-2;
                end;
                Line.AddText(LineText).Style.Assign(Items_Text[i].Style);
                if (pw4 <> -2) and (x1 > 0) then begin
                  Line:=df.AddNewLine;
                  Line.Name:='Test';
                  Line.df:=df;
                end;
               // GANZ wichtig: Damit der Rest ebenso behandelt werden kann, wird er mit Line Text gleich gesetzt.
                LineText1:=LineText2;
                LineText:='';
                x:=0;
//                if x1 > 0 then
                  px2:=left;
  //              if x1 > 0 then begin
                  Continue;
    //            end
              end;
              LineText:=LineText+str;
              px2:=px2+pw2;
              x:=x1;
            until x1 = 0;
          end
          else
            Line.fItems.Add(Items_Text[i]);
        end;
        px:=px+pw-10;
      end;
    end; // for i
  end;
  if (Assigned(df)) and (NewSize) then begin
    df.Visible:=True;
    df.InitPosSizeItems(False);
  end;
  NoInit:=False;
end; // TPLTE_Container_Line.InitPosSizeItems
Diese Methode, soll sich um den Automatischen Zeilenumbruch kümmern. Die Abfrage "if Name = 'Test' then..." verhindert einige Fehler.
die Mehtode "df.InitPosSizeItems" unterscheidet sich von der "TPLTE_Container_Line.InitPosSizeItems" in sehr vielen Punkten.

Zum Schluss noch ein "Screenshot". Die Scrolleisten, haben im Moment noch keine Funktion. Sie sind einfach nur "da".

Ich hoffe ihr könnt mir weiter helfen. Ich sehe einfach den Fehler nicht den ich mache. Ich hoffe der Soruce-Code ist euch klar, wie er Funktioniert.
Wenn jemand Lust hat: Ich könnte auch den Kompletten Soruce-Code der Engine hoch laden so könnte ihr "eure" Ideen gleich ausprobieren. Ich komme an diese Stelle einfach nicht mehr weiter.

PS: Habe den Titel geändert, weil sonst das (gelöst) nicht mehr rein passte. Schön währe eine "CheckBox" dafür.
Dateianhänge
14.08.09_AT_Fehler.jpg
Zuletzt geändert von pluto am So 23. Aug 2009, 20:32, insgesamt 1-mal geändert.
MFG
Michael Springwald

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von Scotty »

Textumbruch macht man IMHO am besten per DrawText() mit der Option DT_WORDWRAP (o.ä.) & DT_CALCRECT. Google wäre dafür eine erste Anlaufstelle, ansonsten frag nochmal.

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: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von pluto »

Leider kann ich "DrawText" nicht nehmen. DrawText kann immer nur mit eine Schrift Konfiguration umgehen. Mein Projekt ist jedoch so aufgebaut, das unterschiedliche Schrift Konfigurationen möglich sind.
Mein Projekt arbeitet Objekt Orientiert.

Ich wüsste nicht wie ich in meinem Projekt "DrawText" einsetzten sollte. Es macht in meinen Augen auch nicht wirklich Sinn. Aber danke für deine Antwort. Eventuell finden wir ja noch eine Lösung.
Ich hoffe dir ist jetzt klar geworden, warum ich DrawText nicht nehmen kann. Selbst wenn ich einen Weg finde, es doch einzusetzen, bleibt die Frage: Wie bekomme ich dann die neuen Zeilen als Objekte ? Ich muss ja drauf zurück greifen können, wenn ich das Objekt mit der Maus anklicke z.b.
MFG
Michael Springwald

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von Scotty »

pluto hat geschrieben:Ich hoffe dir ist jetzt klar geworden, warum ich DrawText nicht nehmen kann.
Nein

Code: Alles auswählen

uses LCLIntf, LCLType; //Ich suche jedes mal nach den Units, in denen die Funktionen definiert sind. Da gibt es wohl keine gute Übersicht, oder?
procedure TForm1.PaintBox1Paint(Sender: TObject);
var s:string;
    r:TRect;
begin
  with PaintBox1 do
  begin
    Canvas.Brush.Color:=clBtnFace;
    Canvas.FillRect(Canvas.ClipRect);
    s:='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris purus lectus, feugiat at blandit nec.';
    Canvas.Font.Name:='Arial';
    Canvas.Font.Style:=[fsItalic];
    r:=Bounds(0,0,Width,Height div 2);
    DrawText(Canvas.Handle,PChar(S), -1, r, DT_LEFT or DT_WORDBREAK);
 
    s:='Suspendisse sagittis ligula non nunc venenatis vehicula. Phasellus varius vulputate tortor ut vestibulum.';
    Canvas.Font.Name:='Sans';
    Canvas.Font.Style:=[fsBold];
    r:=Bounds(0,Height div 2,Width,Height);
    DrawText(Canvas.Handle,PChar(S), -1, r, DT_LEFT or DT_WORDBREAK);
  end;
 
end;

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: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von pluto »

Ändere mal den Abstand der Text zu einander. So das sie enger zusammen sind. Am besten in zwei Zeilen. Weißt du wie ich meine ?
Zeile 1= Text1 Text2 Text3
Zeile 2= TextA TextB TextC
und so weiter.
MFG
Michael Springwald

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von Scotty »

Wenn du DT_CALCRECT mit in die Flags aufnimmst, wird der TRect-var-Parameter entsprechend geändert. Die nächste Zeile fängt dann bei r.Bottom an. Mit DT_CALCRECT wird nichts gezeichnet, es läßt sich also auch für Höhenberechnungen nutzen. Google bleibt dein Freund...

Code: Alles auswählen

DrawText(Canvas.Handle,PChar(S), -1, r, DT_LEFT or DT_WORDBREAK or DT_CALCRECT);

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: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von pluto »

Gut, eine Frage habe ich noch, wenn du bei Drawtext bleibst: Wie mache ich aus dem Text dann Objekte, die ich anklicken kann ?
Angenommen ich habe mehre Objekte in einer Zeile, die Unterschiedlich Groß sind. Die möchte ich jetzt umbrechen. Wenn nötig. Aber die Objekte werden nach der Intern Base Line ausgerichtet(wird die von DrawText beachtet ?) und wie sieht es mit der Anordnung von mehren Objekten aus ?

Ich werde mal ein Test Projekt erstellen, wo ich DrawText versuchen werde. Währe ja möglich das ich zu Kompiliert gedacht habe bisher.
MFG
Michael Springwald

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: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von pluto »

Probiere mal folgendes Beispiel aus:

Code: Alles auswählen

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
  s:String;
  r:TRect;
begin
  with PaintBox1 do begin
    Canvas.Brush.Color:=clBlue;
    Canvas.Font.Color:=clYellow;
    Canvas.FillRect(Canvas.ClipRect);
    s:='Hallo1 Hallo2 Hallo3 Hallo4';
    Canvas.Font.Name:='Arial';
    Canvas.Font.Size:=14;
    r:=Bounds(0,0,Width,Height);
    DrawText(Canvas.Handle,PChar(S), -1, r, DT_LEFT or DT_WORDBREAK);
    DrawText(Canvas.Handle,PChar(S), -1, r, DT_LEFT or DT_WORDBREAK or DT_CALCRECT);
    writeln(r.Right, '\',r.Bottom);
 
    Canvas.Brush.Color:=clBlue;
    Canvas.Font.Color:=clYellow;
    s:='Test1 Test2 Test3 Test4 Test5';
    Canvas.Font.Name:='Arial';
    Canvas.Font.Size:=25;
    r:=Bounds(R.Right,0,Width,Height);
    Canvas.FillRect(r);
    DrawText(Canvas.Handle,PChar(S), -1, r, DT_LEFT or DT_WORDBREAK);
//    DrawText(Canvas.Handle,PChar(S), -1, r, DT_LEFT or DT_WORDBREAK or DT_CALCRECT);
    writeln(r.Right, '\',r.Bottom);
  end;
end;
Ich bin davon überzeugt, dass es mit DrawText nicht geht. Außerdem muss ich es hier zwei mal aufrufen. Das ist auch "Mist". Das Problem liegt meiner Meinung nach daran das ich r beim zweiten Text mit R.Right Installisiere. Jetzt kannst dir bestimmt vor stellen, wo die nächste Zeile anfängt... Also bin ich genauso weit wie vorher..... sehe ich das richtig ?
Ich werde mal etwas googeln Eventuell geht es ja doch mit DrawText....
MFG
Michael Springwald

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von Scotty »

Ich würde eine variable Textanzeige zum Beispiel von TListBox ableiten. Dort gibt es Style=lbOwnerDraw und im OnDrawItem eine Eigenschaft Selected. Ich kann mir nur schwerlich vorstellen, dass es gut ist, jede Zeile einem Objekt zuzuordnen. Vielleicht bringt dich zumindest der Quellcode von TListBox auf Ideen. Dein Codeschnipsel ist mir zu lang :wink:

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: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von pluto »

Danke für deine Antwort, aber "brauchbar" ist sie leider nicht. Ich habe mir ein Ziel gesetzt. Versuch doch mal ein WebBrowser als ListBox zu schreiben *G*.
MFG
Michael Springwald

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: PL Text Engine: Probleme mit dem Automatischen Zeilenumbruch

Beitrag von pluto »

Zur Information: Ich habe die Funktion endlich hinbekommen. Daher ist der Fehler gelöst. Allerdings auch auf eine andere Art und weise. Wenn jemand möchte, kann ich auch gerne Soruce-Code stammen.
Die Eigentliche Kern Idee, stammte jedoch von jemanden anderem.
MFG
Michael Springwald

Antworten