![]() |
Elemente aus TStringList in Laufzeit entfernen
Hallo, ich will als Schulprojekt einen Vokabeltrainer erstellen der Vokabeln aus einer TXT Datei liest und den Benutzer diese abfragt. Dabei sollen die Vokabeln sooft zufällig abgefragt werden bis man sie 3 mal hintereinander richtig eingegeben hat.
Funktioniert soweit auch, nur wenn ich eine Vokabel aus der TStringList entferne, gibt es einen "List index out of bounds" Error. Vermutlich löscht Delphi die Vokabel, nur ohne die verbleibenden neu zu sortieren und somit erwischt der Zufallsgenerator mal einen Wert, der im Index nicht mehr vorhanden ist. Wie kann ich das Problem beheben?
Code:
PS: Die deutschen und englischen Vokabeln liegen in 2 separaten Textdateien, da ich es noch nicht geschafft haben die Wörter aus einer Datei getrennt auszulesen.
Begin
Input:= E_UserGuess.Text; E_UserGuess.Text:= ''; Answer:=AnsiCompareStr(VocabularyEnglish[RandomNumber], Input); If Answer=0 Then Begin L_CorrectAnswer.Caption:=''; jpg:= TJpegImage.Create; jpg.LoadFromFile('True.jpg'); Img_FeedBack.Picture.Bitmap.Assign(jpg); jpg.free; End Else Begin L_CorrectAnswer.Caption:='Deine Antwort: '+(Input)+' '+'Richtige Antwort: '+(VocabularyEnglish[RandomNumber]); jpg:= TJpegImage.Create; jpg.LoadFromFile('False.jpg'); Img_FeedBack.Picture.Bitmap.Assign(jpg); jpg.free; End; RepetitionCheck:=RandomNumber; While RepetitionCheck = RandomNumber Do RandomNumber:=random(WordCount); VocabularyEnglish:= TStringList.Create; VocabularyGerman:= TStringList.Create; try VocabularyEnglish.LoadFromFile('Vocabulary.txt'); VocabularyGerman.LoadFromFile('Vocabulary2.txt'); VocabularyGerman.Delete(RandomNumber); VocabularyEnglish.Delete(RandomNumber); L_RemainingWords.Caption:= 'Verbleibende Vokabeln: '+IntToStr(VocabularyGerman.Count); L_RemainingWords.Font.Name:='Helvetica LT Std'; L_RemainingWords.Font.Size:= 16; L_RemainingWords.Font.Color:= RGB(170,220,70); finally VocabularyGerman.Free; end; |
AW: Elemente aus TStringList in Laufzeit entfernen
Stringlisten beginnen bei Index 0. Nicht nur deswegen solltest du sicherstellen, dass deine Variable RandomNumber im Bereich zwischen 0 und TStringList.Count-1 liegt, bevor du sie als Index für die Stringliste(n) benutzt (z.B. zum Löschen eines Strings aus der Liste).
Grüße Dalai |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Code:
Haus,House
Hund,Dog
Code:
ungetestet
var
Vocab: TStringDynArray; begin Vocab := liste.strings[i].Split([',']); // DE: Vocab[0] // EN: Vocab[1] |
Dieses Thema wurde am "16. Nov 2018, 17:58 Uhr" von "Luckie" aus dem Forum "Algorithmen, Datenstrukturen und Klassendesign" in das Forum "Object-Pascal / Delphi-Language" verschoben.
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Danke für den Tipp @DieDolly, probier ich gleich mal aus. :thumb: |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Zitat:
Code:
Count ergebe hier 4. Um auf das vierte Item zuzugreifen, muss man aber [3] nutzen (weil die Liste null-basiert ist, erstes Item 0, zweites 1 usw.).
[0] => A
Count-1 => D Tipp am Rande: wenn dein Lehrer anfängt Arrays zu deklarieren wie test: array[1 .. 19] dann ignorier das am besten. Diese verfluchten 1-basierten Deklarationen erzeugen nur Probleme früher oder später. |
AW: Elemente aus TStringList in Laufzeit entfernen
'ne Stringliste ist eigentlich schon geeignet.
Wenn man eine Datei hat, in der die Vokabeln in dieser Form stehen:
Code:
so kann man mit
englisch=deutsch
House=Haus Car=Auto
Delphi-Quellcode:
den Inhalt abfragen, ohne dass man dabei dann zwei Dateien parallel pflegen muss.
EnglischeVokabel := VokabelStringliste.Names[RandomNumer];
DeutschVokabel := VokabelStringliste.ValueFromIndex(RandomNumber); Die Pflege kann man im Programm recht leicht mit 'nem TValueListEditor realisieren. Der dürfte irgendwo in der Komponentenpalette zu finden sein. |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
INI-Dateien bestehen aus Bereichen und Werteparen:
Code:
Vor dem Gleichheitszeichen steht der Name (Mehrzahl = Namen -> englisch = Names) des zu konfigurierenden "Teils" und hinter dem Gleichheitszeichen sein Wert (eine mögliche Übersetzung von Wert ins Englische ist Value (Einzahl) -> Values (Mehrzahl)).
[BereichMitBeliebigemEindeutigemNamen]
Name1=Wert1 Name2=Wert2 Name3=Wert3 [EnglischDeutsch] Car=Auto House=Haus Delphi=Delphi [DeutschEnglisch] Auto=Car Haus=House Delphi=Delphi [WeiterSprachpaareMoeglich] ...=... Und das ist ein "Wissen", was man Delphi schon von Anfang an beigebracht hat und heute immernoch nutzen kann, um mit wenig Aufwand 'nen Vokabeltrainer zu schreiben ;-) |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
So ganz scheint es doch nicht mit "Names" und "ValueFromIndex" zu funktionieren. Ich hab jetzt alles darauf umgeschrieben, bekomme auch keinen Compiler Error aber wieder ein "List Index out of Bounds" Fehler. Der tritt genau in der Zeile auf wo die Eingabe der Vokabel mit der in der TXT-Datei hinterlegten verglichen wird.
Code:
Wenn ich "Answer:=AnsiCompareStr(Vocabulary.Names[RandomNumber], Input);" auskommentiere geht es aber ich muss die Wörter vergleichen. Es liegt auch nicht an "RandomNumber", wenn ich das durch eine Zahl ersetze kommt der gleiche Fehler.
Begin
Input:= E_UserGuess.Text; E_UserGuess.Text:= ''; Answer:=AnsiCompareStr(Vocabulary.Names[RandomNumber], Input); RepetitionCheck:=RandomNumber; While RepetitionCheck = RandomNumber Do RandomNumber:=random(WordCount); try Vocabulary:= TStringList.Create; Vocabulary.LoadFromFile('Vocabulary.txt'); L_UnknownWord.Caption:= Vocabulary.ValueFromIndex[RandomNumber]; finally Vocabulary.Free; end; end Gibt es noch eine Möglichkeit die zu vergleichen? |
AW: Elemente aus TStringList in Laufzeit entfernen
Woher kommt WordCount, das darf maximal Vocabulary.Count - 1 sein.
Wenn Du aber erst eine Zufallszahl im Bereich bis WordCount "würfelst", aber WordCount zufällig größer als Vocabulary.Count - 1 ist, kann es sporadisch Fehler geben.
Delphi-Quellcode:
While RepetitionCheck = RandomNumber Do RandomNumber := Random(Vocabulary.Count - 1);
Achso: Die Vokabeln für jede einzelne Abfrage neu zu laden, halte ich nicht für so eine besonders gute Idee. Das sollte einmal (z. B. beim Programmstart) geschehen, ebenso das Freigeben der Vokabelliste. |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Code:
In FormCreat steht noch folgendes damit die erste Vokabel sofort bei Programmstart angezeigt wird:
black=schwarz
red=rot blue=blau
Code:
WordCount:= 3;
RandomNumber:= random(WordCount); try Vocabulary:= TStringList.Create; Vocabulary.LoadFromFile('Vocabulary.txt'); L_UnknownWord.Caption:= Vocabulary.ValueFromIndex[RandomNumber]; L_CorrectAnswer.Caption:= ''; finally Vocabulary.Free; end Zitat:
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
gelöscht
|
AW: Elemente aus TStringList in Laufzeit entfernen
[QUOTE=DieDolly;1418306]
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Es wird sich lohnen. Das sage ich immer wieder.
Am besten gleich richtig machen denn sonst wirst du deinen Code später hassen. Stell dir ein Record vor wie eine Kiste für Schrauben. In der Kiste gibt es Fächer für jede Schraubenart. Deine Kiste heißt TVocab (wovon du eine "Instanz" erstellst die dann in die Liste [die Liste ist dein Schrank wo all die Kisten drin sind] kommt) in deine Kiste kann zwei Arten von Schrauben fassen: Deutsche und Englische. Das sind natürlich Strings. ![]() ![]() |
AW: Elemente aus TStringList in Laufzeit entfernen
Funktioniert das noch mit der TStringList? Denn ich muss die Vokabeln während der Laufzeit entfernen können und jeder Vokabel eine Variable zuordnen können um zu überprüfen, wie oft sie schon richtig eingegeben wurde.
|
AW: Elemente aus TStringList in Laufzeit entfernen
gelöscht
|
AW: Elemente aus TStringList in Laufzeit entfernen
Heute will ich mal nett sein. Hier ein Beispiel mit generischer TList und Klasseninstanzen.
Gelöscht weil der TE sich nur für deine StringListe interessiert |
AW: Elemente aus TStringList in Laufzeit entfernen
Stringlisten werden von 0 bis Count - 1 gezählt.
Bei drei Worten in der Stringliste darf WordCount daher nur 2 sein. Maximalwert für WordCount = Anzahl der Wörter in der Liste - 1; WordCount solltest Du nach dem Laden der Stringliste auf Stringliste.Count - 1 setzen und nicht irgendwo am Programmstart auf den vermutet richtigen Wert. |
AW: Elemente aus TStringList in Laufzeit entfernen
Hmm..
Delphi-Quellcode:
Begin
Input:= E_UserGuess.Text; E_UserGuess.Text:= ''; // Hier greifst Du auf Vocabulary zu. Wann wurde dort etwas reingeladen? Answer:=AnsiCompareStr(Vocabulary.Names[RandomNumber], Input); RepetitionCheck:=RandomNumber; While RepetitionCheck = RandomNumber Do RandomNumber:=random(WordCount); try // Hier wird Vocabulary 'Überschreiben' Vocabulary:= TStringList.Create; Vocabulary.LoadFromFile('Vocabulary.txt'); L_UnknownWord.Caption:= Vocabulary.ValueFromIndex[RandomNumber]; finally // Hier wird Vocabulary 'weggeschmissen Vocabulary.Free; end; end Siehe meine Kommentare.. Woher kommt beim ersten Zugriff auf Vocabulary der Inhalt und was meinst Du passiert beim nächsten Zugriff auf Vocabulary? |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Kann ich Vokabeln auch wieder aus der txt Datei laden, sodass man die ständig wechseln kann? Zitat:
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Ich hab dir bei Eine zufällige englische Vokabel anzeigen doch gezeigt wie man eine Vokabel aus den Klassen lädt. Die Txt-Datei brauchst du nach Programmstart nur ein einziges mal laden. Danach nie wieder. Das ist ja der Sinn der Sache. |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
PS: Ich hab gerade das Problem gefunden. Es lag tatsächlich am .Free nach finally. Jetzt funktioniert es scheinbar. |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Du kannst 99% von meinem Code übernehmen. Du musst sie nur selber reinladen. Ungefähr so
Delphi-Quellcode:
try
Vocabulary:= TStringList.Create; Vocabulary.LoadFromFile('Vocabulary.txt'); for i := 0 to Vocabulary.Count - 1 do begin Vocab := TVocab.Create; Vocab.SolvedCount := 0; Vocab.German := Vocabulary.Names[i]; Vocab.English := Vocabulary.ValueFromIndex[i]; VokabelListe.Add(Vocab); end; finally Vocabulary.Free; end; |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Du gibst den reservierten Speicher der StringListe wieder frei.
|
AW: Elemente aus TStringList in Laufzeit entfernen
Hmm..
Zitat:
Delphi-Quellcode:
(Ungetestet, nur so hingeschrieben ;) )
procedure LoadVocab(VokabelListe : TList<TVocab>);
var tmpVocabulary : TStringList; Vocab : TVocab; begin try tmpVocabulary:= TStringList.Create; tmpVocabulary.LoadFromFile('Vocabulary.txt'); for i := 0 to Vocabulary.Count - 1 do begin Vocab := TVocab.Create; Vocab.SolvedCount := 0; Vocab.German := tmpVocabulary.Names[i]; Vocab.English := tmpVocabulary.ValueFromIndex[i]; VokabelListe.Add(Vocab); end; finally tmpVocabulary.Free; end; end; @KetchUp Oder wenn Du unbedingt mit der StringList weiter arbeiten möchtest, dann solltest Du dir erstmal über einen grundsätzlichen Ablauf klar sein.. z.B.: FormCreate -> Laden der Vokabelliste in die StringList Im (wahrscheinlich) ButtonClick -> Prüfen/Arbeiten MIT der Stringliste -> Nicht wieder neu laden, wozu auch, ist ja bereits FormClose -> Mit .Free die Stringliste wieder freigeben (aufräumen!!) |
AW: Elemente aus TStringList in Laufzeit entfernen
Ich möchte es erstmal mit der TStringList Variante probieren. Das Programm muss auch noch ein paar andere Sachen können wie zum Beispiel die Lernrichtung (Deutsch>Englisch oder Englisch>Deutsch) ändern.
Deswegen sieht mein Ansatz jetzt so aus:
Delphi-Quellcode:
Nachdem alle Vokabeln (in dem Fall) einmal richtig waren, soll ein neues Fenster geöffnet werden. Aber genau an der Stelle stürzt das Programm immer ab. Wo muss ich Vocabulary.Free; platzieren damit das funktioniert?
Begin
If Vocabulary.Count > 0 Then Begin If GermanEnglish = True Then Begin Input:= E_UserGuess.Text; E_UserGuess.Text:= ''; Answer:=AnsiCompareStr(Vocabulary.Names[RandomNumber], Input); If Answer=0 Then Begin L_CorrectAnswer.Caption:=''; Img_FeedBack.Picture.Bitmap.Assign(jpgCorrect); //jpgCorrect.free; Vocabulary.Delete(RandomNumber); End Else Begin L_CorrectAnswer.Caption:='Deine Antwort: '+(Input)+' '+'Richtige Antwort: '+(Vocabulary.ValueFromIndex[RandomNumber]); Img_FeedBack.Picture.Bitmap.Assign(jpgWrong); //jpgWrong.free; End; RepetitionCheck:=RandomNumber; While RepetitionCheck = RandomNumber Do RandomNumber:=random(Vocabulary.Count); try L_UnknownWord.Caption:= Vocabulary.ValueFromIndex[RandomNumber]; L_RemainingWords.Caption:= 'Verbleibende Vokabeln: '+IntToStr(Vocabulary.Count); L_RemainingWords.Font.Name:='Helvetica LT Std'; L_RemainingWords.Font.Size:= 16; L_RemainingWords.Font.Color:= RGB(170,220,70); finally end; end Else Begin Input:= E_UserGuess.Text; E_UserGuess.Text:= ''; Answer:=AnsiCompareStr(Vocabulary.ValueFromIndex[RandomNumber], Input); If Answer=0 Then Begin L_CorrectAnswer.Caption:=''; Img_FeedBack.Picture.Bitmap.Assign(jpgCorrect); jpgCorrect.free; Vocabulary.Delete(RandomNumber); End Else Begin L_CorrectAnswer.Caption:='Deine Antwort: '+(Input)+' '+'Richtige Antwort: '+(Vocabulary.Names[RandomNumber]); Img_FeedBack.Picture.Bitmap.Assign(jpgWrong); jpgWrong.free; End; RepetitionCheck:=RandomNumber; While RepetitionCheck = RandomNumber Do RandomNumber:=random(Vocabulary.Count); try L_UnknownWord.Caption:= Vocabulary.Names[RandomNumber]; L_RemainingWords.Caption:= 'Verbleibende Vokabeln: '+IntToStr(Vocabulary.Count); L_RemainingWords.Font.Name:='Helvetica LT Std'; L_RemainingWords.Font.Size:= 16; L_RemainingWords.Font.Color:= RGB(170,220,70); finally //Vocabulary.Free; end; End; End Else Begin Form3 := TForm3.Create(self); try Form3.ShowModal; finally Form3.Free; Vocabulary.Free; end; End; End; |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Wo erstellst Du die Liste ubd wo lädst Du die Liste? Im FormCreate? Dann gehört das Vocabulary.Free ins FormDestroy. Sinnvollerweise solltest Du die Liste beim Programmstart erstellen (unabhängig davon ob Du sie dort sofort lädst oder erst später). Freigeben solltest Du sie dann beim Programmende. Wenn Du sie unbedingt leeren möchtest, so kannst Du an der Stelle, an der momentan das Vocabulary.Free steht, ein Vocabulary.Clear aufrufen. Dann wird die Liste geleert, aber nicht zerstört. |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Delphi-Quellcode:
Sobald die Bedingung nicht mehr erfüllt ist stürzt er aber ab. Er kommt garnicht dazu die Prozedur FormDestroy aufzurufen.
If Vocabulary.Count > 0 Then
//mach was Else Begin FormDestroy(Vocabulary); End; |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Und wenn du es schon komplizierter machst als es sein muss und ehrlich gesagt auch irgendwie falsch, dann entferne wenigstens diesen einen Fehler hier. Alle anderen kannst du drin lassen denn sonst bleibt kein Code mehr übrig.
Delphi-Quellcode:
If GermanEnglish = True
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Das reicht auf True muss man nicht prüfen..
Delphi-Quellcode:
If GermanEnglish then
oder
Delphi-Quellcode:
If not GermanEnglish then
anstelle von
Delphi-Quellcode:
If GermanEnglish = false then
gruss |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
|
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
Die Liste in Deiner oben geposteten Routine freizugeben ist schlicht und einfach (bei der jetztigen Form der Implementierung) unsinnig und absolut kontraproduktiv. Lass es doch bitte einfach endlich weg. Bitte poste mal den vollständigen Quelltext, den Du bisher geschrieben hast. Mit den Fragmenten ist es nur ein Rumgestocher, wo welcher Fehler herkommen könnte und wie man ihn beheben könnte, wenn man die Abhängigkeiten innerhalb des gesamten Programmes nicht kennt. |
AW: Elemente aus TStringList in Laufzeit entfernen
Zitat:
sorry das musste sein. gruss |
AW: Elemente aus TStringList in Laufzeit entfernen
Oder der Willen, es endlich mit den Klassen zu machen. Dann braucht er die SttringListe, seinen Gegner, nur noch einmalig beim Programmstart.
Ich habe vor 10 Jahren auch mal einen Vokabeltrainer gemacht und der baute auch auf StringListen auf, weil ich damals nix anderes kannte. Sei doch froh, dass dir hier direkt ein sehr viel besserer Weg vorgeschlagen wird. Der ist nicht nur für dich besser, sondern auch für deine Zensur. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz