Ich denke, dass die in Qt mit Modell- / Ansichtssteuerelementen verwendete Terminologie fehlerhaft ist. Auf ihrer Erklärungsseite geben sie an, dass sie die MVC zu MV vereinfacht haben, indem sie View und Controller zusammengeführt haben, und sie geben das folgende Bild:
Wie auch immer ich denke, sie haben die Rollen von Objekten falsch benannt und ich denke, dass
- Was sie Ansicht mit zusammengeführtem Controller nennen, ist in der Tat nur eine Ansicht.
- Was sie Model nennen, ist in der Tat nur Controller.
- Wenn Sie wirklich ein Modell haben möchten, ist es irgendwo, wo sich ihre "Daten" befinden.
Ich spreche von der üblichen und vernünftigen Art und Weise, wie Sie die Qt-Modell- / Ansichtskomponente in Ihrer App verwenden würden. Hier sind die Gründe:
- Dies ist normalerweise eine Qt-Komponente, die unverändert verwendet wird, ohne dass eine für Ihre Objekte spezifische Controller-Logik hinzugefügt wird.
- Dies ist kaum ein Modell, nur weil Sie mehrere Qt-Methoden wie rowCount, columnCount, data usw. implementieren sollten, die nichts mit Ihrem Modell zu tun haben. Tatsächlich gibt es typische Modellmethoden in Controllern. Natürlich können Sie hier sowohl Controller- als auch Modelllogik implementieren , aber erstens wäre es ein ziemlich schlechtes Code-Design und zweitens würden Sie Controller und Modell zusammenführen, nicht Controller und View, wie sie angeben.
- Wie in Grund 2 gesagt, wenn Sie die Modelllogik trennen möchten, ist dies sicherlich nicht das blaue Feld auf dem Bild, sondern das gestrichelte Feld "Daten" (Kommunikation mit realen Daten natürlich).
Ist Qt in ihrer Terminologie falsch oder bin es nur ich, der es nicht versteht? (Übrigens: Der Grund, warum es keine akademische Frage ist, ist, dass ich begonnen habe, mein Projekt nach ihrer Benennung zu codieren, und ich habe bald herausgefunden, dass der Code eindeutig nicht richtig ist. Erst danach wurde mir klar, dass ich es tun sollte nicht versuchen, Modelllogik in das zu setzen, was sie Modell nennen)
Antworten:
Ich stimme Ihnen zu, dass die Benennung von Qt irreführend ist. Meiner Meinung nach liegt das Problem jedoch nicht nur bei Qt, sondern wird von allen Frameworks geteilt, die es uns ermöglichen, bei der Implementierung unserer Benutzeroberflächen das Prinzip der Trennung von Bedenken einzuhalten. Wenn jemand ein solches Framework entwickelt und einen guten Weg findet, um "Dinge" getrennt zu halten, fühlt er sich immer verpflichtet, Module zu haben, die er "Modell" nennt, und andere, die er "Ansicht" nennt. Im Laufe der Jahre habe ich mit folgenden Frameworks gearbeitet:
Wenn Sie vergleichen, wie die Begriffe "Modell" und "Ansicht" in diesen Frameworks verwendet werden und welche Verantwortlichkeiten die Klassen in "Ansicht", "Modell" und "Controller" (falls vorhanden) haben, werden Sie finde, dass es sehr große Unterschiede gibt. Es wäre sicherlich nützlich, die verschiedenen Konzepte und Terminologien zu vergleichen, damit Menschen, die von einem Framework zu einem anderen wechseln, die Möglichkeit haben, gesund zu bleiben, aber das würde viel Arbeit und Forschung erfordern. Eine gute Lektüre ist Martin Fowlers Übersicht .
Da es so viele verschiedene Ideen gibt, wie ein MVC-Muster aussehen kann, welches ist richtig? Meiner Meinung nach sollten sich die Leute, die MVC erfunden haben, an uns wenden, wenn wir wissen wollen, wie es "richtig" implementiert werden soll. Auf dem Original-Smalltalk-Papier steht:
In Anbetracht dessen würde ich Ihre drei Hauptanliegen folgendermaßen beantworten:
Wo bleibt es uns? Meiner Meinung nach ist es am besten herauszufinden, was Qt wirklich bedeutet, wenn die Begriffe "Modell" und "Ansicht" verwendet werden, und die Begriffe auf ihre Weise zu verwenden, während wir mit Qt programmieren. Wenn Sie sich weiterhin Sorgen machen, wird dies Sie nur verlangsamen, und die Art und Weise, wie die Dinge in Qt eingerichtet sind, ermöglicht ein elegantes Design - das mehr wiegt als ihre "falschen" Namenskonventionen.
quelle
Kurze Antwort
Die MVC von Qt gilt nur für eine Datenstruktur . Wenn Sie über eine MVC- Anwendung sprechen , sollten Sie nicht an
QAbstractItemModel
oder denkenQListView
.Wenn Sie eine MVC-Architektur für Ihr gesamtes Programm wünschen, hat Qt kein so "riesiges" Modell- / Ansichts-Framework. Für jede Liste / jeden Datenbaum in Ihrem Programm können Sie jedoch den Qt MVC-Ansatz verwenden, für den tatsächlich ein Controller angezeigt wird. Die Daten befinden sich innerhalb oder außerhalb des Modells. Dies hängt davon ab, welchen Modelltyp Sie verwenden (eigene Modellunterklasse: wahrscheinlich innerhalb des Modells; z. B. QSqlTableModel: außerhalb (aber möglicherweise innerhalb des Modells zwischengespeichert)). Verwenden Sie zum Zusammenstellen Ihrer Modelle und Ansichten eigene Klassen, die dann die Geschäftslogik implementieren .
Lange Antwort
Qts Modell- / Ansichtsansatz und Terminologie:
Qt bietet einfache Ansichten für ihre Modelle. Sie haben einen eingebauten Controller : Das Auswählen, Bearbeiten und Verschieben von Elementen ist etwas, was ein Controller in den meisten Fällen "steuert". Das heißt, Benutzereingaben interpretieren (Mausklicks und Bewegungen) und dem Modell die entsprechenden Befehle geben.
Die Modelle von Qt sind in der Tat Modelle mit zugrunde liegenden Daten. Die abstrakten Modelle enthalten natürlich keine Daten, da Qt nicht weiß, wie Sie sie speichern möchten. Aber Sie einen QAbstractItemModel auf Ihre Bedürfnisse erweitern , indem Sie Ihre Datencontainer an die Unterklasse hinzufügen und machen das Modell Schnittstelle Ihre Daten zugreifen kann . In der Tat, und ich nehme an, dass Ihnen das nicht gefällt, besteht das Problem darin, dass Sie das Modell programmieren müssen, damit auf Daten in Ihrer Datenstruktur zugegriffen und diese geändert werden können.
In der MVC-Terminologie enthält das Modell sowohl die Daten als auch die Logik . In Qt liegt es an Ihnen, ob Sie einen Teil Ihrer Geschäftslogik in Ihr Modell aufnehmen oder nach außen stellen, um eine "Ansicht" für sich zu sein. Es ist nicht einmal klar, was unter Logik zu verstehen ist: Elemente auswählen, umbenennen und verschieben? => bereits implementiert. Berechnungen mit ihnen machen? => Platzieren Sie es außerhalb oder innerhalb der Modellunterklasse. Daten aus / in eine Datei speichern oder laden? => Fügen Sie es in die Modellunterklasse ein.
Meine persönliche Meinung:
Es ist sehr schwierig , einem Programmierer ein gutes und allgemeines MV (C) -System bereitzustellen . Da die Modelle in den meisten Fällen einfach sind (z. B. nur Zeichenfolgenlisten), bietet Qt auch ein gebrauchsfertiges QStringListModel. Wenn Ihre Daten jedoch komplexer als Zeichenfolgen sind, liegt es an Ihnen, wie Sie die Daten über die Qt-Modell- / Ansichtsschnittstelle darstellen möchten. Wenn Sie beispielsweise eine Struktur mit 3 Feldern haben (z. B. Personen mit Name, Alter und Geschlecht), können Sie die 3 Felder 3 verschiedenen Spalten oder 3 verschiedenen Rollen zuweisen. Ich mag beide Ansätze nicht.
Ich denke, das Modell- / Ansichts-Framework von Qt ist nur nützlich, wenn Sie einfache Datenstrukturen anzeigen möchten . Es wird schwierig zu handhaben, wenn die Daten benutzerdefinierte Typen haben oder nicht in einem Baum oder einer Liste (z. B. einem Diagramm) strukturiert sind. In den meisten Fällen reichen Listen aus, und selbst in einigen Fällen sollte ein Modell nur einen einzigen Eintrag enthalten. Insbesondere wenn Sie einen einzelnen Eintrag mit unterschiedlichen Attributen (eine Instanz einer Klasse) modellieren möchten, ist das Modell- / Ansichts-Framework von Qt nicht der richtige Weg, um Logik von der Benutzeroberfläche zu trennen.
Zusammenfassend denke ich, dass das Modell- / Ansichts-Framework von Qt genau dann nützlich ist, wenn Ihre Daten von einem der Viewer-Widgets von Qt angezeigt werden . Es ist völlig nutzlos, wenn Sie einen eigenen Viewer für ein Modell schreiben möchten, das nur einen Eintrag enthält, z. B. die Einstellungen Ihrer Anwendung, oder wenn Ihre Daten nicht druckbar sind.
Wie habe ich das Qt-Modell / die Qt-Ansicht in einer (größeren) Anwendung verwendet?
Ich habe einmal (in einem Team) eine Anwendung geschrieben, die mehrere Qt-Modelle zum Verwalten von Daten verwendet. Wir haben uns entschlossen, ein zu erstellen
DataRole
, um die tatsächlichen Daten zu speichern, die für jede Modellunterklasse einen anderen benutzerdefinierten Typ hatten. Wir haben eine äußere Modellklasse erstellt,Model
die alle verschiedenen Qt-Modelle enthält. Wir haben auch eine äußere Ansichtsklasse erstellt,View
die die Fenster (Widgets) enthält, die mit den darin enthaltenen Modellen verbunden sindModel
. Dieser Ansatz ist also eine erweiterte Qt-MVC, die an unsere eigenen Bedürfnisse angepasst ist. BeideModel
undView
Klassen selbst haben nichts mit der Qt MVC zu tun.Wo haben wir die Logik hingelegt ? Wir haben Klassen erstellt, die die eigentlichen Berechnungen für die Daten durchgeführt haben, indem wir Daten aus Quellmodellen gelesen haben (wenn sie sich geändert haben) und die Ergebnisse in Zielmodelle geschrieben haben. Aus Sicht von Qt wären diese Logikklassen Ansichten, da sie sich mit Modellen "verbinden" (nicht "Ansicht" für den Benutzer, sondern eine "Ansicht" für den Geschäftslogik-Teil der Anwendung).
Wo sind die Controller ? In der ursprünglichen MVC-Terminologie interpretieren Controller die Benutzereingaben (Maus und Tastatur) und geben dem Modell Befehle, um die angeforderte Aktion auszuführen. Da die Qt-Ansichten bereits Benutzereingaben wie das Umbenennen und Verschieben von Elementen interpretieren, war dies nicht erforderlich. Was wir jedoch brauchten, war eine Interpretation der Benutzerinteraktion, die über die Qt-Ansichten hinausgeht.
quelle
View
Klasse sollten Sie das Proxy-Modell hinzufügen, das das Baummodell als zugrunde liegendes Modell hat und von Ihrer Dateisystem-Listenansicht verwendet wird. Wie Sie sagen: Es sollten keine zwei Modelle für dieselben Daten vorhanden sein. Noch nie! (Aber Proxy-Modelle zählen nicht als separate Modelle.)QAbstractItemModel
, von denen einige Modelle im Sinne von MVC sind und einige nicht.Die Terminologie ist nicht richtig oder falsch, sie ist nützlich oder nutzlos.
Sie können die Frage ein wenig ändern und fragen, warum Qt nicht MVC-freundlicher ist. Die Antwort darauf ist, dass die frühen Qt-Entwickler glauben, dass das Entkoppeln von V von C in GUI-Anwendungen zu schlechten Vs und Cs führt. Das Design von QWidget versucht, es einfach zu machen, die Interferenz der Mauseingaben eng mit den Entscheidungen zur Pixelausgabe zu verknüpfen, und Sie können sehen, dass dies nicht der Weg zu MVC ist.
quelle
Als Modellfunktion reagiert auf Anfragen nach Informationen, denke ich nichts falsch es bei der Festlegung solcher Verfahren wie
rowCount
,columnCount
etc. Ich denke Modell eine Art Wrapper für Datenquelle (egal , was es ist SQL - Tabelle oder ein Array) Es stellt Daten in Standardform bereit, und Sie sollten Methoden definieren, die von Ihrer Datenquellenstruktur abhängen.quelle
Ich glaube, ihre Terminologie ist korrekt ... obwohl es in realen Anwendungen sehr einfach sein kann, die Grenzen zwischen Modell, Ansicht und Controller zu verwischen, abhängig von Ihrer Abstraktionsebene: Die Ansicht einer Ebene kann das Modell einer höheren Ebene sein.
Ich glaube, die Verwirrung ergibt sich aus ihrer QAbstractModelItem-Klasse. Diese Klasse ist kein Modellelement, sondern eine Schnittstelle zu einem Modell. Um ihre Ansichtsklassen mit dem Modell zu verbinden, mussten sie eine generische abstrakte Schnittstelle zum Modell erstellen. Ein Modell kann jedoch ein einzelnes Element, eine Liste von Elementen, eine Tabelle mit zwei oder mehr Dimensionen von Elementen usw. sein. Daher muss ihre Schnittstelle alle diese Modellvarianten unterstützen. Zugegeben, dies macht die Modellelemente ziemlich komplex, und der Klebercode, damit es mit einem tatsächlichen Modell funktioniert, scheint die Metapher ein wenig zu dehnen.
quelle
Nein, ihr "Modell" ist definitiv kein Controller.
Der Controller ist der Teil der vom Benutzer sichtbaren Steuerelemente, die das Modell ändern (und daher indirekt die Ansicht ändern). Beispielsweise ist eine Schaltfläche "Löschen" Teil der Steuerung.
Ich denke, es gibt oft Verwirrung, weil viele so etwas wie "Der Controller modifiziert das Modell" sehen und denken, dass dies die Mutationsfunktionen ihres Modells bedeutet, wie eine "deleteRow ()" - Methode. In der klassischen MVC ist der Controller jedoch speziell der Teil der Benutzeroberfläche. Methoden, die das Modell mutieren, sind einfach Teil des Modells.
Seit der Erfindung von MVC ist die Unterscheidung zwischen Controller und Ansicht immer angespannter geworden. Denken Sie an ein Textfeld: Es zeigt Ihnen sowohl Text als auch die Möglichkeit, ihn zu bearbeiten. Ist es also eine Ansicht oder ein Controller? Die Antwort muss sein, dass es Teil von beiden ist. Als Sie in den 1960er Jahren an einem Teletyp arbeiteten, war die Unterscheidung klarer - denken Sie an die
ed
-, aber das bedeutet nicht, dass die Dinge für den Benutzer damals besser waren!Es ist wahr, dass ihr QAbstractItemModel eher höher ist als ein Modell normalerweise. Zum Beispiel können Elemente darin eine Hintergrundfarbe haben (technisch gesehen ein Pinsel), was ein ausgesprochen anschauliches Attribut ist! Es gibt also ein Argument, dass QAbstractItemModel eher einer Ansicht ähnelt und Ihre Daten das Modell sind. Die Wahrheit ist, dass es irgendwo zwischen den klassischen Bedeutungen von Ansicht und Modell liegt. Aber ich kann nicht sehen, wie es ein Controller ist; Wenn überhaupt, dann ist dies das QT-Widget, das es verwendet.
quelle