Zum Inhalt springen

PL1994

Mitglieder
  • Gesamte Inhalte

    77
  • Benutzer seit

  • Letzter Besuch

Letzte Besucher des Profils

Der "Letzte Profil-Besucher"-Block ist deaktiviert und wird anderen Benutzern nicht angezeit.

  1. Ich habe das nur auf das Wesentliche reduziert. Natürlich muss in der Klasse "Change" noch gespeichert werden, welches Objekt geändert wurde. Da lag nur nicht mein Problem. Das würde ich dann mit Hilfe einer Enumeration machen, deren Member beschreiben, welche Aktion vorgenommen wurde. Eine Variable muss noch den Primärschlüssel speichern. Dann reichen einzelne Integer und Strings völlig und ich brauche nicht Objekte, die den ganzen Datensatz widerspiegeln, in "Change" speichern, obwohl nur ein einzelnes Feld eines Datensatzes geändert werden soll ... Löschen und Einfügen brauche ich nicht, sondern nur die Möglichkeit, eine Aktion rückgängig zu machen. Dafür reichen die Daten aus. Ich wollte nur vermeiden, dass in der Klasse "Value" zwangsläufig immer eine Variable des Wertes "NULL" steht.
  2. Na gut, dann eben anders. Ich werde es wohl jetzt wie folgt machen : #include <ctime> #include <iostream> #include <map> #include <string> using namespace std; class Value { private: enum Type { INTEGER, STRING } type; const int intValue; const string stringValue; public: Value(int value) : type(INTEGER), intValue(value) {} Value(string value) : type(STRING), intValue(NULL), stringValue(value) {} int getIntValue() { return intValue; } string getStringValue() { return stringValue; } }; class Change { private: Value newValue, oldValue; public: Change(Value newValue, Value oldValue) : newValue(newValue), oldValue(oldValue) {} Value getNewValue() { return newValue; } Value getOldValue() { return oldValue; } }; map<time_t, Change> changelog; int main() { changelog.insert(pair<time_t, Change>(time(NULL), Change(Value(1), Value(2)))); changelog.insert(pair<time_t, Change>(time(NULL)+1, Change(Value("string1"), Value("string2")))); for (map<time_t, Change>::iterator i = changelog.begin(); i != changelog.end(); i++) cout << i->first << ": " << i->second.getOldValue().getIntValue() << " -> " << i->second.getNewValue().getIntValue() << " | " << i->second.getOldValue().getStringValue() << " -> " << i->second.getNewValue().getStringValue() << endl; system("pause"); } Das geht prinzipiell zwar, ist aber halt ungünstig, weil bei "Value" immer eine völlig sinnlose Variable gespeichert ist und man später erst mal herausfinden muss, was überhaupt gespeichert werden sollte. Das scheint mir nicht gerade optimal zu sein. Für Verbesserungsvorschläge bin ich also absolut offen EDIT: Nicht fragen, warum da die Variable "type" drin ist. Wollte was anderes versuchen, was aber Quatsch war. Nur vergessen, das rauszulöschen ...
  3. Bevor ich mich mit Smartpointern auseinandersetze, erkläre ich dann wohl erst einmal, was ich mit den Daten vorhabe: Es geht darum, dass der Benutzer zum Beispiel Änderungen an einer TreeView vornehmen kann oder bestimmte Datensätze bearbeitet etc. Diese Daten werden in einer Datenbank gespeichert. Damit jetzt nicht jedes mal, bei jeder noch so kleinen Änderung gleich die Datenbank bearbeitet werden muss, wollte ich ebendiese Änderungen in einem Changelog speichern, um dann, wenn gewünscht, alle auf einmal in die Datenbank zu übertragen. Außerdem sollte man eine Aktion auch noch rückgängig machen können. Diese könnte ich aber bei einer bloßen Änderung an der Datenbank nicht mehr nachvollziehen. Das wären die zwei Hauptfunktionen. Das muss aber eben mit verschiedenen Datentypen gehen ...
  4. Herrlich, das ist besser! Danke nochmal. Aber wie komme ich jetzt hinterher an die Daten aus "Change" wieder heran? Das geht jedenfalls nicht: Change<int> c = (Change<int>)changelog.at(0);
  5. Habe noch etwas anderes ausprobiert. Das geht im Prinzip. Ich kann mir nur fast nicht vorstellen, dass das keine Nachteile mit sich bringen soll: #include <ctime> #include <iostream> #include <map> using namespace std; typedef long Value; class Change { public: Value v1, v2; Change(Value v1, Value v2) : v1(v1), v2(v2) {} }; map<time_t, Change> changelog; int main() { changelog.insert(pair < time_t, Change>(0, Change((Value)"Val1", (Value)"Val2"))); cout << (char*)changelog.at(0).v1 << "\n" << (char*)changelog.at(0).v2 << endl; system("pause"); } Was haltet ihr davon?
  6. Danke dir für die Antwort. Wenn ich das jetzt richtig verstanden habe, meinst du das so: #include <ctime> #include <iostream> #include <map> using namespace std; class AbstractChange { }; class IntChange : public AbstractChange { public: int newVal; int oldVal; IntChange(int newVal, int oldVal) : newVal(newVal), oldVal(oldVal) {} }; class CharChange : public AbstractChange { public: char newVal; char oldVal; CharChange(char newVal, char oldVal) : newVal(newVal), oldVal(oldVal) {} }; map<time_t, AbstractChange> changelog; int main() { changelog.insert(pair < time_t, AbstractChange>(time(NULL), IntChange(0, 0))); } Dann bräuchte ich aber für alle Datentypen eine eigene Klasse, die jeweils eine Änderung von einer Variable dieses Typs behandelt. Das wäre dann noch aufwendiger, als in einer Klasse "Change" von allen Datentypen Variablen für jeweils neu und alt bereitzustellen. Habe ich das falsch verstanden?
  7. Hallo, ich versuche mich gerade an einem Changelog, das, sobald eine Variable eines beliebigen Typs geändert wird, ebendiese Änderung mit einem Timestamp als Key in einer "map" abspeichern soll. Um nicht an einen Datentyp gebunden zu sein, habe ich eine Klasse "Change" als template geschrieben, die jeweils neuen und alten Wert der Variable beinhalten soll (die Variable, auf die sich die Änderung bezieht, wird noch nicht referenziert, was für mein Problem aber auch egal ist). Das ganze nutzt mir natürlich herzlich wenig, wenn ich mich bei der Definition der "map" dann doch auf einen Datentyp festlegen muss. Ich hatte mir das so vorgestellt: #include <ctime> #include <iostream> #include <map> using namespace std; template<class T> class Change { T n; T o; public: Change(T n, T o) : n(n), o(o) {} T getN() { return n; } T getO() { return o; } }; map<time_t, Change< /* ??? */ >> changelog; int main() { changelog.insert(pair < time_t, Change<int>>(time(NULL), Change<int>(0, 0))); } Die mit "???" markierte Stelle ist mein Problem. Kann ich da irgendetwas einsetzen, um den Datentyp, der hinterher tatsächlich verwendet werden soll, noch offen zu lassen oder geht das sowieso nicht? Die einzige Alternative, die mir einfällt, ist "Change" (dann nicht als template) so umzuschreiben, dass die Klasse für alle möglichen Datentypen Variablen für jeweils neu und alt bereitstellt und entsprechende Konstruktoren. Das dürfte aber ziemlich aufwendig werden. Gibt es eine andere (einfachere) Lösung? Gruß PL1994
  8. Wäre möglich ... ja. Wenn ich "string" statt "char*" verwende, sollte es funktionieren (habe es bis jetzt noch nicht an dem richtigen Programm getestet). Danke dir!
  9. Hallo, ich möchte ein paar Datensätze aus einer SQLITE-Datenbank in eine Liste schreiben. Das Auslesen an sich funktioniert, die Liste wird auch initialisiert. Allerdings werden die vorherigen Einträge immer wieder mit dem nächsten Datensatz überschrieben. Die Liste hat am Schluss also die richtige Länge, aber alle Einträge entsprechen dem letzten, der ausgelesen wurde. Hier der Quellcode: list<Country> countriesList; while (sqlite3_step(statements[GET_COUNTRIES]) == SQLITE_ROW) { countriesList.push_back(Country((int)sqlite3_column_int(statements[GET_COUNTRIES], 0), (char *)sqlite3_column_text(statements[GET_COUNTRIES], 1), (char *)sqlite3_column_text(statements[GET_COUNTRIES], 2), (char *)sqlite3_column_text(statements[GET_COUNTRIES], 3))); for (list<Country>::iterator i = countriesList.begin(); i != countriesList.end(); ++i) { Country c = *i; OutputDebugStringA(c.getName()); OutputDebugStringA("\n"); } } sqlite3_reset(statements[GET_COUNTRIES]);Warum klappt das nicht? Gruß PL1994
  10. Danke. Tatsächlich klappt es, wenn WS_DLGFRAME nicht gleichzeitig WS_CHILD ist. Wieso steht dann im MSDN, WS_DLGFRAME habe keine Titelleiste? Es hat nämlich eine, in der der zweite Parameter von CreateWindow() angezeigt wird ...
  11. Hallo, ich möchte ein Dialogfenster für eine Benutzereingabe erstellen. So etwas ist doch grundsätzlich als Dialog Box zu klassifizieren, oder nicht? Typischer Window Style für solche ist laut dieser Seite WS_DLGFRAME. Der nächste Satz lautet aber, ein solches Fenster könne nicht auch eine Titelleiste haben. Unter einer Dialog Box stelle ich mir so etwas vor, also gerade ein Fenster mit Titelleiste. Dieser Style ist aber eigentlich WS_POPUP, das seinerseits aber nicht WS_CHILD des Hauptfensters sein kann (Eine Dialog Box ist doch Child vom Hauptfenster!?). Also: Warum soll der Standard Style für Dialog Boxes keine Titelleiste haben können? Hat es Vorteile, wenn ich mir die Leiste selber da hineinbastele, nur um den adäquaten Style zu verwenden? Wenn der Style für meine Zwecke gar nicht gedacht sein sollte, wofür ist er denn normalerweise vorgesehen? Gruß PL1994
  12. Danke für eure Antworten. Wenn das schlechthin nicht passt, werde ich nicht extra noch ein Framework benutzen, nur um das in MVC hinzubekommen. Entweder versuche ich es dann eben mit der Document-View-Architektur oder als Win32-Applikation ...
  13. Hallo, ich möchte ein Programm gerne nach der Model-View-Controller-Architektur strukturieren. Der Controller erbt dabei von "CWinApp", die View von "CFrameWnd". Das Model ist für mein Problem im Augenblick unwichtig. Mein Problem ist, dass ich es nicht hinbekomme, dass der Controller auf Events, die von der View ausgelöst werden, reagiert. Wenn ich das richtig verstanden habe, sollte man innerhalb einer Message Map des "CFrameWnd" definieren, welche Funktion etwa bei "ON_BN_CLICK" aufgerufen werden soll. Das funktioniert auch glänzend, wenn die entsprechende Funktion Member des "CFrameWnd" ist. Damit wäre sie aber Teil der View, was ja nun gerade nicht der Fall sein soll. Vielmehr sollte die Funktion im Controller definiert sein. Auf eine solche kann ich aber in der Message Map des "CFrameWnd" natürlich nicht verweisen. Ist ja auch im Prinzip richtig, die View soll den Controller nicht kennen. Wie bekomme ich es denn hin, dass mehr oder weniger "vom Controller aus" die Funktionen zu den entsprechenden Events zugeordnet werden? Um das exemplarisch zu verdeutlichen, hier das Notwendigste in ein paar Zeilen Code: #include <afxwin.h> #define ID_OK_BUTTON 1 class View : public CFrameWnd { private: CButton okButton; protected: DECLARE_MESSAGE_MAP() public: View() { Create(NULL, _T("View")); okButton.Create(_T("OK"), WS_CHILD | WS_VISIBLE, CRect(0, 0, 200, 100), this, ID_OK_BUTTON); }; }; class Controller : public CWinApp { private: View *view; afx_msg void onClick(); public: BOOL InitInstance(); }; BOOL Controller::InitInstance() { view = new View(); m_pMainWnd = view; m_pMainWnd->ShowWindow(SW_SHOW); return TRUE; } afx_msg void Controller::onClick() { TRACE("CLICKED"); } BEGIN_MESSAGE_MAP(View, CFrameWnd) ON_BN_CLICKED(ID_OK_BUTTON, /* ??? */) END_MESSAGE_MAP() Controller c;Ist das überhaupt im Ansatz richtig? Funktioniert das mit Message Maps oder muss man das irgendwie anders machen? Gruß PL1994
  14. Danke für deine Antwort. Habe versucht, das Problem durch Erhöhung der Mindestversion zu lösen. Leider bekomme ich trotzdem immer wieder die Angabe der 23px. Wird wohl stimmen, dass Windows dahingehend absichtlich "lügt". Schade.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...