trennung zweier aufgabenbereiche (berechnung/zeichnen) - konkreter problemfall
-
hallo,
ich schreibe ein programm mit hilfe v. Qt und Qwt und muss eine klasse von QwtPlotCurve ableiten.
hier wird die methodevoid MyCurve::draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect& ) const;
reimplementiert.
die objekte, die gezeichnet werden sollen, enthalten diverse logische daten (skalenkooridnaten), die logischer weise zu pixeldaten transformiert werden muessen, um sie richtig zeichnen zu koennen.
dies passiert eigentlich so (konkret am beispiel der draw-methode) fuer rechtecke:
QwtDoubleRect dRect( value1, value2, value3, value4 ); // QwtDoubleRect: QRectF (typedef) QRect paintRect = transform( xMap, yMap, dRect );
und so fuer einzelne werte (ja, werte und keine punkte):
int paintValue1 = xMap.transform( value1 );
wie man sieht, werden die funktionsparameter (hierfeur natuerlich besonders xMap, yMap) direkt genutzt, oder eben die eigene transform()-Methode, die von QwtPlotCurve geerbt ist.
*
ich soll/muss nun aber die berechnung vom zeichnen strikt trennen - meine myCurve klasse soll ausschliesslich zeichnen und nichts vom transformieren wissen, eine zweite klasse (PixelToValueMapper) soll ausschliesslich berechnen/transformieren.und hier faengt mein problem an: ich weiss nicht, wie ich die transformationen wirklich strikt und 100% vom zeichnen trennen kann.
ich habe nun erstmal direkte "wrapper-methoden" fuer die transform()-methoden gebastelt:
(QwtPlotItem&, weil QwtPlotCurve davon abgeleitet ist und die transform-methode auch von QwtPlotItem erbt ...)QRect PixelToValueMapper::getPaintRect( const QwtPlotItem &p_item, const QwtScaleMap &p_xMap, const QwtScaleMap &p_yMap, const QwtDoubleRect &p_rect ) { return p_item.transform( p_xMap, p_yMap, p_rect ); } int PixelToValueMapper::getPaintValue( const QwtScaleMap &p_scaleMap, const double &p_val ) { return p_scaleMap.transform( p_val ); }
das halte ich allerdings fuer wenig sinnvoll, dann koennte man genauso gut in der draw-methode direkt die transform()-methoden von QwtCurve oder QwtScaleMap aufrufen.
und wenn das koordinatensystem von Qwt wirklich grundlegend geaendert wird - andere methodenaufrufe/zustaendige klassen usw. - dann muessen die methoden vom PixelToValueMapper auch geaendert werden und die zeilen, in denen in der draw-methode der pixelToValueMapper benutzt wird, ebenfalls.etwas besseres faellt mir allerdings auch nicht ein.
so entschuldigung schonmal fuer die ellenlangen erklaerungen ...
kann mir vielleicht jemand einen tipp geben, wie ich die ganze trennung am sinnvollsten und moeglichst zukunftssicher (sprich falls sich beim transformieren an den funktionsaufrufen oder beteiligten klassen seitens Qwt etwas aendert, sollte moeglichst nur der PixelToValueMapper geaendert werden muessen) anstelle?
ich waere wirklich sehr dankbar.
danke im voraus!
ps: sorry, falls das hier das falsche subforum ist, falls noetig, bitte verschieben.
mfg,
julian
-
zu lang/unverstaendlich erklaert, zu bloed, zu langweilig?
mfg,
julian
-
Julian__ schrieb:
zu lang/unverstaendlich erklaert, zu bloed, zu langweilig?
mfg,
julianNa ja, wenn dein Problem Qt-sprezifisch ist, wäre die Frage vielleicht besser im Board "Andere GUIs - Qt, GTK+, wxWidgets" aufgehoben (bitte um Verschiebung). Qwt kenne ich nicht mal. Ich kann dir leider nicht helfen...
-
schonmal danke fuer die antwort
Qwt sind spezielle Qt widgets (Qt Widgets for Technical applications ...).
eigentlich ist es wurst, ich denke eher, dass es ne allgemeine frage ist, nur haengt die erklaerung vllt. zu sehr am beispiel.ich habe ne methode
draw( par1, par2, par3, par4 );
und mit den parameter dieser methode wird transformiert, bzw. mit deren methoden, zusaetzlich braucht man eine transformations-methode der eigenen basisklasse.nun soll das transformieren aber soweit wie moeglich (und sinnvoll) ausgelagtert werden in einer zweite klasse, fuer den fall, das das koordinatensystem, spricht auch die transformationen grundlegend geaendert werden, also andere methoden oder sogar klassen dafuer zustaendig sind.
das waere nicht das problem, wenn nicht die methode der klasse, welche die draw()-methode enthaelt, zum transformieren gebraucht wuerde.
dann uebergibt sie *this als parameter an die zweite klasse und laesst sich das transformationsergebnis der eigenen methode 1:1 wiedergeben - irgendwie nicht so sinnvoll imho, vllt. mangelts auch an erfahrung.dasselbe gilt fuer weitere transformationen, die von den parametern der draw()-methode abhaengen.
mfg,
julian
-
Julian__ schrieb:
ich habe ne methode
draw( par1, par2, par3, par4 );
und mit den parameter dieser methode wird transformiert, bzw. mit deren methoden, zusaetzlich braucht man eine transformations-methode der eigenen basisklasse.nun soll das transformieren aber soweit wie moeglich (und sinnvoll) ausgelagtert werden in einer zweite klasse, fuer den fall, das das koordinatensystem, spricht auch die transformationen grundlegend geaendert werden, also andere methoden oder sogar klassen dafuer zustaendig sind.
Soweit komme ich mit.
Julian__ schrieb:
das waere nicht das problem, wenn nicht die methode der klasse, welche die draw()-methode enthaelt, zum transformieren gebraucht wuerde.
dann uebergibt sie *this als parameter an die zweite klasse und laesst sich das transformationsergebnis der eigenen methode 1:1 wiedergeben - irgendwie nicht so sinnvoll imhoHier kann ich nicht ganz folgen. Die Transformation muß über eine Methode der Klasse mit der draw()-Methode erfolgen? Warum das, bzw. von welchen Parametern dieser Klasse ist die Transformation noch abhängig, und ließen sich diese nicht isolieren und als Interface formulieren?
Oder muß die Klasse gewisse Details bei der Transformation selbst verarbeiten? Dann verwende doch eine Callback-Funktion.
-
die klasse, welche die draw()-methode enthaelt (MyCurve) hat eine transform()-methode, die genutzt werden muss.
zudem muessen die transform-methoden zweier als parameter uebergebener objekte (bzw. referenzen darauf werden uebergeben) genutzt werden.
das alles soll in eine zweite klasse.ich habe es nun erstmal so geloest:
- struct ValueBox enthaelt members, die in der draw methode "gefuellt" werden, darunter zeiger auf die basisklasse von MyCurve, zeiger fuer die beiden objekte, welche mit der draw()-methode als parameter kommen, die zu transformierenden werte und variablen fuer die transformierten werte, plus eine bool-variable success.
... sprich alles, was an informationen zu bekommen ist, kommt da am anfang der draw-mthode rein.- die klasse, welche fuer die transformationen zustaendig ist, hat nun ne statische methode, welche als argument eine referenz auf so ein struct ValueBox objekt entgegennimmt.
die enthaltenen werte werden transformiert und die ergebnisse in den ensprechenden anderen membervariablen gespeichert.
success (bool member der struct) wird dann ggf. auf true oder false gesetzt, je nachdem, ob alle noetigen zeiger gueltig gesetzt waren oder sonstwelche fehler auftraten, oder eben nicht.praktisch sieht es dann jetzt so aus
void MyCurve::draw( par1, &par2, &par3, par4 ) const { ValueBox vbox; vbox.item = this; // fuer this->transform() vbox.par2 = par2; // fuer par2.transform() vbox.par3 = par3; // fuer par2.transform() vbox.logicalValueA = sonstwas; // werte die transformiert werden sollen vbox.logicalValueB = whatever; PixelToValueMapper::transform( vbox ); // vbox.pixelValueA und vbox.pixelValueB enthalten nun richtige werte, // sofern alles geklappt hat (sprich vbox.success == true). if( !vbox.success ) return; // ... weiter zeichnen mit den erthaltenen transformierten werten. }
ist dieses vorgehen eurer meinung nach sinnvoll? oder gibt es wesentlich sinnvollere ansaetze (auch in hinsicht auf die umgebung von QT/QWT vllt.)?
ps: oh mann - tut mir leid dass ich immer gleich ganze aufsaetze schreibe ...
mfg,
julian
-
Julian__ schrieb:
ist dieses vorgehen eurer meinung nach sinnvoll? oder gibt es wesentlich sinnvollere ansaetze (auch in hinsicht auf die umgebung von QT/QWT vllt.)?
Grundsätzlich scheint mir die Lösung sinnvoll und angemessen. Vielleicht könnte man es unter Verwendung von std::tr1::bind und std::tr1::function noch eleganter formulieren, aber das ist mein Fachgebiet nicht.
-
ok vielen dank fuer die antwort und tipps.
ich werde dann erstmal weitermachen mit den naechsten klassen und, falls am ende zeit und bedarf vorhanden sind, mich mal mit den beiden tr1-features auseinandersetzen, die du genannt hast.
den ansatz zu verfeinern/eleganter zu gestalten, hoert sich sehr gut an, allerdings denke ich, dass erstmal der andere kram vom projekt vorgeht.
wenn der ansatz beibehalten wird, wird man es auch spaeter, wenn die zeit ueber ist, noch aendern koennen.mfg,
julian