On Saturday 18 June 2005 13:35, Norbert Pilsl wrote:
Mit Qt könnte man auch den einen ein Signal versenden lassen, das man auf höherer Ebene mit einem Slot auf der anderen Seite verbindet - dann wären die Komponenten maximal entkoppelt.
Diese Idee gefällt mir auch am besten. Einen Slot zu schreiben ist kein Problem. Nur mit dem Signal habe ich Probleme. Wenn ich das richtig sehe kann man nur die vordefinierten Signale versenden. (Mausclick oder anderes)
Nein, natürlich nicht - dann wäre das Konzept ja reichlich nutzlos. Du kannst selber Signale mit beliebigen Parametern definieren und zu beliebigen Zeitpunkten versenden. Es empfiehlt sich aber, sich auf einigermaßen gängige Datentypen zu beschränken - dann erhöht sich der Wiederverwendbarkeitsfaktor der Komponenten, die man son entwickelt hat. Um selber ein Signal zu definieren, muß man es nur im Header-File des Objekts (das von QObject abgeleitet sein muß, also auch alles, was von QWidget abgeleitet ist) definieren und in einer der Methoden dieses Objekts dann mit "emit" versenden. Also etwa: class MySuperCoolThingy: public QWidget { ... signals: void doSomething( int howMany ); void doMore( void ); ... }; MySuperCoolThingy::somewhere() { if ( ... ) { emit doSomething( 42 ); } if ( ... ) emit doMore(); } Die Parameter, die man bei "emit" mitschickt, werden jedem Slot mitgegeben, der mit "connect()" mit diesem Signal verbunden wurde. Eben deshalb empfiehlt es sich, nicht unbedingt exotische Pointer auf komplexe Strukturen zu verwenden (oder gar die komplexen Strukturen selber), sondern nach Möglichkeit einfache Datentypen wie int, boolean, QString u.s.w.; dann kann man ganz leicht ein solches Signal auch mit einem Qt-Standard-Slot verbinden und fertig. Man kann insbesondere auch ein Signal mit einem anderen Signal verbinden, ohne daß man dazu extra noch einen Slot schreiben müßte, der das auch nur weiterreicht. Das ist in der Praxis sehr viel nützlicher, als sich das jetzt vielleicht anhört.
"Mein" Signal müsste auch "mittendrin" versendet werden. (z.B. Settings geladen)
Ja, natürlich.
Als "Ersatz" für globale Variablen wäre wohl eine eigene Klasse am Besten. Diese speichert die Daten und stellt Methoden bereit um diese Daten zu bearbeiten. Diese Klasse müßte im MainWindow erstellt werden.
Das macht das Ganze zwar komplexer, ändert aber am eigentlichen Problem kein bißchen: Du mußt eine Verbindung zwischen dem Dialog und dem Hauptfenster herstellen.
Für die anderen Dialoge müßte eine Funktion erstellt werden die den Zugriff auf das MainWindow zurückgibt. (So wie unten) mainwindow.h muß dann nicht mehr in den Header der anderen Dialoge. Leider habe ich bei dem Beispiel noch ein Verständnisproblem:
mainwindow.cpp:
// Die Variable für den eingenen Zugriff wird // erstmal in einen definierten // Zustand versetzt. MainWindow::_mainWindow = 0;
// Der Sinn dieser nachfolgender Zeilen ist mir nicht klar
MainWindow::MainWindow( ... )
: QMainWindow( ... )
{ ... // Setzen des eigenen Objektes _mainWindow = this; }
// Rückgabe des eigenen Objekts MainWindow::mainWindow() { return _mainWindow; }
Damit implementiert man den Zugriff auf ein Singleton-Objekt - d.h. du weißt von außen gar nichts über irgendwelche Instanzen dieser Klasse, insbesondere hat der Aufrufer keinen Zeiger oder keine Referenz auf eine Instanz. Aber man weiß, daß es davon genau eine gibt, und den Zeiger darauf kann man sich so holen.
// Rückgabe des Textes QString MainWindow::sonstwas() const { return _sonstwas->text(); }
Gehe ich recht in der Annahme das man mit diesen System so ziemlich alle Aufgaben des Datenaustausches lösen kann (soll) ?
Das sind nur so die ganz gängigen Sachen - man will mit den Zugriffsmethoden Objektattribute auslesen können ( sonstwas() ) genauso wie setzen (setSonstwas() ). Von der Namensgebung her gibt es da zwei Lager: Die einen ziehen es vor, eine Methode getSonstwas() und eine setSonstwas() zu nennen, die anderen benutzen sonstwas() und setSonstwas() mit dem Hintergrund, daß man sehr viel Öfter solche Werte holt, als daß man sie setzt. Qt verwendet sonstwas() und setSonstwas(), deshalb paßt diese Methode besser ins Schema, wenn man Qt benutzt - deshalb findet man das auch in Qt-Programmen sehr viel öfter als getSonstwas().
In der Hilfe Funktion des QT - Designer gibt es ein extra Kapitel über die Erstellung von eigenen Klassen. Dieses habe ich noch nicht gelesen. Konnte mir bis jetzt nicht vorstellen das man schon bei solchen "Kleinkram" eigene Klassen einsetzten muß (soll).
Qt erleichtert es mit seinen Signals und Slots enorm, vorhandene Klassen einfach zu verwenden, anstatt für jede Kleinigkeit eine eigene abzuleiten. Aber ganz ohne eigene Klassen geht es natürlich auch dort nicht. Bei Qt muß man z.B. nicht eine eigene Klasse MachWasButton() erfinden, die z.B. von QPushButton() abgeleitet ist, wenn man nur auf einen Mausklick reagieren will - da erzeugt (instanziiert) man einfach einen vorhandenen QPushButton() und verbindet sein clicked() -Signal mit dem Slot, der tatsächlich etwas tut.
Bis jetzt habe ich nur mit prozeduralen Sprachen gearbeitet und mein Hirn denkt auch immer nur prozedural. Erst mit der Zeit werde ich ein Gespür dafür entwickeln wann und wo man eigene Klassen einsetzt.
Kleiner Nachtrag für Stefan Hundhammer: Wirklich herzlichen Dank für Dein Beispiel. Das wird mein "Grundgerüst" für meine ersten eigenen Klassen. Nur eine kleine Kritik: Es ist etwas schwierig für das menschliche Auge zwischen MainWindow ; QMainWindow ; mainWindow ; _mainWindow zu unterscheiden.
Es empfiehlt sich dringend, sich an eine Konvention zur Namensgebung zu
halten. Es gibt auch hier natürlich verschiedene Ansätze, die alle ihre
Berechtigung haben - und letztendlich natürlich hauptsächlich eine
Geschmacksfrage sind.
Was man aber definitiv braucht, ist eine offensichtliche Verbindung zwischen
- Membervariable
- Methode zum Holen
- Methode zum Setzen
Ich verwende hier die Konvention, daß Membervariablen mit einem Unterstrich
beginnen (andere verwenden m_). Das vermeidet Namenskonflikte innerhalb von
Klassen und macht außerdem deutlich, daß man mit einer Membervariable
arbeitet, auch wenn man ein Codefragment nur flüchtig liest. Es gehören also
immer zusammen:
sonstwas() // lesen - public oder protected
setSonstwas() // setzen - public oder protected
_sonstwas // die Variable selber - private (!)
Man kann die private Membervariable natürlich auch irgendwie benennen, aber
dann wird es wirklich kompliziert - und fehleranfällig. Man hat dann nach
einiger Zeit ganz schnell vergessen, daß man ja auf "larifari" mit
"sonstwas()" und "setSonstwas()" zugreift, und wird lange rätseln, was der
Code denn eigentlich tut. Wenn jemand etwas ändern muß, wird er evtl. nur
fluchen und (vor allem unter Zeitdruck) "larifari" einfach "public" oder
"protected" machen und direkt darauf zugreifen - und dann geht nicht nur die
Abstraktion verloren, sondern auch noch jede Art Fehlerbehandlung, die in
"setSontwas()" oder "sonstwas()" so stecken mag. Und damit verschenkt man
einen der allergrößter Vorteile von objektorientierter Programmierung.
Für abgeleitete Klassen gilt das analog - es gibt nicht so wirklich viele
sinnreiche Arten, wie man Widgets und ähnliche Klassen nennen kann. Speziell
ein Hauptfenster wird man deshalb auch irgendwas mit "mainWindow" nennen -
und immer schön aufpassen, daß man nicht künstlich Konfusion einbringt, indem
man etwa Namen verwendet, die schon mit anderer Semantik vorbelegt sind -
z.B. "xyApplication" für irgendwas, was von QMainWindow oder QDialog oder
auch nur QWidget abgeleitet ist - es gibt ja auch QApplication, und das ist
etwas ganz anderes.
Bevor man hier also glaubt, alles selber komplett anders neu erfinden zu
wollen, sollte man sich einfach mal ansehen, wie das andere gelöst haben.
Manche solchen Konventionen haben sich einfach bewährt.
CU
--
Stefan Hundhammer