Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Zeichenlänge eines Memo zu klein (https://www.delphipraxis.net/177136-zeichenlaenge-eines-memo-zu-klein.html)

Hansi 18. Okt 2013 14:37

Zeichenlänge eines Memo zu klein
 
Hallo,

über folgenden Code lade ich mir eine txt-Datei aus dem Internet in mein einfaches Programm und arbeite dann Zeile für Zeile ab. Seit neuestem gibt es aber ein Problem, dass die Zeilen zu lang für das TMemo sind und der Inhalt einer Zeile umgebrochen wird.
Kann ich die möglichen Zeichenmenge eines TMemo vergrößern?

Code:
url := 'http://www.xxx.com/daten.txt';

  try
    daten := IdHTTP1.get(url);
  Except
    Memo1.Lines.Add('URl existiert nicht!');
    Exit;
  end;

  Memo1.Lines.Add(daten);


  For i := 1 to Memo1.Lines.Count - 1 do begin
  Application.ProcessMessages;
  s := Memo1.Lines[i];
  ...
  end;

Bernhard Geyer 18. Okt 2013 14:41

AW: Zeichenlänge eines Memo zu klein
 
Musst du es denn in ein Memo Laden?
Würde nicht das halten in einer Stringliste reichen?

Hansi 18. Okt 2013 14:44

AW: Zeichenlänge eines Memo zu klein
 
ne es muss kein Memo sein. Ich will es ja nur "temporär" Speichern um es zeilenweise auszulesen

hathor 18. Okt 2013 14:45

AW: Zeichenlänge eines Memo zu klein
 
For i := 1 to Memo1.Lines.Count - 1 do begin
???
For i := 0 to Memo1.Lines.Count - 1 do begin

Memo.Lines[] ist ein StringArray, das wie ein Array 0-indiziert ist.

Ausserdem:
Memo1.Lines.Add(daten);
besser:
Memo1.text:= daten;

Hansi 18. Okt 2013 14:47

AW: Zeichenlänge eines Memo zu klein
 
@hathor: Ja weil in der ersten Zeile die Spaltenüberschriften stehen

WoGe 18. Okt 2013 14:52

AW: Zeichenlänge eines Memo zu klein
 
TListbox ist hier eventuell besser geeignet.
Kein Zeilenumbruch und visuell

Gruß
wo

Perlsau 18. Okt 2013 14:55

AW: Zeichenlänge eines Memo zu klein
 
Die Menge der Zeichen, die ein TMemo aufnehmen kann, ist grundsätzlich nicht begrenzt bzw. findet ihre Grenze am verfügbaren Arbeitsspeicher. Zeilen werden umgebrochen, wenn die ClientWidth des Memos nicht für ihre Darstellung ausreicht. Ich würde dir daher empfehlen, mit einer globalen Stringliste statt mit einem (globalen) Memo zu arbeiten und das Memo gegebenenfalls zur Darstellung einzusetzen, nicht jedoch zur Verarbeitung deiner Daten.

Delphi-Quellcode:
 ...
  PRIVATE
   Var
      FehlerListe : TStrings;


Implementation

Procedure TFormMain.FormCreate(Sender: TObject);
begin
  FehlerListe := TStringList.Create;
end;

Procedure TFormMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  FehlerListe.SaveToFile(Dateiname);
  FehlerListe.Free;
  CanClose := True;
end;

Procedure TForm1.Runterladen;
Var
  Url : String;
begin
 
  ...
  url := 'http://www.xxx.com/daten.txt';

  try
    daten := IdHTTP1.get(url);
    FehlerListe.Append(daten);
  Except
    FehlerListe.Append(e.message + ': "' + url + '"');
    Exit;
  end;



  For i := 0 to FehlerListe.Count - 1 do
  begin
    Application.ProcessMessages;
    s := FehlerListe[i];
    ...
  end;

Hansi 18. Okt 2013 15:19

AW: Zeichenlänge eines Memo zu klein
 
ok vielen Dank...

laden tut; nur bei Fehlerliste.Count ist der Wert immer 1 und nicht die Anzahl an Zeilen.

Perlsau 18. Okt 2013 15:23

AW: Zeichenlänge eines Memo zu klein
 
Welche Anzahl erwartest du denn?

Hansi 18. Okt 2013 15:26

AW: Zeichenlänge eines Memo zu klein
 
exakt 2854 Zeilen ;)
(wenn ich es exportiere nach Excel)

Unx 18. Okt 2013 15:29

AW: Zeichenlänge eines Memo zu klein
 
Beim Memo die Eigenschaft WordWrap auf false stellen müssten einen automatischen Zeilenumbruch verhindern.

Perlsau 18. Okt 2013 15:29

AW: Zeichenlänge eines Memo zu klein
 
Setze einen Breakpoint am Anfang deiner Procedure und steppe durch. Kleiner Hinweis: ich hab den Code oben noch mal ein wenig abgeändert, denn das Add gehört in den Try-Block und die Fehlermeldung e.message sollte man ebenfalls protokollieren.

Hansi 18. Okt 2013 16:14

AW: Zeichenlänge eines Memo zu klein
 
mit Wordwrap funzt nicht, da die Zeile ja zu lang ist.

immer noch der gleiche "Fehler", dass die Anzahl Zeilen = 1 ist. Kann es sein, dass er den String als eine Zeile einliest?

Perlsau 18. Okt 2013 16:24

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Zitat von Hansi (Beitrag 1232446)
mit Wordwrap funzt nicht, da die Zeile ja zu lang ist. Immer noch der gleiche "Fehler", dass die Anzahl Zeilen = 1 ist.

Da ich nicht über eine Glaskugel verfüge, wären weitere Infos äußerst hilfreich:

1. Welche Delphi-Version? Die Frage gilt der Unicode-Unterstützung: Ab Delphi 2009 sind Strings unicodefähig und nicht mehr auf 256 Zeichen begrenzt.

2. Wo hast du FehlerListe deklariert? Doch hoffentlich als globale Variable, wie im Beispielcode vorgeschlagen, und nicht in der Procedure Runterladen.

3. Zeig uns doch bitte mal deinen Code, inkl. FormCreate, ButtonKlick und Runterladen.

Zitat:

Zitat von Hansi (Beitrag 1232446)
Kann es sein, dass er den String als eine Zeile einliest?

Eine Zeile in einer Stringliste wird immer durch einen String repräsentiert. Im Grunde gibt es in einer Stringlist keine "Zeilen", weil die Stringlist sich nicht selbst zeilenmäßig darstellt wie z.B. ein TMemo.

himitsu 18. Okt 2013 17:09

AW: Zeichenlänge eines Memo zu klein
 
TFormMain.FormCloseQuery ist etwas "ungünstig" zum Speichern, aber vorallem zum Freigeben.

Das Gegenstück zum OnCreate ist OnDestroy, also was man im OnCreate erstellt, gibt man es im OnDestroy frei.

Denn eine Form die geschlossen wird, kann auch wieder angezeigt werden, ohne sie neu zu erstellen.
Und OnCloseQuery wird nicht immer aufgerufen, denn z.B. die Freigabe via Free schließt die Form direkt, ohne Nachfrage.

Perlsau 18. Okt 2013 17:15

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Zitat von himitsu (Beitrag 1232458)
TFormMain.FormCloseQuery ist etwas "ungünstig" zum Speichern, aber vorallem zum Freigeben.
Und OnCloseQuery wird nicht immer aufgerufen, denn z.B. die Freigabe via Free schließt die Form direkt, ohne Nachfrage.

Danke, Himitsu, das wußte ich noch nicht :thumb:

In meinen Anwendungen wird jedoch niemals eine Form via Free geschlossen, sondern immer durch vom Anwender ausgelöste Aktionen wie Button- oder Menüklick oder Alt-F4 usw. Insofern muß ich jetzt wohl nich alle meine Projekte durchgehen und eine Ereignisbehandlung für OnDestroy hinzufügen :?:

Ich dachte immer, wenn ich Close in der Hauptunit aufrufe, wird das Programm beendet. Gilt natürlich nicht für Close in weiteren Forms, die mit Show oder ShowModal angezeigt werden. Aber du hast natürlich recht: besser sind Freigaben und Ähnliches in OnDestroy aufgehoben.

DeddyH 18. Okt 2013 17:35

AW: Zeichenlänge eines Memo zu klein
 
Strings sind übrigens seit Delphi 2(!!) nicht mehr auf 256 Zeichen begrenzt. Wieso die Stringliste nur eine Zeile enthält, könnte in der Tat mit nicht erkannten Zeilenumbrüchen zu tun haben. Unter Windows ist der Zeilenumbruch #13#10, unter Unix #13 und AFAIK unter MacOS #10. Was passiert denn, wenn Du den empfangenen String mal in einer Datei speicherst und diese mit Notepad (nicht Wordpad) öffnest? Ist das dort auch nur eine Zeile (ggf. mit "komischen Zeichen" drin)?

Perlsau 18. Okt 2013 17:42

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Zitat von DeddyH (Beitrag 1232461)
Strings sind übrigens seit Delphi 2(!!) nicht mehr auf 256 Zeichen begrenzt.

Danke, DeddyH :thumb: Ich erinnere mich, schon mal darauf hingewiesen worden zu sein, hab' aber wohl wieder vergessen :?

himitsu 18. Okt 2013 17:46

AW: Zeichenlänge eines Memo zu klein
 
TForm.Close schließt grundsätzlich erstmal nur die Form (quasi Hide/Visible), aber gibt sie nicht frei (außer man gibt z.B. im OnClose das caFree an).

Bei der MainForm ist da aber noch eine Besonderheit, denn wird diese geschlossen, dann wird der Schliessenbefehl an Application weitergegeben, genauso wie Minimieren da auch an Application durchgeht.

MainForm ist die Form, welche bei Application.MainForm registriert ist.
Und standardmäßig wird die erste TForm, welche über CreateForm erstellt wird, automatisch als MainForm registriert.

MDI-Forms werden beim Schließen (Close) ohne einen OnCloseQuery-Aufruf direkt mit caFree dichtgemacht.


Ach ja, als Gegenstück von OnClose könnte man OnShow ansehen.

himitsu 18. Okt 2013 17:49

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Zitat von Perlsau (Beitrag 1232465)
Zitat:

Zitat von DeddyH (Beitrag 1232461)
Strings sind übrigens seit Delphi 2(!!) nicht mehr auf 256 Zeichen begrenzt.

Danke, DeddyH :thumb: Ich erinnere mich, schon mal darauf hingewiesen worden zu sein, hab' aber wohl wieder vergessen :?

255 Zeichen, da es die Länge 0 auch gibt. (ingesammt aber 256 Byte, inkl. Längenbyte)

Und den "alten" Delphi-Referenz durchsuchenShortString gibt es immernoch.

Seit mindestens D2 ist "String" kein generischer Typ, sondern leitet nur an die "aktuelle" String-Definition weiter.
Also AnsiString und seit D2009 den UnicodeString.

Perlsau 18. Okt 2013 17:51

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Zitat von himitsu (Beitrag 1232466)
Bei der MainForm ist da aber noch eine Besonderheit, denn wird diese geschlossen, dann wird der Schliessenbefehl an Application weitergegeben, genauso wie Minimieren da auch an Application durchgeht.

Ergo wird in meinen Anwendungen, in denen ich in der Hauptform (bei mir immer FormMain bzw. UnitMain) in OnCloseQuery CanClose auf True setze, immer zuverlässig das Programm beendet und alle damit zusammenhängenden Freigaben veranlaßt.

himitsu 18. Okt 2013 18:22

AW: Zeichenlänge eines Memo zu klein
 
Du brauchst da nichmal caFree.
Sobald das Ding geschlossen wird (Close oder Free), wird die Messageloop verlassen und dann alle anderen Fenster (welche via CreateForm erstellt wurden) geschlossen.

In wie weit dabei alles Andere ordentlich freigegeben wird, hängt davon ab, ob es es irgendwo registriert wurde, was das Freigeben übernimmt, bzw. ob es entsprechende Freigaberoutingen an der richtigen Stelle gibt.


Delphi-Referenz durchsuchenReportMemoryLeaksOnShutdown

Perlsau 18. Okt 2013 18:47

AW: Zeichenlänge eines Memo zu klein
 
Von mir selbst bzw. im Code erzeugte Objekte werden bei mir immer zuverlässig freigegeben. Hab das eben mal mit ReportMemoryLeaksOnShutdown := True in einigen meiner Anwendungen getestet: Kein einziges Speicherleck ... caFree verwende ich praktisch nicht, da ich OnClose bislang ebenfalls nicht einsetzte. Freigaben können also weiterhin in OnCloseQuery der Hauptform stattfinden, da diese Methode ohne Ausnahme immer nach dem Close aufgerufen wird:
Zitat:

Zitat von himitsu (Beitrag 1232472)
Du brauchst da nichmal caFree.
Sobald das Ding geschlossen wird (Close oder Free), wird die Messageloop verlassen und dann alle anderen Fenster (welche via CreateForm erstellt wurden) geschlossen.
In wie weit dabei alles Andere ordentlich freigegeben wird, hängt davon ab, ob es es irgendwo registriert wurde, was das Freigeben übernimmt, bzw. ob es entsprechende Freigaberoutingen an der richtigen Stelle gibt.
Delphi-Referenz durchsuchenReportMemoryLeaksOnShutdown

Wie das läuft, wenn ich einen Prozeß via TaskManager abschieße, weiß ich jetzt aber echt nicht. Aber wir kommen wohl schon eine Weile vom Thema ab ...

Sir Rufo 19. Okt 2013 01:08

AW: Zeichenlänge eines Memo zu klein
 
Der Speicher wird vom Prozess beim System angefordert.
Stirbt der Prozess ist auch der Speicher wieder frei.

Medium 19. Okt 2013 04:00

AW: Zeichenlänge eines Memo zu klein
 
Um nochmals zum eigentlichen Thema zurück zu kommen:

Es wäre in der Tat hier jetzt das wichtigste zu wissen, welche der 3 weiter oben genannten Zeilenumbrüche in der Datei vorliegen. Desweiteren wurde bereits angesprochen, dass ein Memo ggf. nicht die Richtige Wahl ist - das wäre sie bestenfalls dann, wenn der Text wirklich auch dem Benutzer zur Ansicht und Bearbeitung präsentiert werden soll. Ansonsten ist eine TStringList weit günstiger an dieser Stelle. (Die TMemo.Lines Property ist vom Typ TStrings, wie auch TStringList. Sie sind sich sehr ähnlich, jedoch fällt bei TStringList der gesamte Overhead zum Anzeigen raus, was durchaus beachtlich ist.) Zudem meine ich im Hinterkopf zu haben, dass TMemo nur bis zu 64kB Text verträgt (bedingt durch eine Grenze von Windows; TStringList leidet nicht darunter), jedoch kann das u.U. eine veraltete Info sein. Ich weiss nicht, wie sich Delphi >2007 da verhält.

Meine Vermutung ist hier ganz stark, dass ein Linux-Linebreak vorliegt, der versucht wurde mit dem Memo.WordWrap zu "reparieren". Das haut einfach nicht hin, da WordWrap sich auf die Breite der visuellen Komponente bezieht, NICHT auf die missverstandenen Linebreaks in dem Original-Text. Und die Notwendigkeit der Anzeige steht überdies zur Debatte.

Mein Vorschlag, wie es vermutlich klappen könnte:
Delphi-Quellcode:
var
  rawText, line: String;
  s: TStringList;
begin
  url := 'http://www.xxx.com/daten.txt';

  try
    rawText := IdHTTP1.get(url);
  except
    on e: Exception do
      raise Exception.Create('Fehler beim Download von "'+url+'": '+e.Message);
  end;

  s := TStringList.Create;
  try
    try
      s.Text := StringReplace(rawText, #13, #13#10, [rfReplaceAll]);

      For i := 1 to s.Count - 1 do
      begin
        Application.ProcessMessages;
        line := s[i];
        try
          ...
        except
          on e: Exception do
            raise Exception.Create('Fehler beim Verarbeiten von Zeile '+IntToStr(i)+': '+e.Message);
        end;
      end;
      ...
    except
      on e: Exception do
        raise Exception.Create('Fehler beim verarbeiten der Datei: '+e.Message);
  finally
    s.Free;
  end;
end;

himitsu 19. Okt 2013 10:50

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Delphi-Quellcode:
s.Text := StringReplace(rawText, #13, #13#10, [rfReplaceAll]);

Das StringReplace kann ganz beruhigt weg, da die TStringList mit allen Zeilenumbrüchen klarkommen wird. (#13#10, #10 und #13)

Zitat:

Delphi-Quellcode:
For i := 1 to s.Count - 1 do

0 bis count-1 :zwinker:


Delphi-Quellcode:
var
  s: TStringList;
  line: String;
begin
  url := 'http://www.xxx.com/daten.txt';

  s := TStringList.Create;
  try
    try
      s.Text := IdHTTP1.Get(url);
    except
      on e: Exception do
        raise Exception.CreateFmt('Fehler beim Download von "%s": %s', [url, e.Message]);
    end;
    for i := 0 to s.Count - 1 do
      begin
        //Application.ProcessMessages;
        line := s[i];
        try
          ...
        except
          on e: Exception do
            raise Exception.CreateFmt('Fehler beim Verarbeiten von Zeile %d der Datei "%s": %s %s', [i, url, s[i], sLineBreak + e.Message]);
        end;
      end;
  finally
    s.Free;
  end;
end;

Medium 20. Okt 2013 15:34

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Zitat von himitsu (Beitrag 1232504)
Das StringReplace kann ganz beruhigt weg, da die TStringList mit allen Zeilenumbrüchen klarkommen wird. (#13#10, #10 und #13)

Seit welcher Version? Ich meine, dass die D7 StringList das noch nicht tat, kann mich aber irren. (Der TE hat seine Version nicht angegeben, daher bin ich mit meiner mutmaßlichen Erinnerung auf Nummer Sicher gegangen.)

Zitat:

0 bis count-1 :zwinker:
Wenn man alle Zeilen durchgehen will ja, aber der TE hat irgendwo hier erwähnt, dass er wirklich erst ab Zeile 1 anfangen will :zwinker:

himitsu 20. Okt 2013 18:16

AW: Zeichenlänge eines Memo zu klein
 
Zitat:

Zitat von Medium (Beitrag 1232556)
Seit welcher Version? Ich meine, dass die D7 StringList das noch nicht tat, kann mich aber irren.

Ich wollte vorhin nachsehn, wie es in D7 aussieht, aber mir ist grade eben der Server abgeraucht und ich komm an die D7-VM nicht ran.
Also nächste Woche dann mal.

Zitat:

Zitat von Medium (Beitrag 1232556)
Zitat:

0 bis count-1 :zwinker:
Wenn man alle Zeilen durchgehen will ja, aber der TE hat irgendwo hier erwähnt, dass er wirklich erst ab Zeile 1 anfangen will :zwinker:

Na dann :oops:

himitsu 21. Okt 2013 00:05

AW: Zeichenlänge eines Memo zu klein
 
Ein Blick in den Delphi7-Quellcode (TStrings.SetTextStr) sagt mir, daß .Text mit Allem (#13#10, #10 und #13) zurecht kommt.

Medium 21. Okt 2013 00:15

AW: Zeichenlänge eines Memo zu klein
 
Dann war's nur meine Verwirrtheit :) Danke für die Aufklärung!

Edit: Wenn das schon in TStrings enthalten ist, wirft das natürlich die Frage auf, was nun das Problem beim TE wirklich ist... Weil dann sollte auch das Memo dies berücksichtigen, und das Abstellen von WordWrap zum Ziel führen (wenn auch mit dem Overhead der grafischen Ausgabe bzw. Nutzen eines WinControls für Aufgaben, für die es nicht gedacht ist.)


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:51 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