Seite 1 von 1
Vererbung verschiedener QWidgets und deren Findung
Verfasst: 21. März 2011 16:29
von mastershybby
Hallo Forum,
folgende Programmstruktur ist vorhanden:
Mehere Verschiedene QWidgets (also QLineEdit, QSpinbox, Q...) wurden zu SWidgets vererbt (neu SLineEdit, SSpinbox, S....). Gleichzeitig sind diese SWidgets auch von der Klasse Saveme (hat eine reinvirtuelle Funktion save()) abgeleitet. (Dabei ist natürlich zubeachten, dass die Saveme Klasse keine QObject Klasse ist (wegen der Multiple inheritance von QObject)).
So nun Erstelle ich eine Form. In dieser Platziere ich viele verschiedene SWidgets. Auch erstelle ich eine QAction welche ich mit der Funktion Saveall der Form verbinde.
Die Saveall Funktion dient dazu, in sämtlichen SWidgets die Funktion save() aufzurufen.
Und so lautet meine Saveall Funktion:
Code: Alles auswählen
void Form::Saveall(){
foreach(QWidget* w, this->findChildren<QWidget*>()){
if(w->inherits("Saveme")
(Saveme*)w->save();
}
}
nun schmiert mir aber mein Programm ständig ab und gibt ein Rückgabewert von -1073741819 an.
Habe auch ein qobject_cast versucht jedoch geht auch das nicht da die Klasse Saveme keine QObject Klasse ist. Aus dem selben Grund kann ich auch die Suchfunktion "findChildren<Saveme*>()" nicht brauchen.
Kann mir jemand sagen wie ich meine Saveall Funktion gestallten muss, ohne das ich nach jedem SWidget-typ (also SLineEdit etc..) speziell suchen muss?
Vielen Dank
Gruss
mastershybby
Verfasst: 21. März 2011 17:04
von franzf
So etwas ist sehr unschön...
Du musst für alle möglichen QWidgets eine eigene Klasse ableiten (Könnte man sicherlich zur Buildtime automatisieren).
Kannst du mal erklären, was du in save() machst? Möchtest du nur den state in eine ini o.Ä. schreiben?
Hilft dir ads property-system nicht weiter? Du kommst über das metaObject() auf alle properties und kannst diese auslesen, das funktioniert generisch für alle von QObject abgeleiteten Objekte.
Wenn du wirklich was spezielleres machst, würde ich nicht über Ableitung gehen, sondern über templates und deren Spezialisierung. Aber jetzt schaun ma erstmal, obs nicht mit properties zu lösen ist

Verfasst: 21. März 2011 17:22
von mastershybby
Erst mal danke für die schnelle Antwort.
Nun das mit dem automatisieren ist so eine Sache... Dies würde bestimmt gehen, wenn nur eine Ableitung vorliegen würde... aber jedes SWidget hat auch wieder spezifische Funktionen wie z.B. setMultiplicationFactor für das SSpinBox-Widget oder setPath für das SLineEdit-Widget. Somit bleibt mir nichts anderes übrig als jedes QWidget einzeln abzuleiten. Oder?
in der saveroutine erstelle ich einen QString mit der benötigten Information. Natürlich wieder Spezifisch für jedes SWidget. z.B. SSpinBox speichert den MultiplicationFactor sowie den aktuellen Wert. Das SLineEdit speichert den Pfad und den Aktuellen Text.
So kann ich das property-system meiner Meinung nach auch vergessen. Oder irre ich mich da?
Verfasst: 21. März 2011 17:29
von upsala
Es ist ja schön, daß dein Programm abschmiert und dein Kontonummer ausgibt. Aber was sagt dein Debugger dazu? Denn der sollte eine aussagekräftigere Fehlermeldung liefern.
Verfasst: 21. März 2011 19:36
von solarix
upsala hat geschrieben:...und dein Kontonummer ausgibt...
Hoffen wir, dass es nicht der Konto
stand ist..
Zum Problem: Im Grunde sollte dein eingeschlagener Weg schon funktionieren.. es ist zwar nicht der eleganteste, aber der Crash muss trotzdem hausgemacht sein. Also: Debugger anwerfen wie upsala gesagt hat.
Alternativen bieten sich natürlich recht viele:
- Wie franz schon gesagt hat: einfach von aussen die Properties abfragen, Speichern und beim Erstellen der Form wiederherstellen (MultiplicationFactor als Property implementieren)
- Im Grunde müsste nicht einmal abgeleitet werden.. du könntest die "saveInternalState()"-Methode als Slot implementieren und dann rufst du von aussen mit "invokeMethod" einfach alle "saveInternalState()"-Slots auf. Das ist dann allerdings auch kein schönes OOP..
- OOP bietet vermutlich auch was zu diesem Thema. Ich habe das noch nie so angewendet, aber vermutlich liesse sich mit dem Memento-Pattern was schönes machen.
Aber den Crash solltest du schon zuerst in den Griff kriegen.. denn gerade bei der Memento-Variante landest du am Ende doch wieder bei einer gemeinsamen Baseclass..
btw:
mastershybby hat geschrieben:...
Wir programmieren in Qt mit C++.. da gibt's "dynamic_cast" & CO
hth!
Verfasst: 22. März 2011 07:20
von franzf
mastershybby hat geschrieben:aber jedes SWidget hat auch wieder spezifische Funktionen wie z.B. setMultiplicationFactor für das SSpinBox-Widget oder setPath für das SLineEdit-Widget.
Bitte genauer: ist multiplicationFactor nur ein anderer Name für value, oder wird der Wert in der Spinbox nach dem Editieren mit diesem Factor multipliziert?
Ist path das was im lineedit angezeigt wird, oder wird der irgendwie mit dem Inhalt des LineEdit verkuddelmuddelt?
Prinzipiell ist Ableiten nicht die einzige Möglichkeit, Funktionalität hinzuzufügen. Komposition ist eine andere. Wenn nicht etwas fundamentales geändert wird, sondern nur mit der öffentlichen Schnittstelle minimal der Funktionsumfang erweitert wird, ist mMn. Ableiten nicht gerechtfertigt. Ableiten ist kein Mittel, um Schreibarbeit zu sparen.
Verfasst: 22. März 2011 08:46
von mastershybby
@ upsala:
Na da hab ich mit dem Debugger aber andere erfahrungen gemacht... bis jetzt gab und gibt der mir immer nur das gleiche zurück: Segmentation Fault. Signal SIGSEGV.
@solarix:
-Wie kann ich denn eine Neue Property implementieren ohne das QMetaObject zu verändern? Soviel ich verstanden habe sind die Properties allesamt im QMetaObject.
-Ums Ableiten komm ich nicht rum.. hab noch weitere Funktionen die ich implementieren muss... Diese sind jedoch für mein Problem nicht relevant.
-Memento-Pattern noch nie von gehört... werde mich mal schlau machen...
btw. hab mich bereits gewundert, dass nicht schon früher jemand was zu mienem "unsauberen" oder einfach C-basierten casting was sagt. Bin mir natürlich bewusst das wir in C++ sind und kann dich da aber auch gleich versichern... auch mit dem dynamic_cast & CO schmierts ab...
@franzf:
Sorry mein Fehler...
ja mit dem multiplicationFactor wird der Wert ind er Spinbox nach dem Editieren noch multipliziert.
Und der path wird nach dem editieren vor oder/und nach den inhalt des LineEdits geschrieben...
Ist mir klar das auch Kompositionen möglich sind. Jedoch müsste ich auch da QLineEdit und QSpinBox ableiten um die Komposition zu erstellen oder?
Verfasst: 22. März 2011 09:12
von solarix
mastershybby hat geschrieben:@ upsala:
Na da hab ich mit dem Debugger aber andere erfahrungen gemacht... bis jetzt gab und gibt der mir immer nur das gleiche zurück: Segmentation Fault. Signal SIGSEGV.
Der Debugger gibt "nichts zurück", sondern der hält das Programm an. Ich weiss nicht wie du arbeitest (creator, eclipse, gedit, ..) aber so ganz in Kürze:
1. Debug-Variante erstellen, indem in der pro-File "CONFIG += debug" hinzugefügt und alles neu erstellt wird (make distclean; qmake; make) (Beim Compilen findest du nun u.A. "-g" als Argument)
2. Das Programm im Debugger laden: "gdb meineBinary"
3. Das Programm starten (Kommando "run")
4. Beim Crash schauen, wo das Programm steht (Kommando "where")
mastershybby hat geschrieben:
@solarix:
-Wie kann ich denn eine Neue Property implementieren ohne das QMetaObject zu verändern? Soviel ich verstanden habe sind die Properties allesamt im QMetaObject.
Nein, musst du nicht.. das steht alles unter
http://doc.qt.nokia.com/4.7/properties. ... rty-system
Der Zugriff zur Laufzeit erfolgt über das QMetaObject, aber deklariert wird es ganz normal in deiner (QObject-)Klasse.
mastershybby hat geschrieben:
auch mit dem dynamic_cast & CO schmierts ab...
Das glaube ich dir gerne, aber wenn dynamic_cast & CO zum Crash führen, hilft der C-Cast ganz sicher nicht weiter
mastershybby hat geschrieben:
Ist mir klar das auch Kompositionen möglich sind. Jedoch müsste ich auch da QLineEdit und QSpinBox ableiten um die Komposition zu erstellen oder?
Ja, ableiten schon, aber dann brauchst du keine multiple Vererbung mehr.
hth..
Verfasst: 22. März 2011 09:15
von franzf
mastershybby hat geschrieben:Na da hab ich mit dem Debugger aber andere erfahrungen gemacht... bis jetzt gab und gibt der mir immer nur das gleiche zurück: Segmentation Fault. Signal SIGSEGV.
Das sagt dir die runtime ja auch schon. Was aber der Debugger kann: Einen Backtrace angeben, der dir die letzten Funktionsaufrufe anzeigt und insbesondere den letzten, entscheidenden Aufruf, der dein Programm crasht.
-Ums Ableiten komm ich nicht rum.. hab noch weitere Funktionen die ich implementieren muss... Diese sind jedoch für mein Problem nicht relevant.
Meinst du damit deine "setPath()" usw? Wenn noch mehr dazu kommt - bitte mal komplette Anforderungsliste posten, damit man nicht nebulös rumfantsieren muss
Bin mir natürlich bewusst das wir in C++ sind und kann dich da aber auch gleich versichern... auch mit dem dynamic_cast & CO schmierts ab...
Wenn du ihn richtig einsetzt nicht! dynamic_cast gibt NULL zurück, wenn der cast scheitert (bei pointern, beim casten von Referenzen gibts ne Exception). Nur den return abfragen, dann hört der Crash auf.
Ist mir klar das auch Kompositionen möglich sind. Jedoch müsste ich auch da QLineEdit und QSpinBox ableiten um die Komposition zu erstellen oder?
Für Komposition muss man eben NICHT ableiten.
Ableitung ist eine extrem starke Bindung, die bei reiner Verwendung des öffentlichen Interfaces in der Ableitung vermieden werden sollte, vor allem wenn nicht wirklcih Polymorphie verwendet wird (du implementierst keine der virtuellen Funktionen).
Komposition == Zusammensetzung.
So könnte das aussschauen:
Code: Alles auswählen
class LineEditWrapper : public QObject
{
Q_OBJECT
QLineEdit* lineEdit_;
QString path_;
QString originalText_;
public:
LineEditWrapper(QLineEdit* le, QObject* parent=0)
: QObject(parent)
, lineEdit_(le)
{
connect(le, SIGNAL(returnPressed()), SLOT(updateLineEdit()));
}
public slots:
void setPath(QString const& p) {
path_ = p;
}
private slots:
void updateLineEdit() {
originalText_ = le->text();
le->setText(path_+ "/" + originalString_);
}
};
Vorteil:
Du kannst deine Gui ganz normal gestalten (z.B. designer), und erst nachträglich an passender Stelle die Wrapper setzen. Die Schreibarbeit ist die selbe, nur hast du deine Abhängigkeiten minimiert und Zuständigkeiten besser delegiert.
Verfasst: 23. März 2011 15:10
von mastershybby
@ solarix:
nun ich arbeite mit dem QTCreator dabei hab ich den Debugger schon mehrmals gestartet aber hab dessen Funktion noch nicht in den Griff gekriegt. Werde mich mal genauer in diesen Einarbeiten...
Auch das implementieren der Properties muss ich weiter verfolgen...
Vielen Dank für deine Hilfe werde mich bei Problemen nochmals hier melden.
@franzf:
ok so hab ich die Komposition nicht erwartet... hätte ich eigentlich schon früher drauf kommen müssen! Ich werde meinen Code jetzt zuerst mal versuchen über genau solche Kompositionen aufzubauen. Vielen dank für das öffnen meiner Augen!
Wie bereits gesagt werde ich mich bei weiteren Problem wieder melden (allerdings kann das jetzt mit dem umschreiben eine weile dauern).
Verfasst: 23. März 2011 15:37
von franzf
mastershybby hat geschrieben:Ich werde meinen Code jetzt zuerst mal versuchen über genau solche Kompositionen aufzubauen. Vielen dank für das öffnen meiner Augen!
Versuchs erst mal im Kleinen. Also minimale Gui, an der du ALLE deine gewollten Features austestest. Vielleicht auch im Vergleich zu deiner jetzigen Lösung. Evtl. funktioniert nicht alles so wie du willst, und bevor du dein ganzes großes Projekt umkrempelst und erst spät merkst, dass Feature XYZ nicht geht, hast du ein Problem

Und Fragen jederzeit

Verfasst: 25. März 2011 11:42
von RHBaum
Was mich noch intressiert ....
Alle "Controls" sind QObject-Ableitungen. Nun willst DU den Zweig noch mal zusammenfuehren zu Saveme zusammenführen um Ihn dann gleich wieder aufzudrieseln ?
Wie das funktionieren soll, keine Ahnung ... ist SaveMe nen Template ???
Ciao ...