Files und Streams mit wxWidgets
-
Hallo,
ich möchte Files und Streams mit wxWidgets schreiben. Leider kriege ich weder den Code aus dem sehr guten Tutorial (den Rest habe ich soweite verstanden) von phlox81, noch die Fragmente aus der Doku zum laufen.
Ich habe eigentlich nur ein paar ints und wxStrings und möchte die in eine Datei schreiben und wieder rauslesen. Aber es scheitert irgendwie immer, spätestens bei file.Write(Name); oder so. Hat jemand vielleicht einen funktionierenden Beispiel Quelltext oder so?
Besten Dank für alle Hilfen
-
Der Code im Tutorial müsste eigentlich funktionieren
Wo genau liegen denn die Probleme?
-
Mit out << und in >> kommt der Compiler (MingW mit Code::Blocks) nicht klar (kennt er nicht)
-
Filemacher schrieb:
Mit out << und in >> kommt der Compiler (MingW mit Code::Blocks) nicht klar (kennt er nicht)
Zeig mal deinen Code.
-
Erstmal danke für dein Interesse
Also: Ich glaube ich weiss was das Problem ist, aber nicht, wie ichs beheben kann.
Bei einem Konstruktor:SettingsDlg::SettingsDlg(wxWindow* parent, int id): wxDialog(parent,wxT("Einstellungen"),id), name(in >> Name), alter(in >> Alter)
Das sieht jetzt ziemlich grausam aus. Also: Ich möchte im Konstruktor bereits aus Dateien lesen und dabei möglichst auch bestimmen welche Zeile gelesen werden soll (ist hier nicht angegeben)
-
So geht das nicht. Du kannst nicht auf einen undefinierten Stream im Konstruktor zugreifen.
Ich würde dir dafür empfehlen, eine Load Methode in deine Anwendung einzubauen:
struct foo { foo(std::istream& i){Load(i);} void Load(std::istream& i){/*daten laden*/} };
Statt std::istream kannst du natürlich auch eine wxStreamklasse nehmen.
phlox
-
Vielen Dank für deine Antwort
Eine Frage hab ich noch: Wie kann ich bestimmen, welche Positionen in einer Datei geschrieben und gelesen werden.
Ich möchte zum Beispiel ein Programm schreiben, dass eine bestimmte Anzahl Objekte verwaltet. Ein Objekt hat als Eigenschaften einen Zahlenwert, einen Namen und eine Beschreibung.class Objekt { public: double Zahl; wxString Name; wxString Beschr; }
Nun sollen diese Werte in eine Datei geschrieben werden. Gleichzeitig möchte ich Standardoperationen wie Auslesen, etc. vornehmen. Gibt es dazu irgendwo eine Anleitung oder Beispielcode? Die Doku hilft mir irgendwie nicht weiter und mit in >> und out << kann ich die Objekte nicht spezifisch ansprechen (z.B. Objekt1.Read(Name) oder Objekt2.Write(Name, wxT("NeuerName"));
Vielen Dank auf jeden Fall für die Hilfe bisher
-
Du kannst für die Objekte jeweils einen operator << und >> implementieren.
Bei mehreren Objekten musst du jedoch jeweils angeben wieviele du davon in den Stream schreibst.Es gibt auch vordefinierte Datenformate, wie yaml oder xml, für xml gibt es schon unterstützung in wxWidgets.
-
Danke für deine Antwort.
Wie kann ich bei den Operatoren << und >> festlegen, das zum Beispiel die zweite Zeile gelesen werden soll?
-
Ok, damit ich jetzt auch mal denke
:
Eine Lösung wäre doch z.B.://Zweite Zeile lesen wxString Wort1,Wort2; in >> Wort1 >> Wort2; //bei entsprechend deklariertem Instream in >> Wort1 >> Wort2; // erste Zeile wird überschrieben //oder out: in >> Wort1 >> Wort2; out << Wort1 << Wort2; out << wxT("neu") << wxT("auchneu");
aber irgendwie ist das extrem unpraktisch und unübersichtlich. gibt es da eine einfachere Lösung?
beste grüße
-
Und da fängt das Problem mit den Streams schon an.
out << "hallo" << "welt" ergibt hallowelt.
Wenn du also das jetzt wieder auslesen willst, landen hallo und welt in einem string. Der danach hätte das nachsehen.
Du musst also entsprechend trennen mit einem Leerzeichen, kann aber auch probleme machen, da ein string ja auch Leerzeichen enthalten kann.
Solange keine Newlines drin sind, kann man das in eine Zeile packen, und später mit getline auslesen:string str = "Hallo Welt"; out << str << endl; getline(in,str);
Natürlich kannst du auch in einem Stream springen, bzw. ihn entsprechend positionieren, dies geht aber nur, wenn du weisst was wo steht.
z.B. wenn du einen vordefinierten Header hast, und weisst das an Byte 53 ein int beginnt, das du auslesen willst. Ein Stream kennt von sich aus keine Zeilen oder markierungen, nach denen man suchen könnte.phlox
-
Erstmal vielen Dank für deine Antworten
Streams scheinen mir dann nicht ganz geeignet für "Config" Files zu sein. Könnte man denn mit wxTextfile oder so nach Zeilen und/oder Wortpositionen vorgehen?
Die Doku hilft mir da irgendwie nicht weiter.Viele Grüße,
Roland
-
Für config daten gibt es doch wxConfigFile.
-
Hallo,
ich hab mich letztendlich für wxTextFile entschieden, doch leider bin ich dabei auf ein kleines Problem gestoßen:void MyFrame::OnProject(wxCommandEvent &event) { ProjectDlg* dlg = new ProjectDlg(this,-1); if(dlg->ShowModal() == wxID_OK) { wxTextFile* txt = new wxTextFile(wxT("My.sav")); if(txt->Exists()) { txt->Open(); } else { txt -> Create(wxT("My.sav")); } wxString dummy = wxT(""); wxString str = txt->GetFirstLine(); for(int i = 0; i<4; i++, str = txt->GetNextLine()) { switch(i) { case 0: dummy << dlg->PlayerXpos; break; case 1: dummy << dlg->PlayerYpos; break; //evtl. Art bestimmen default: {};/*cerr << "Error*/ } str = dummy; dummy = wxT(""); txt->Write(); } str = txt->GetLine(5); for(int i = 0; i<4; i++, str = txt->GetNextLine()) { switch(i) { case 0: dummy << dlg->PlayerXpos; break; case 1: dummy << (dlg->Player2Entf - dlg->PlayerYpos); break; default: {};/*cerr << "Error*/ //implementier ich später //default: /*cerr << "Error*/ } str = dummy; dummy = wxT(""); } txt->Write(); } }
Zur Erklärung: In der OnInit() FUnktion lege ich ein wxTextFile namens My.sav an, welches folgende 8 Werte Speichert (jeweils einen pro Zeile):
0 // Player Xpos 0 // Player Ypos Player1 // Player Name Warrior // Player Klasse 0 // Player2 Xpos 1 // Player2 Ypos Player2 // Player Name Rogue // Player Klasse
Jetzt habe ich einen Konfigurationsdialog (OnProject()) geschrieben, in dem der Spieler die X/Y Koordinaten Player1 festlegen kann und den Abstand von Player2 auf Player1 auf der Y-Achse bestimmen kann. Theoretisch soll jetzt der obige Code diese Werte übernehmen und in die anfangs generierte sav Datei schreiben. Name und Klasse werden dabei per default übersprungen und daher beibehalten (daher momentan /*cerr << error*/, weil das noch kommen soll).
Leider passiert rein gar nichts, wenn ich diesen Dialog aufrufe und die Werte veränder.Es wäre klasse, wenn man mir hier nochmal helfen könnte
Beste Grüße,
Filemacher
-
Ein Kernproblem ist wohl, ob ich korrekt in die Datei schreibe, aber ich bin mir nicht sicher.
Es wäre klasse, wenn jemand helfen könnte
-
Dein For-switch sieht etwas komisch aus.
Auch ist mir nicht klar, wie die Daten aus Dummy in der Datei landen sollen.
-
Erstmal danke nochmal für dein vielen Antworten:
Die for-switch berücksichtigt die Struktur einer "Spieler" Klasse. Da diese vier Werte enthält sollen durch die Vier möglichkeiten diese jeweils in eine Zeile geschrieben werden. Da die letzten beiden Werte in diesem Fall unangetastet werden bleiben sollen, werden sie mit default übersprungen (hoffe ich zumindest)
Wie die Daten aus dummy in der Datei landen sollen, weiss ich leider auch nicht genau (ich dachte, in dem ich sie dem str zuweise, aber dass scheint nicht der Fall zu sein).
Welche Möglichkeit gäbe es denn stattdessen?
-
Schreib direkt in die Datei. Vermeide switch Anweisungen sie sind unperformant und schlecht leserlich.
stream << value
Dies steht aber auch alles im Tutorial.
-
Vielen Dank für deine Hinweise.
Im Tutorial habe ich nur nicht verstanden, wie ich z.B. liniengenau Daten änder oder schreibe (bspw. 3. Linie durch "Text2" ersetzen).Sry für meine Newbiefragen
-
In dem du die Datei neuschreibst.
-
erstnochmal danke für deine Geduld beim beantworten meiner Anfängerfragen
Ich habe jetzt doch auf deinen rat gehört, und streams verwendet. Ich habe aber eine Frage (ich hoffe die letzte zum Thema
). Wie kann ich z.B. das dritte Wort der zweiten Zeile lesen und schreiben.
z.B.:out << string1 << ' ' << double1 << ' ' << string2; out << string3 << ' ' << double2 << ' ' << string4;
Ich möchte jetzt einem wxString Mystring den Inhalt von string4 zuweisen.
Gibt es da einen befehl wie:in >> endl; // => geht in zweite zeile; in >> temp1 >> temp2 >> Mystring; //
Und beim schreiben dann:
out << endl; out << temp1 << temp2 << wxT("Ganzwasneues");