Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi letzten linebreak aus tstrings (trichedit.lines) entfernen (https://www.delphipraxis.net/184534-letzten-linebreak-aus-tstrings-trichedit-lines-entfernen.html)

DrUArn 2. Apr 2015 11:59

Delphi-Version: XE

letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Hi, comm,

ich möchte in einem Trichedit verhindern, daß am Ende eine linebreak angefügt wird (man also auf der letzten text-Zeile und nicht auf einer Zeile darunter steht).


Beispiel:
richedit.text sieht bei normalem Anhängen von 3 Zeilen mit append so aus: '1'#$D#$A'2'#$D#$A'3'#$D#$A
Der letzte Linefeed soll weg, mglst. OHNE Richedit.text neu zu setzen

Delphi-Quellcode:
procedure TextAnhaengen;
  var i:integer;
begin
  for i:=1 to 3 do richedit1.lines.append(inttostr(i)); //ergibt bei Richedit1.text : '1'#$D#$A'2'#$D#$A'3'#$D#$A
end;

procedure deletelastlinebreakMitTextNeu; //funktioniert
 var p:pchar;
begin

p:=pchar(richedit1.text);
if (p-2)^ in [#13,#10] then
    (strend(p)-2)^:=#0; //ist so was erlaubt?, geht jedenfalls, -2 entspricht entspricht -length(lines.linebreak)
RichEdit1.Text:=p

end;

procedure deletelastlinebreakOhneTextNeu;//funktioniert nicht
begin

if (pchar(richedit1.text)-2)^ in [#13,#10] then
    (strend(pchar(richedit1.text))-2)^:=#0

end;
deletelastlinebreakOhneTextNeu geht sicherlich nicht, weil text ein Konstanten-Object ist, also scheinbar so nicht verändert wird.
Genausowenig darf setlength(richedit1.text,lenght(richedit1.Text)-2) versucht werden.

Seht ihr eine Möglichkeit, richeidt1.Text zu manipulieren, ohne das wie hier RichEdit1.Text:=p; neu gesetzt werden muß?


Grüße
Uwe

himitsu 2. Apr 2015 12:35

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Was soll denn bitte das mit den Nullen?

Ich dachte du wolltest entfernen und nichts willd überschreiben.
PS: Bei einem leeren Text im Richedit kann das schnell mal knallen, wenn du versuchst die Standardkonstante für einen leeren PChar zu überschreiben.



Delphi-Referenz durchsuchenTrimRight oder Delphi-Referenz durchsuchenEndsStr mit Copy/Delete? :roll:

Oder du leitest das RichEdit ab, überschreibst WM_GETTEXTLENGTH und WM_GETTEXT und gibst dort den gewünschten Text raus, denn TMemoStrings (die Klasse hinter .Lines) greifst darauf zu,, bzw. auf RichEdit.Text.

p80286 2. Apr 2015 12:57

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Zitat:

Zitat von DrUArn (Beitrag 1295963)
ich möchte in einem Trichedit verhindern, daß am Ende eine linebreak angefügt wird (man also auf der letzten text-Zeile und nicht auf einer Zeile darunter steht).

Und warum versuchst du dann
Delphi-Quellcode:
.Text
zu vergewaltigen?
setze
Delphi-Quellcode:
.SelStart
(z.B. auf
Delphi-Quellcode:
length(RichEdit1.Text)-3
(und nicht den leeren Text vergessen!)) und
Delphi-Quellcode:
.SelLength:=0
und gut ist.

Gruß
K-H

DrUArn 2. Apr 2015 13:38

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Hi,

Danke für die schnelle Antwort.
@himitsu: Habe schon geahnt, daß ich mir Prügel abhole. Deinen Worten nach setzt man in einem Null-terminierten String nicht einfach #0, um ihn an einer anderen Stelle zu beenden. Zu trim ..: ich möchte eben eine Neuzuweisung an Richedit1.text verhindern, da dann alle Angaben für diesen Text (Farben, Schrifttyp an und einige andere Berechnungen an diversen (sehr vielen) Stellen wieder neu durchgeführt werden werden müssen (und dass sehr oft).
@P80286: Einfacher geht's nimmer. Ich arbeite gerade bei diesem Projekt sehr viel mit selstart und sellength - darum flackerts leider immer mal etwas (man sieht dann die Markierung aufblitzen - dafür habe ich aber auch keine Lösung, man müßte verhindern, daß sellength blau eingefärbt wird), aber irgendwie habe ich diese simple Lösung nicht gesehen - danke.

so wäre meine Lösung:
Delphi-Quellcode:
procedure deletelastlinebreakOhneTextNeu;//funktioniert nicht
begin
if length(richedit1.text>1 then //sicher ist sicher, wer weiß, was passiert, wenn da '' oder nur 'a' steht, ich denke aber, auch bei einem Leerstring passiert
                                //nichts
if RichEdit1.text[length(richedit1.text)-length(richedit1.lines.linebreak)+1] in [#13,#10] //das sieht ganz schön umständlich aus,
                                                                                           //+1 muß sein, da ein String bei 1 Anfängt zu zählen?
 then
 with richedit1 do
   begin
     selstart:=length(text))-length(lines.linebreak);//selstart steht jetzt vor #13
     sellength:=length(lines.linebreak);//sellength markiert #13#10
     clearselection //weg damit
  end
end;
Danke an alle
Uwe

DrUArn 2. Apr 2015 16:19

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Hi,

Kommando zurück, so funktioniert's nur bei einzeiligen Texten. Bei trichedit muß man ja auch mit den als 1 gezählten Zeilenvorschüben kämpfen.
Für Operationen am Ende eines Textes ist das aber einfach:

Delphi-Quellcode:

procedure deletelastlinebreakOhneTextNeu;//funktioniert nicht
begin

if length(richedit1.text>1 then //sicher ist sicher, wer weiß, was passiert, wenn da '' oder nur 'a' steht, ich denke aber, auch bei einem Leerstring passiert
                                //nichts ;
   //oder auch so: if strend(pchar(text)-1))^ in [#13#10] then - was ist besser? -1 nur, da bei -2 und wenn am Ende kein #13#10 mehr auch steht, greift man in die
                                                      bei kurzen Zeilen aufden Zeilenvorschub der vorhergehenden Zeile und löscht diese gleich mit
if RichEdit1.text[length(richedit1.text)-length(richedit1.lines.linebreak)+1] in [#13,#10] //das sieht ganz schön umständlich aus,
                                                                                         //+1 muß sein, da ein String bei 1 Anfängt zu zählen?
then
 with richedit1 do
   begin
{--->} selstart:=length(text)-length(lines.linebreak)-(lines.Count-1);//selstart steht jetzt vor #13, die Anzahl der Zeilenvorschübe muß mit eingerechnet
                                                                      //werden je als 1
      sellength:=length(lines.linebreak);//sellength markiert #13#10
      clearselection //weg damit
  end
end;
Grüße
Uwe

himitsu 2. Apr 2015 17:09

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Warum nicht einfach die Befehle benutzen, welche am Anfang schon genannt wurden?
> Text auslesen und das Ende entfernen.


Du darfst gern meinen vor Jahren bei Emba (QC) eingereichten Bugreport (samt Lösungsvorschlägen) raussuchen.
Die "aktuell" genutzte RichText-Komponente (von Microsoft) arbeitet erschreckender Weise mit #13 und die von Codegear/Embarcadero waren so doof, daß sie nur die Hälfte versucht hatten auf die #13#10 umzusetzen ... leider nur die Hälfte und da ist nicht SelStart/SelLength dabei. :wall:

Ich hab aufgegeben und werde garantiert zu 99,8% nicht mehr miterleben, wie die VCL hier jemals repariert wird.
Mein anderer Vorschlag war, wenn sie es nicht schaffen, dann sollen sie den Quatsch (die halbherzige Umwandlung) einfach wieder ausbauen ... lieber "falsche" Zeilenumbrüche, alt soein Dreck.

PS: Bevor du dich freust, daß es ja nun was Neueres gibt, aber das FMX-Memo hat mit den Zeilenumbrüchen ebenfalls Probleme, wie ich gestern mitbekommen hab.

DrUArn 2. Apr 2015 18:53

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Hhi, Himitsu,

ja, Du hast recht.
Am einfachsten wäre schon Dein Vorschlag:
Delphi-Quellcode:
Procedure DeletelastLinebreak;
  var s.string;
begin

//text:=trimright(RichEdit1.text);geht nicht
s:=richedit1.text;
text:=trimright(s);
text:=s
end;

aber, in meinem Richedit werden sehr viele Abfragen für die Darstellung gebraucht, die ich dann wieder neu aufrufen müßte;

Delphi-Quellcode:
//Richedit1.Text:='   {123}   {456} '#13#10'{789}'
//wenn man mit lines.append arbeit entsteht zum Schluß'   {123}   {456} '#13#10'{789}'#13#10

Procedure prepareText
begin
//hier soll '{' rot, '}' gelb, die Texte dazwischen wenn Zahl blau, wenn Text grün eingefärbt werden
//also sellstart vor erstes'{', sellength:=1; Farbe,

//selstart nach erstem '{', Textlänge zwischen erstem '{' und erstem '}' ermitteln,
//(und dabei berücksichtigen, daß in diesem Text auch linebreaks sein könnten)
//prüfen, ob dieser Text eine Zahl oder ein Text ist, sellength setzen und färben

//sellstart vor erstes'}', sellength:=1; Farbe,


//und das alles für alle Klammern{...}

//um das zu bewerkstelligen, mußte ich eine Zugriffsmethode auf Text schreiben, die mir das richtige Selstart und das richtige Sellength zurückgibt
//geht ja nicht mit pos o.ä., sondern man muß immer aufpassen, wieviele linebreaks in Richedit1.text und dann auch noch in dem Text zwischen den Klammern versteckt sind, die man mit 1 berücksichtigen muß
//aber ich hab's gelöst (auch wenn mir die Funktion dazu umständlich aussieht), und verstehe deinen Unmut über #13 und #13#10
end;

Procedure Settext;
begin
 for i:=0 to 100 //oder mehr
  richedit1.lines.add('{'+inttostr(i)+'}')
  preparetext;
  deletelastlinebreak; //Farben wieder weg
  preparetext//alles wieder gut
end;

procedure addstring;
begin
 lines.add(('{'+'irgendein Text+'}')
 prepareneuenEintrag//nicht den ganzen Text

//aber, falls wieder ein linebreak hinten dranhängt

  deletelastlinebreak; //Farben wieder weg
  preparetext//alles wieder gut
end;
Wenn addstring dann oft ausgeführt wird, muß deletelastlinebreak und preparetext immer wieder durchlaufen werden.
Darum mein Versuch, eben nur den letzten linebreak wegzulöschen.
Oder man garantiert, daß nach dem ersten Eintrag nie wieder ein linebreak angehängt wird
Delphi-Quellcode:
procedure addstring2;
begin
 lines.add(('{'+'irgendein Text+'}')
 if lines.count=1 //erster Eintrag
    then begin deletelastlinebreak;preparetext end
 else
 prepareneuenEintrag//es dürfte hier eigentlich kein neuer linebreak angehängt worden sein, daß macht richedit wohl nur berim ersten Eintrag,
                    //wenn man den wglöscht, wird kein neuer erzeugt
end;

Grüße Uwe

himitsu 2. Apr 2015 19:44

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Hmmm, dann gäbe es natürlich noch BeginUpdate.

DrUArn 2. Apr 2015 21:38

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Hi, himitsu

da stehe ich gerade auf dem Schlauch.

BeginUpdate EndUpdate von tstrings ...

meinst du, daß ich die Neudarstellung von lines irgendwie stoppen kann, und erst wenn alles fertig, wieder auf den Schirm werfen?


Grüße
Uwe

Perlsau 2. Apr 2015 23:06

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Dann schau dir doch mal die Online-Hilfe zu BeginUpdate und EndUpdate an und lies, was dort steht.

mann mann ...

DrUArn 7. Apr 2015 20:35

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Hi, comm,

@ mann mann ... : natürlich schaue ich mir die Hilfen an. Aber nicht jeder versteht wie du alles sofort ....

In den Beispielen der Hilfe finde ich:

procedure TForm1.ComboBox1DropDown(Sender: TObject);
var
I: Integer;
begin
with ComboBox1 do
begin
Items.BeginUpdate; { Prevent repaints until done. }
....

Items.EndUpdate; {Reenable painting. }
end;
end;

Von meinem Verständnis: Teile ich der Liste mit, daß ich was ändern will (BeginUpdate), stellt sie sich solange nicht neu dar, bis ich mitteile, daß ich fertig bin (EndUpdate).

Delphi-Quellcode:
Procedure Test;
begin
RichEdit1.Lines.BeginUpdate;
RichEdit1.Clear;
i:=strtoint(editintegerpanel_ua1.ei.text);
for i := 0 to 1000 do TestRich1.Lines.Add(IntToStr(i));
RichEdit1.Lines.EndUpdate;
end;
In dem Beispiel wird aber mit jedem neuen Listeneintrag auch neu dargestellt, also die Liste hochgescrollt, bis der 1000ste Eintrag erreicht wird.

Damit nützt mir das BeginUpdate - EndUpdate hier nichts - keine Unterdrückung der Neudarstellung.

Aber auch LockWindowUpdate(richedit1.Handle) hilft da nicht.


Gruß uwe

Dalai 7. Apr 2015 20:48

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Zitat:

Zitat von DrUArn (Beitrag 1296544)
Von meinem Verständnis: Teile ich der Liste mit, daß ich was ändern will (BeginUpdate), stellt sie sich solange nicht neu dar, bis ich mitteile, daß ich fertig bin (EndUpdate).

Korrekt, und das funktioniert auch.

Zitat:

Delphi-Quellcode:
Procedure Test;
begin
RichEdit1.Lines.BeginUpdate;
RichEdit1.Clear;
i:=strtoint(editintegerpanel_ua1.ei.text);
for i := 0 to 1000 do TestRich1.Lines.Add(IntToStr(i));
RichEdit1.Lines.EndUpdate;
end;
In dem Beispiel wird aber mit jedem neuen Listeneintrag auch neu dargestellt, also die Liste hochgescrollt, bis der 1000ste Eintrag erreicht wird.
Liegt wohl daran, dass du RichEdit1 zum Neuzeichnen sperrst, die Einträge aber in TestRich1 hinzufügst.

MfG Dalai

DrUArn 7. Apr 2015 21:04

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
@Dalei: Danke, Du hast recht! Schreibfehler.

Dann werde ich damit noch ein wenig experimentieren.

Gruß Uwe

Sir Rufo 7. Apr 2015 21:44

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
Zitat:

Zitat von DrUArn (Beitrag 1296550)
@Dalei: Danke, Du hast recht! Schreibfehler.

Dann werde ich damit noch ein wenig experimentieren.

Gruß Uwe

Manchmal hilft es auch den Quellcode vernünftig zu formatieren damit das Lesen und damit das Erkennen von Fehlern deutlicher und schneller ins Auge springt.
Delphi-Quellcode:
Procedure Test;
begin
  RichEdit1.Lines.BeginUpdate;
  RichEdit1.Clear;
  i := strtoint( editintegerpanel_ua1.ei.text );
  for i := 0 to 1000 do
    TestRich1.Lines.Add( IntToStr( i ) );
  RichEdit1.Lines.EndUpdate;
end;

DrUArn 7. Apr 2015 22:43

AW: letzten linebreak aus tstrings (trichedit.lines) entfernen
 
@Sir Rufo: ja, ist richtig.

Nun habe ich mit BeginUpdate und EndUpdate etwas propbiert, verhindert auch größtenteils das Flackern bei vielfachem Einfärben.

Eine interessante Beobachtung hier noch, die ich nicht erklären kann:
Delphi-Quellcode:
procedure TSimpCellRichEd_UA.SetEditModus(const EdMo: tcelleditmodi);
  var s:string;

begin
 try
  s:='';
  lines.beginupdate;
  case Edmo of
{1}   emedaslines_UA:
      begin
        for i := 0 to 1000 do
               s:=s+inttostr(i)+lines.linebreak;
        text:=s;
{--->}  wordwrap:=false;//lines.assign(strl);
      end;
{2}   emedasFreePos_UA:
      begin
        for i := 0 to 1000 do
               s:=s+'{'+inttostr(i)+'}'+dupestring(' ',3);
        text:=s;
{--->}  wordwrap:=true;
      end;
 finally

 preparetext;//Einfärben an sehr vielen Stellen

{
case Editmodus of
{1}  emEdasLines_UA: self.wordwrap:=false;
{2}  emEdasFreePos_UA: self.wordwrap:=true;
end;
}
 lines.endupdate;
end;
end;
Dies ist nur ein Auszug aus dem umfangreicheren Original.
Die Einträge werden also einmal wie ein Text, geklammert mit Zeilenumbruch dargestellt oder
Zeile für Zeile.
Lasse ich den Zeilenumbruch innerhalb der ersten Case-Schleife setzen {---->}, flimmert es beim Umrechnen von {2} nach {1},
und zwar nur dann, wenn Wordwrap vorher true war. Verlege ich das Setzen von wordwrap aus der ersten Case-Schleife in eine spätere (im Beispiel vor lines.endupdate), flimmerts nicht.


Das passiert auch, wenn ich bei {1} direkt Lines fülle (for i:=0 to 100 do lines.add(inttostr(i)));

Hebt vielleicht wordwrap:=false mein Beginupdate auf?


Gruß Uwe


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:55 Uhr.

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