QT und Templates
-
Ich suche doch nicht danach. Ich habe mein Backend und da ist das mit der Schnittstelle genau so definiert. Da kannst Du auch jedes policy-based-design nehmen und hast die gleiche Schnittstelle. Also ich kann mir da viele Anwendungsmöglichkeiten vorstellen. Backend hat Templates -> will ich darstellen. Wenn das unrealistisch ist, dann ist es unrealistisch, dass man Templates in C++ nutzt.
Oder was missverstehe ich hier?
Nochmal: Ich suche die Möglichkeit im UI verschiedene Ausprägungen (definiert durch Templateargumente) eines Templates darzustellen, deren Templateklassen dieselbe Schnittstelle definieren, wobei das Anzuzeigende vom gleichen Typ (std::string) für alle Templateklassen ist und es deswegen für die UI-Klasse kein Problem ist, auch die gesamte Palette der Templateklassen zu akzeptieren.
Und ja, manche Templateklassen haben spezielle Methoden. Daher gehört die UI-Klasse ja teilweise auch spezialisiert - das betrifft aber nur wenige Methoden.
-
Vielleicht kann man das Problem mit einem anderen Beispiel illustrieren. Sagen wir meinetwegen, dass ich als Daten wirklich einfach nur vector<int> und vectorstd::complex habe. Nehmen wir jetzt meinetwegen zur Darstellung eine QListView, dort soll für den int-vector in jeder Zeile eine Zahl und bei der complex-Variante für jede Zeile die Vektorschreibweise für complex zur Anzeige genutzt werden.
Dann ist die View natürlich "enttemplatisiert", da die Datenbefüllung ja über einen Erben von QAbstractListModel stattfindet.
Aber das verschiebt das Problem ja nur: Wie löse ich das Problem, dass QAbstractItemModel beide vector zur Anzeige gestattet?
Variante 1 wäre z.B.:
class VectorModelBase : public QAbstractListModel { // definiert alles, was sowohl für vector<int> als auch vector<complex> klappt }; class IntVectorModel : public VectorModelBase { // implementiert Methoden entsprechend des int-Parameters anders }; class ComplexVectorModel : public VectorModelBase { // implementiert Methoden entsprechend des complex-Parameters anders };
Logischer erscheint mir aber doch Variante 2, durch die wir noch mehr in die Base stecken können:
template<typename VectorT> class VectorModelBase : public QAbstractListModel { // wie oben, aber jetzt kann auch std::vector<VectorT>* ein Attribut sein (oder wenn wir Controller/Model zusammenlegen, meinetwegen auch ohne *) // Vorteil: In der obigen Variante haben wir immer noch viel Code doppelt, der einfach auf vector<T> zugreift, // obwohl T hier für mancherlei Zugriff egal ist (kombinierbar mit CRTP, keine Frage) }; class IntVectorModel : public VectorModelBase<int> { // Doppelcode fällt heraus, nur vector<int>-spezifischer Code ist notwendig }; class ComplexVectorModel : public VectorModelBase<complex> { // ibid. };
Obiges Modell ist vereinfacht. Feedback dazu hilft mir mit hoher Wahrscheinlichkeit auch in meinem Fall weiter.
Mein tatsächlicher Anwendungsfall ist jetzt nur insofern anders, dass ich View und Model (bzw. in einem strikteren Sinne imo Controller) nicht trenne, weil diese Trennung in meinen Augen nur dann Sinn ergibt, wenn man einen Controller für unterschiedliche Views nutzen möchte, was in meinem Fall ausgeschlossen erscheint (vll. bin ich zu kurzsichtig; und natürlich gibt es für meinen Fall von QT kein Model). Daher fällt der Template-Parameter eben direkt aufs View an und nicht auf ein dazwischen geschobenes Model.
Kann man damit besser arbeiten? Auch die Frage meine ich ernst, da ich ja sehe, wie schwer meine Abstraktionen verständlich zu sein scheinen.
-
Also erstnoch mal die Bemerkung, dass Templates nicht mit dem Moc funktionieren, du könntest evtl mit einer Basisklasse Dinge vererben...
... ich bin aber der Meinung, das es viel besser ist für UI zu daten die hat-ein beziehung zu wählen, als die ist-ein.
Zurück zum Model, die Schnittstelle mit der dort Datenabgefragt werden ist:
QVariant data(const QModelIndex &index, int role) const
index.row() wäre jetzt der Index von deinem vector. Index.column würde die Spalte angeben, hier wohl immer 0.
Um hier in dein Backend sinnvoll zu kommen, würde ich obiges Interface etwas umbauen, und mit std/boost::function als Callback verwenden.
Die Klasse auf die der Callback zeigt, kann dann in deinem Backend den richtigen String/Variant zurückgeben.
-
phlox81 schrieb:
Also erstnoch mal die Bemerkung, dass Templates nicht mit dem Moc funktionieren, du könntest evtl mit einer Basisklasse Dinge vererben...
Wobei der moc AFAIK nur notwendig ist, wenn die Klasse entweder signals/slots definiert oder übers meta object system von Qt angesprochen werden soll.
-
Ja, dass das so nicht geht, ist klar, dafür ja die Lösung im OP. Die Begründung für hat-ein statt ist-ein basiert auf den üblichen Daumenregeln dafür? Oder gibt es dafür im MVC-Umfeld noch ein paar zusätzliche Argumente? Im Grunde genommen hast Du aber schon Recht...
Um hier in dein Backend sinnvoll zu kommen, würde ich obiges Interface etwas umbauen, und mit std/boost::function als Callback verwenden.
Oh, darüber muss ich Mal nachdenken. Wenn das so funktioniert, ist der Vorteil, dass ich die Abhängigkeiten (ob Klasse->Klasse durch Beziehungen oder Template-Argumente) massiv minimiere, richtig?
Wie löse ich jetzt Validierungsfunktionen, wenn man die Listenelemente abändern können soll? Da benötige ich ja ein neues std::function.
Nächste Verkomplizierung:
Im selben Dialogfenster werden die Daten über kommaseparierte Werte im QLineEdit dargestellt. D.h. für ein vector<int> erhalte ich z.B. "10,20,30,40" und für ein vector<complex> "(10,5),(20,7),(30,9)". Auch hier benötige ich dann ja zwei std::function (für Text aus Backend ziehen und Text validieren).Lässt sich Dein Vorgehen nicht irgendwie abstrahieren? Also nutzt Du grundsätzlich immer und überall std::function, wenn man es damit abbilden kann, sodass Du die Abhängigkeiten einfach so gering wie möglich hältst? Ich müsste an vielen Stellen, um mein eigentliches Verhalten zu simulieren, meistens 2 (wie oben dargestellt) oder sogar noch mehr std::function einbauen. Und irgendwie wirkt das auf mich dann immer gefrickelt, wobei der Vorteil durchaus ist, dass man die Abhängigkeiten gering hält.
Es gibt doch sicher Schwellen, ab denen man bei x std::function-Objekten sagt: Ne, jetzt darf das Model auch Mal abhängig vom abzubildenden Typ sein, oder?
-
@Eisflamme: Wenn du die bestehenden Views von Qt verwenden und nicht einen komplett eigenen View bauen möchtest, kommst du um ein Model nicht herum. Die ganzen Views in Qt sind auf das Model-View Konzept ausgelegt.
Ist die Darstellung in einem ListView readonly oder soll der Benutzer auch Werte Ändern können?
Und wenn der Benutzer Werte ändern können soll? Wie soll die Eingabe aussehen?
z.b. für dein Vector<int> variante soll der Benutzer beim editieren im View ein Textbox oder eine NumericTextbox (mit optional spinner controls) sehen?
Wobei zweiteres zu bevorzugen wäre, weil du dann direkt wieder ein int vom view bekommst.
Für die konkrete Darstellung in einem View (egal ob readonly oder im edit modus) sind in Qt sogennante delegates verantwortlich, welche einem View mitgegeben werden.
Falls du das ganze Model-View konzept von Qt nicht kennen solltest, aus der Docu von Qt4 über Model-View: http://qt-project.org/doc/qt-4.8/modelview.html
-
Das Model-View-Konzept sowie Delegates sind mir bekannt. Leider beantwortet das nicht meine Fragen im vorherigen Post.
Wie bereits mehrfach erwähnt und auch erläutert: Ob ich jetzt (wie in Deinem Link auch beschrieben) Model und View trenne oder der View die Daten innerhalb des Views verwendet, ändert überhaupt nichts an meinem Problem, wie ich die Abhängigkeiten zwischen View (oder Model) und meinem Backend gestalte. Trotzdem bin ich mittlerweile davon überzeugt, dass man sich dann eben für nicht-triviale Daten ein eigenes Model (QT-Terminologie) bauen sollte, da habt ihr ja Recht.
Zudem gibt es für QLineEdit kein Model von QT, somit muss ich hier für eine konsequente Umsetzung ein eigenes schreiben.
Ansonsten fände ich etwas stärkeren Bezug zu meinem letzten Beitrag super.
Und wenn der Benutzer Werte ändern können soll? Wie soll die Eingabe aussehen?
Ja, sind änderbar und zwar in Textform, weil die Zahlen ja wieder nur eine Vereinfachung sind und wir für den Spezialfall der Zahlen zwar jetzt eine etwas umständlichere Lösung hätten, die sich aber leichter auf mein eigentliches Szenario übertragen lassen.
Die Frage, die sich hier stellt, wäre dann ja wieder: Darf der Delegate die Backend-Klassen wirklich kennen oder soll er auch wieder nur über std::function mit denen kontaktieren? (Änderbarkeit [=Validierung] + Auslesen erfordert dann zwei std::function; wird bei mir aber vermutlich wieder auf mehrere hinauslaufen)
-
Hab ich was falsch/zu wenig formuliert? Wenn ihr mir nicht antworten könnt, weil ich es nicht deutlich genug schreibe, gebt mir bitte darauf Rückmeldung.
Die einzige Konsequenz aus dem Thread ist bisher für mich wieder, dass ich Zweifel an meinem Design habe, weil ihr es nicht schön findet/versteht... Aber gut, Abhängigkeiten geringer halten als ich es mit dem Template tue ist ja eine Grundrichtung, die ich verstehe. Ich werde selbst überlegen, ob es mit weniger Abhängigkeit geht - oder ob eben nicht.
-
Also für diesen Beitrag sag ich nochmal vorneweg, dass die QT-Models im MVC-Sinne ja eigentlich nur als Controller zu gebrauchen sind (siehe auch: http://stackoverflow.com/questions/5543198/why-qt-is-misusing-model-view-terminology )
Tja, nächste Sache: Wenn ich die Modelklassen von QT nicht verwende(n kann), weil das jeweilige "View"-Objekt von QT (bzw. Widget, ist ja deren selbsternannte andere Klasse von Widgets) zu keinem Model passt (und setModel nicht anbietet), wie soll ich dann überhaupt eine Controller-Zwischenschicht erschaffen?
Ich finde immer noch, dass bei View : Controller 1:1 es unnötig ist hier zu separieren, zumal wir das Problem haben, dass wir den Controller irgendwo speichertechnisch verwalten müssen. Möglich wäre:
class LineEditView : public QLineEdit { public: // ctor void setModel(AbstractLineEditModel* model); // Eigenkreation };
, wobei AbstractLineEditModel jetzt alle möglichen Slots anbietet. Somit kennt der View nur indirekt den Controller. Dass er dennoch die abstrakte Klasse kennt, finde ich jedoch etwas unschön, aber das wäre zumindest eine Variante. Und die Speicherverwaltung wäre damit auch abgedeckt, wenn LineEditView den Besitz übernimmt.
Es erscheint somit sinnvoll bei 1:1 einfach z.B. ein VectorLineEdit (für meinen Fall) von QLineEdit erben zu lassen mit folgenden Vorteilen:
- wir wissen, "wohin" mit VectorLineEdit, da es einfach als View-Objekt mit impliziertem Model erstellt wird
- da der View in QT sein Model ohnehin besitzt (obwohl nicht die spezielle Klasse, wohl aber die abstrakte kennt), haben wir Laufzeit/Speicherverwaltung kongruent zu sonstigen QT-Views nebst -Models
- Konkrete Nachteile konnte keiner benennen; die Nachteile, die ich sehe, liegen darin begründet, wenn man den Controller für einen anderen View nutzen könnte, was hier entfälltSomit haben wir eben QLineEdit bzw. den Erben, der View und Controller kombiniert. Für den könnte ich jetzt sogar noch drei std::function-Objekte nutzen. Die kombiniere ich dann aber doch besser als struct, die übergeben wird, ist flexibler, falls ich noch mehr brauche, oder?
Das QLineEdit befindet sich aber im Dialog. Und von welchem Objekt ich die function-Objekte erstelle, hängt davon ab, was der Dialog erhält, da auch der nur kennend (nicht besitzend) mit einem vector<?>-Objekt verbunden ist und daher ein Template wäre.
Oder ich übergebe die drei std::function-Objekte (bzw. die Struktur, s.o.) an den Dialog bereits. Im Dialog gibt es jedoch auch andere Views, welche den vector<?> nutzen (davon selbstgestaltete grafische Teile, die also auch kein QT-Model gebrauchen können) - auch dafür müsste ich dann std::function-Bulks mitliefern.
Dafür spare ich mir beim Dialog den Templateparameter. Aber - was genau nützt mir das? Im Grunde soll der Dialog flexibel erweiterbar bleiben, er kennt nur die darzustellende Klasse und kann Views flexibel darauf aufbauen, was dort angezeigt werden soll. Möchte ich dort einen neuen Viewtyp hinzufügen, bräuchte ich also wieder einen neuen std::function-Bulk und somit würde jeder Nutzer des Dialogs wieder die ganzen std::function-Objekte basteln müssen. Das soll aber den Nutzer gar nicht interessieren, also da gehört es nicht hin.
Wenn aber der Dialog template ist, könnte er wunderbar den Templatetypen an das Textfeld und die grafische Anzeige weitergeben, wenn er die ja eh hat. Dafür müssten die wieder template sein, finde ich aber eigentlich nicht so wild. Die werden eh niemals von jemandem genutzt, der als darzustellenden Typen etwas anderes angeben möchte.
Somit erscheint die Lösung alles zu templatisieren hier am angebrachtesten, ich denke, das war jetzt auch nachvollziehbar argumentiert.
-
Eisflamme schrieb:
Also für diesen Beitrag sag ich nochmal vorneweg, dass die QT-Models im MVC-Sinne ja eigentlich nur als Controller zu gebrauchen sind (siehe auch: http://stackoverflow.com/questions/5543198/why-qt-is-misusing-model-view-terminology )
Wo siehst du in den Qt-Models (Abgeleitet von QAbstractItemModel) Controller Funktionalität?
Ich sehe da keine. Die Models an sich stellen die Daten über eine definierte Schnittstelle bereit.
In Qt ist es eher so, dass View und Controller oft(immer?) eine Entität darstellen.
-
Na ja, dafür der verlinkte Beitrag, dem ich nur 100% zustimmen kann: Der Witz an MVC ist, dass das Model unabhängig vom UI(-Framework) ist. Wenn QT mir aber das Model stellt, ist das eben nicht der Fall. Oder wie soll ich mein eigentliches Model jetzt noch in einer Konsolenanwendung oder als Basis für eine Handy-App wiederverwenden?
Daher taugen die QT-Models nur dazu zwischen eigentlichem Model zu vermitteln. Wer aber zwischen Model und View vermittelt, wird üblicherweise Controller genannt. So ist die Terminologie logisch.
Edit:
Wobei, eigentlich ist es so auch nicht logisch. VCs sind schon irgendwie verschmolzen, je nachdem, wie man ein View halt definiert. Aber das, was als Model bezeichnet wird, ist dann eben ein Controller auf anderer Ebene. Oder man definiert Model wirklich so wie von QT, aber dann muss man zwangsläufig die Applikationslogik nochmal auf einen Bereich vor dem Model schieben, somit hätten wir also 4 "Arten von Komponenten". Denn zusätzlich zum M(V)C-Konzept von QT sollte man sein "eigentliches" Model/Backend imo als von QT unabhängigen Teil modellieren. Ich finde es unsauber (und man ärgert sich wie ich auch einfach), wenn man nicht einen auslagerbaren Teil QT-unabhängig entwickelt.Aber wie gesagt, verlinkter Beitrag argumentiert das ebenfalls. Ist ne Frage der Ebene, aber vermutlich gab es hier wegen meiner QT-unüblichen Beschreibung einige Missverständnisse.
-
klar kannst du auch Qt models in konsolen programmen verwenden...
Und nur weil es auf stackoverflow was steht muss es nicht heißen dass es korrekt ist...
Und Qt != Gui. Qt ist ein "komplettes" Application Framework wo die Gui nur ein kleiner Teil davon ist.
Ich glaube so langsam trifften wir vom eigentlichen problem komplett ab...
Und ich denke das wir aneinander vorbei reden, da auser dir vermutlich keiner weis was du eigentlich vor hast. Zu mindestens geht es mir so.
Also beschreib bitte genau was du eigentlich vor hast. Und mir geht es dabei um das Prinzip/Idee.
-
Eisflamme schrieb:
Der Witz an MVC ist, dass das Model unabhängig vom UI(-Framework) ist.
Im Grunde ja. Aber das model muss eine wohl definierte Schnittstelle bieten, damit ein View oder Controller auch unabhängig einer konkreten model instanz/Implementierung funktionieren kann.
Und wenn du verschiedene "Frameworks" mischt so bleibt es nicht aus, dass du Adapter Objekte erstellen musst.
Und da Qt auch entsprechende Views bereitstellt, definiert es auch eine entsprechende Schnittstelle (in form von QAbstractItemModel).
Eisflamme schrieb:
Wenn QT mir aber das Model stellt, ist das eben nicht der Fall. Oder wie soll ich mein eigentliches Model jetzt noch in einer Konsolenanwendung oder als Basis für eine Handy-App wiederverwenden?
Qt an sich stellt dir in erster Hinsicht nur eine definierte Schnittstelle bereit. Und die im Qtgui(qt4)/qtwidget(qt5) bereitgestellten Views verwenden diese Schnittstelle.
Eisflamme schrieb:
Daher taugen die QT-Models nur dazu zwischen eigentlichem Model zu vermitteln. Wer aber zwischen Model und View vermittelt, wird üblicherweise Controller genannt. So ist die Terminologie logisch.
Sehe ich nicht so. Laut der Definition die ich kenne hat ein View lesenden zugriff auf das Model. Nur über den Controller können Änderungen am Model vorgenommen werden (z.b. um Input Validierung zu ermöglichen).
Quellen:
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
http://msdn.microsoft.com/en-us/library/ff649643.aspxDie Qt-Models (Abgeleitete Klassen von QAbstractItemModel) an sich sind Models. QAbstractItemModel definiert nur die Schnittstelle.
In Qt sind View und Controller eine Entität. Und dadurch ist das Model-View Framework in Qt eher eine MVC Ausprägung namens ModelDelegate
Eisflamme schrieb:
Edit:
Wobei, eigentlich ist es so auch nicht logisch. VCs sind schon irgendwie verschmolzen, je nachdem, wie man ein View halt definiert. Aber das, was als Model bezeichnet wird, ist dann eben ein Controller auf anderer Ebene. Oder man definiert Model wirklich so wie von QT, aber dann muss man zwangsläufig die Applikationslogik nochmal auf einen Bereich vor dem Model schieben, somit hätten wir also 4 "Arten von Komponenten". Denn zusätzlich zum M(V)C-Konzept von QT sollte man sein "eigentliches" Model/Backend imo als von QT unabhängigen Teil modellieren. Ich finde es unsauber (und man ärgert sich wie ich auch einfach), wenn man nicht einen auslagerbaren Teil QT-unabhängig entwickelt.Aber wie gesagt, verlinkter Beitrag argumentiert das ebenfalls. Ist ne Frage der Ebene, aber vermutlich gab es hier wegen meiner QT-unüblichen Beschreibung einige Missverständnisse.
Ich denke auch das hier Missverständnisse auf beiden Seiten entstanden sind.
Das Model-View Framework in Qt stellt ein paar Views bereit und definiert eine Grundlegende Schnittstelle über welche die Views mit einem Model kommunizieren können. Zusätzlich werden halt schon für ein paar oft genutzte Fälle konkrete Model Implementationen zusätzlich von Qt bereitgestellt.
Wenn du bestehende Views von Qt (und damit sind nicht irgendwelche widgets gemeint) verwenden möchtest/musst, so musst du dich an die definierte Schnittstelle halten.
Aber es spricht nichts dagegen im Backend komplett ohne Qt zu arbeiten. Wobei mit Qt 5.2 (mit 5.1 nur Android) auch komplette Smartphone Apps entwickelt werden können.
-
Okay, was Du so schreibst, ist alles in sich schlüssig und ich stimme einem großen Teil auch zu. Der einzige Unterschied ist: Wenn man bei QT den Modelteil wirklich als Model akzeptiert, impliziert das einige Dinge, denen ich widersprochen haben, weil das nach meiner Modeldefinition nicht korrekt ist.
Aber meine Definition ist auch nur eine von vielen, ich bin da jetzt etwas offener und sehe schon, dass man das unterschiedlich definieren kann. Macht die Diskussion leider mühselig, aber die Literatur zum Thema ist ja nicht besser.
Jedenfalls habe ich mein eigentliches Problem ja bereits gelöst. Wenn man so möchte, habe ich bei mir sogar MVC verschmolzen (was aber bei QT-Definition ohnehin für jedes Widget, welches nicht View/Model unterstützt der Fall ist), wobei mein eigentliches Backend (also QT-unabhängig, somit noch vor Model) eben Template ist.
Möchte ich im QT-UI entsprechend die Templateklassen darstellen, dann sollte das Widget meiner Meinung nach auch template sein. Alternativvorschläge hier im Thread basieren ja nur auf std::function, was aber nur dann ginge, wenn meine Backend-Klassen so einfältig wären, dass dort nur Text gelesen und gesetzt würde.
Tatsächlich werden über 5 verschiedene, je schreibende und lesende Methoden aufgerufen, was einfach eine Abhängigkeit vom Widget zu meinen Templateklassen als deutlich intuitiver erscheinen lässt. Kenntnis von Templateklassen erfordert aber eben, dass mein Widget selbst template wird. Und das ist auch völlig logisch und sauber in meinem Design.
Kritik dazu nehme ich gerne mit sachlichen (und nicht für mich leider unnachvollziehbaren Erfahrungsargumenten) entgegen, aber anscheinend haben sich die meisten hier ja wie so oft ohnehin zurückgezogen, als ich die Schwachpunkte deren Lösungen oder Nachfragen Mal ins Feld geführt hab.
Dennoch vielen Dank und beste Grüße!
-
Eisflamme schrieb:
Tatsächlich werden über 5 verschiedene, je schreibende und lesende Methoden aufgerufen, was einfach eine Abhängigkeit vom Widget zu meinen Templateklassen als deutlich intuitiver erscheinen lässt. Kenntnis von Templateklassen erfordert aber eben, dass mein Widget selbst template wird.
Das ein Widget auch ein template sein muss, da es ein Klassentemplate als member referenziert ist falsch. Es mag vielleicht deiner Meinung so sein.
Da du meine Frage nicht beantwortet hast... hier noch einmal etwas abgewandelt:
Wie genau sieht dein Model Konzeptionell aus?(keine konkrete Implementation)
Und wie steht das UI-Element dazu in Beziehung?
-
@firefly: das seh ich anders. Die QAbstractItemModels von Qt sind für mich auch eher Controller. Das sind keine "Modelle". Ich werde meine Logik sicher nicht in Form von QAbstractItemModel definieren, wo ich über Indizes und QVariants auf die Daten zugreife. Das eigentliche Modell besteht aus stark typisierten Klassen, wie Person, AddressBook und was weiß ich was. Das wäre das Modell.
Eine QAbstractItemModel Ableitung, die darauf zugreift, ist nur eine Zwischenschicht. Man kann darüber streiten, ob man sie als Modell oder Controller bezeichnet. Es wäre für mich aber sicher nicht das Modell in dem Sinne von MCV wenn man die gesamte Anwendung betrachtet. Vielleicht sowas wie das ViewModel beim MVVM von Microsoft. Ich seh aber auch kein Problem damit, das QAbstractItemModel als Controller zu bezeichnen.
-
@Eisflamme: ja, ich finds immer noch etwas schwierig, mir konkret vorzustellen, was du willst. Vielleicht kannst du mal ein einfaches Beispiel mit zwei konkreten Modell Klassen und der entsprechenden UI machen, wie du dir das vorstellt und was du da gemeinsam verwenden willst? Also, wirklich ein Beispiel wo man sieht, was die Klassen für Daten beinhalten und wie du die View wiederverwenden willst.
Deinen Vergleich mit Policy Based Design kann ich nicht wirklich nachvollziehen. Beim Policy Based Design geht es meist um grundlegende Sachen, z.B. SmartPointer und Speicherverwaltung. Das ist etwas, was bei so gut wie jeder Klasse Sinn macht. Du hingegen willst die GUI über Templates für verschiedene Klassen wiederverwenden, und das ist etwas, was schon wieder sehr sehr selten zusammenpasst. Es würde mir wahrscheinlich echt schwerfallen, in unserer Software zwei Klassen zu finden, wo man das anwenden könnte.
-
Mechanics schrieb:
@firefly: das seh ich anders. Die QAbstractItemModels von Qt sind für mich auch eher Controller. Das sind keine "Modelle". Ich werde meine Logik sicher nicht in Form von QAbstractItemModel definieren, wo ich über Indizes und QVariants auf die Daten zugreife. Das eigentliche Modell besteht aus stark typisierten Klassen, wie Person, AddressBook und was weiß ich was. Das wäre das Modell.
Eine QAbstractItemModel Ableitung, die darauf zugreift, ist nur eine Zwischenschicht. Man kann darüber streiten, ob man sie als Modell oder Controller bezeichnet. Es wäre für mich aber sicher nicht das Modell in dem Sinne von MCV wenn man die gesamte Anwendung betrachtet. Vielleicht sowas wie das ViewModel beim MVVM von Microsoft. Ich seh aber auch kein Problem damit, das QAbstractItemModel als Controller zu bezeichnen.WO siehst du in QAbstractItemModel COntroller funktionalität?
Was du beschreibst ist eher eine Adaption eines bestehenden "Models" an die Model-View Infrastruktur von Qt (Um bestehende Views von Qt verwenden zu können).
Und das ist nicht der einzige zweck von QAbstractItemModel...
Was nützt dir stark typisierte "Models", wenn du dann für jedes Model einen eigenen View erstellen musst? (da die Anzahl der "Properties" unterschiedlich sein können)
Oder wie meinst du da ein allgemeine Schnittstelle definiert zu bekommen?
-
Ich will keine allgemeine Schnittstelle. Wenn ich mein gesamtes Programm betrachte, ist das Modell die "Geschäftslogik" des Programms. Und das hat nichts mit irgendwelchen Schnittstellen und erstmal auch nichts mit der GUI zu tun. Das ist davon völlig unabhängig. Und das implementiere ich in eigenen Klassen. Denk z.B. an das QFileSystemModel. Das ist NICHT das eigentlich Modell. Das Modell wären QFile, QFileInfo usw. QFileSystemModel ist der Adapter für die GUI, ja.
Warum sollte ich für jedes "Modell" eine eigene View definieren müssen und warum brauchen die Modelle irgendwelchen allgemeinen Schnittstellen? Wir verstehen das Wort Modell einfach unterschiedlich.
QAbstractItemModel entspricht für mich eigentlich perfekt der Definition des Controllers. Das ist die Zwischenschicht zwischen der View und dem Model. Das benachrichtigt z.B. die View über Änderungen des Modells, über allgemeine Signale wie dataChanged. Und das nimmt Commands in allgemeiner Form (setData) von der GUI entgegen und leitet sie an das drunterliegende Modell weiter, indem es in der setData Implementierung die entsprechenden Methoden des Modells (z.B. QFle::rename) aufruft. Aber es implementiert selber keine Geschäftslogik, daher ist es kein Modell.
-
Mechanics schrieb:
Ich will keine allgemeine Schnittstelle. Wenn ich mein gesamtes Programm betrachte, ist das Modell die "Geschäftslogik" des Programms. Und das hat nichts mit irgendwelchen Schnittstellen und erstmal auch nichts mit der GUI zu tun. Das ist davon völlig unabhängig. Und das implementiere ich in eigenen Klassen. Denk z.B. an das QFileSystemModel. Das ist NICHT das eigentlich Modell. Das Modell wären QFile, QFileInfo usw. QFileSystemModel ist der Adapter für die GUI, ja.
Warum sollte ich für jedes "Modell" eine eigene View definieren müssen und warum brauchen die Modelle irgendwelchen allgemeinen Schnittstellen? Wir verstehen das Wort Modell einfach unterschiedlich.
QAbstractItemModel entspricht für mich eigentlich perfekt der Definition des Controllers. Das ist die Zwischenschicht zwischen der View und dem Model. Das benachrichtigt z.B. die View über Änderungen des Modells, über allgemeine Signale wie dataChanged. Und das nimmt Commands in allgemeiner Form (setData) von der GUI entgegen und leitet sie an das drunterliegende Modell weiter, indem es in der setData Implementierung die entsprechenden Methoden des Modells (z.B. QFle::rename) aufruft. Aber es implementiert selber keine Geschäftslogik, daher ist es kein Modell.Ja da haben wir unterschiedliche Definitionen was ein Model ist :).
Bei MVC kann der View auch direkt zugriff auf das Model haben. So interpretiere ich die einzelnen graphischen Darstellungen von MVC die ich im internet gefunden habe.
Und laut Wikipedia gibt es da auch keine genaue Definition was ein Model ist. Je nach Betrachtungsweise kann ein Model Geschäftslogik enthalten oder auch nicht.
https://de.wikipedia.org/wiki/Model_View_Controller schrieb:
Modell
Das Modell enthält die darzustellenden Daten und gegebenenfalls (abhängig von der Implementierung des MVC-Patterns) auch die Geschäftslogik.In der reinen Theorie dürfte ein Model keine Geschäftslogik enthalten, weil sonst das Model nur für einen bestimmten Aufgabenbereich (definiert über die Geschäftslogik) verwendet werden kann.
Aber grundsätzlich ist QAbstractItemModel eine Basis für ein Model und es bietet soviel logik an um daten im model zu verändern.
Z.b. um dein Beispiel Klasse Person = Model aufzugreifen:
- Person definiert bestimmt keine Geschäftslogik es dient eher als Datasource für eine Geschäftslogik (z.b. um Personen in einem Addressbuch zu verwalten).
Aber das gleiche "Model" kann auch dazu genutzt werden um z.b. Profil information über eine Forenmitglied darzustellen. Und hierfür ist eine andere Geschäftslogik notwendig. - Sind die getData/setData Methoden von QAbstractItemModel vergleichbar mit den einzelnen "getter/setter" der Klasse Person um auf die einzelnen Attribute der Klasse zuzugreifen. Im falle von QAbstractItemModel wurde das ganze über ein generisches Interface gelöst damit die Views nur ein Interface kennen müssen.
Und ich sehe da keinerlei Geschäftslogik nur "Methoden" um Werte im "Model" zu lesen/verändern.
Wenn du jetzt eine Instanz von Person z.b. in eine QListView darstellen möchtest (eine Zeile pro Attribut der Klasse). So verwendest du QAbstractListModel (erbt von QAbstractItemModel) eher in der Form Model–view–adapter (MVA)
Mechanics schrieb:
Warum sollte ich für jedes "Modell" eine eigene View definieren müssen und warum brauchen die Modelle irgendwelchen allgemeinen Schnittstellen? Wir verstehen das Wort Modell einfach unterschiedlich.
Müssen nicht, aber da jede Klasse für dich ein Model sein kann und jede Klasse nicht die selben Attribute hat (sonst wären es nicht unterschiedliche Klassen :)) musst du Anpassungen am View vornehmen damit dieser mit dem "Model" umgehen kann.
Und somit hast du ein View fest an ein bestimmen Type von Model gekoppelt. Das ist ja an sich nicht schlecht, wenn es so die Anforderung ist.
Nur dadurch ist der View als solches (z.b. ein ListView/TreeView) nicht mehr verwendbar für andere Typen von Models. Z.b. du kannst ein ListView, welche eine "Person" darstellen kann, nicht verwenden um z.b. "Tier" anzuzeigen. Da beide Klassen keine gemeinsame Schnittstelle definieren, wie auf die einzelnen Attribute zugegriffen werden kann.Mechanics schrieb:
QAbstractItemModel entspricht für mich eigentlich perfekt der Definition des Controllers. Das ist die Zwischenschicht zwischen der View und dem Model. Das benachrichtigt z.B. die View über Änderungen des Modells, über allgemeine Signale wie dataChanged.
Je nach definition ist QAbstractItemModel ein Model oder nur ein Adapter.
Aber an sich bestimmt kein Controller.Denn das Model kann dem Controller eine Möglichkeit bieten über Änderungen im Model selbst zu signalisieren. Und nur durch diese Funktionalität soll dann aus einem Model ein Controller werden?
In Qt existiert der Controller nicht als eigenständige Instanz sondern ist in den Views enthalten.
- Person definiert bestimmt keine Geschäftslogik es dient eher als Datasource für eine Geschäftslogik (z.b. um Personen in einem Addressbuch zu verwalten).