Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - RichEdit Lines Delete hängt sich auf
Knulli - Fr 21.06.13 16:39
Titel: RichEdit Lines Delete hängt sich auf
Hi Leute,
ich hab in nem RichEdit etliche Zeilen Text (Logging)
Nun will ich all diejenigen Zeilen rauswerfen, in denen ein bestimmter Text NICHT vorkommt.
Das klappt auch etliche Male und bei einer bestimmten Zeile hängt sich mein Programm auf. Es kommt aus
RichEdit1.Lines.Delete(IDXZeile); nicht wieder.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| CntZeile := RichEdit1.Lines.Count; IDXZeile := 0;
while IDXZeile < CntZeile do begin Zeile := RichEdit1.Lines[IDXZeile];
.....
if Not bHalten then begin RichEdit1.Lines.Delete(IDXZeile); Dec(CntZeile); end else Inc(IDXZeile); end; |
Ich hab mal in die Sourcen reindebuggt, er kommt aus dem
SendMessage(RichEdit.Handle, EM_REPLACESEL, 0, Longint(Empty)); nicht wieder.
Kennt das jemand? Es scheint übrigens an einer bestimmten Konstellation zu liegen. Lösche ich andere Zeilen, hängt er sich nicht auf.
Falls jemand Lust hat: Im Anhang die RTF, alle Zeilen löschen, außer die mit
"DeviceId": "AnimalPort 3". Bei verbleibenden 258 Zeilen knallts.
RichEdit.Refresh zwischendurch hilft auch nicht :-(
Knulli
WasWeißDennIch - Fr 21.06.13 16:47
Was passiert denn, wenn Du eine TStringlist anlegst, die Zeilen aus dem RichEdit hineinkopierst, dann die betreffenden Zeilen aus dieser Liste löschst und zum Schluss alles wieder zurückschreibst?
[edit] Also ungefähr so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| var Liste: TStringlist; i: integer; begin RichEdit1.Lines.BeginUpdate; try Liste := TStringlist.Create; try Liste.Assign(RichEdit1.Lines); for i := Liste.Count - 1 downto 0 do if not Bedingung then Liste.Delete(i); RichEdit1.Lines.Assign(Liste); finally Liste.Free; end; finally RichEdit1.Lines.EndUpdate; end; end; |
[/edit]
Gerd Kayser - Sa 22.06.13 00:30
Knulli hat folgendes geschrieben : |
Im Anhang die RTF, alle Zeilen löschen, außer die mit "DeviceId": "AnimalPort 3". Bei verbleibenden 258 Zeilen knallts. |
Mach's mit einer for-downto-Schleife:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.Button1Click(Sender: TObject); var SuchText : string; Schleife : integer; begin SuchText := '"DeviceId": "AnimalPort 3"'; Label1.Caption := IntToStr(RichEdit1.Lines.Count); for Schleife := RichEdit1.Lines.Count - 1 downto 0 do if (Pos(SuchText, RichEdit1.Lines[Schleife]) = 0) then RichEdit1.Lines.Delete(Schleife); Label2.Caption := IntToStr(RichEdit1.Lines.Count); end; |
jaenicke - Sa 22.06.13 08:50
Eine separate Stringliste wie von
WasWeißDennIch vorgeschlagen ist dennoch besser, da das deutlich schneller ist als die GUI Komponente ständig zu aktualisieren...
// EDIT:
Woher kommen die Daten eigentlich? Wenn die nicht vom Benutzer dort eingegeben werden, wäre es sinnvoller die zuerst zu bearbeiten und dann in die Richedit Komponente zu packen.
Gerd Kayser - Sa 22.06.13 11:05
jaenicke hat folgendes geschrieben : |
da das deutlich schneller ist als die GUI Komponente ständig zu aktualisieren... |
Dann setzt man halt ein "RichEdit1.Lines.BeginUpdate;" davor und ein "RichEdit1.Lines.EndUpdate;" danach. Ich kann mir jedenfalls kaum vorstellen, daß die Variante mit der StringList deutlich schneller ist.
jaenicke - Sa 22.06.13 13:36
Gerd Kayser hat folgendes geschrieben : |
Dann setzt man halt ein "RichEdit1.Lines.BeginUpdate;" davor und ein "RichEdit1.Lines.EndUpdate;" danach. Ich kann mir jedenfalls kaum vorstellen, daß die Variante mit der StringList deutlich schneller ist. |
Ich empfehle dir sehr einen Blick in den Quelltext von TRichEdit, dann würdest du das nicht sagen...
Kurz gesagt:
Zuerst wird der Anfang der Zeile über das Handle und den Zeilenindex von Windows erfragt, wenn diese existiert auch das Ende der Zeile. Dann wird dieser Teil des Textes wiederum über die Windows API markiert. Und schließlich wird dieser markierte Teil durch einen Leerstring ersetzt.
Was passiert bei TStringList:
Es wird anhand reiner Integervergleiche geprüft, ob der Index im gültigen Bereich liegt. Dann wird der Record mit den Daten des Eintrags gelöscht und die anderen Einträge um diesen freigewordenen Platz im Array verschoben. Es werden dabei nur wenige Bytes angefasst, da die Pointer auf die Strings verschoben werden. Die anderen Zeilen werden da gar nicht angefasst.
Probier es aus, wenn du es trotzdem nicht glaubst. Es ist deutlich schneller. Und zudem ist es auch sinnvoller solche Sachen ohne Beteiligung der GUI zu machen.
Gerd Kayser - Sa 22.06.13 15:07
jaenicke hat folgendes geschrieben : |
Es ist deutlich schneller. |
Stimmt. Gerade mit der Datei des Fragestellers getestet. Meine Variante 0,163 Sekunden, die Variante mit der Stringlist 0,010 Sekunden (jeweils beste Zeiten aus mehreren Durchläufen genommen). Bei dieser (kleineren) Datei fällt das einem bei der Programmausführung aber kaum auf. Aber je größer die Datei ist, desto größer fallen die Zeitunterschiede aus. RichEdit wird da extrem langsam im Vergleich zur StringList-Variante.
Knulli - Do 27.06.13 13:45
So, erstmal Danke für die vielen Ideen.
Das mit einer zweiten Liste hab ich nicht gemacht, weil dabei die Text-Formatierungen verlorengehen. Das mit dem rot und blau hilft nämlich zusätzlich, den Überblick in den vielen Zeilen zu behalten.
Geschwindigkeit ist hier nicht so das Problem, da es um eine Fehleranalyse geht, es soll also aus den Log-Daten der Grund für ein Fehlverhalten der Anlage gewonnen werden.
Leider ist in den LogDaten eben auch viel anderes Zeugs mit drin.
Ich probier mal die Idee mit dem Löschen von Hintem aus.
Knulli
Knulli - Do 27.06.13 14:12
OK, so geht's... von hinten ist halt besser :lol:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| IDXZeile := RichEdit1.Lines.Count - 1; while IDXZeile >= 0 do begin Zeile := RichEdit1.Lines[IDXZeile]; bHalten := false; JSONobject := TlkJSONobject(TlkJSON.ParseText(Zeile)); if JSONobject <> Nil then begin stDeviceID := GetValue('DeviceId'); FreeAndNil(JSONObject); bHalten := stDeviceID = cboFilter.Items[cboFilter.ItemIndex]; end; if Not bHalten then RichEdit1.Lines.Delete(IDXZeile); Dec(IDXZeile); end; |
WasWeißDennIch - Do 27.06.13 14:20
Und was machst Du, wenn JSONobject nil wird? Wird dann gelöscht oder nicht?
Knulli - Di 23.07.13 15:43
Dann ist bHalten == false und die aktuelle Zeile wird gelöscht. Stand ja sowieso Müll (oder nix) oder eben nicht das gesuchte Wort drin...
jaenicke - Di 23.07.13 16:01
Nein, ist es nicht. Dann ist es nicht initialisiert...
Du setzt es nur in if JSONobject <> Nil then, liest es danach aber immer aus.
Der Compiler sollte da auch eine Warnung ausgeben.
Knulli - So 28.07.13 18:56
bHalten wird auch immer erstmal auf false gesetzt (Zeile über ParseText).
Der Compiler meckert nicht...
jaenicke - So 28.07.13 19:49
Knulli hat folgendes geschrieben : |
bHalten wird auch immer erstmal auf false gesetzt (Zeile über ParseText). |
Hinten in der Zeile... ach du Schreck... :shock:
Wer Quelltext so formatiert... ohjemine. Ja, da hast du Recht, da steht es... aber durch die abenteuerliche Formatierung mit mehreren Befehlen in einer Zeile sieht man das halt nicht so schnell...
wq121984 - Di 06.08.13 07:30
This is a very good post, I like it very much
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!