[gelöst] Signale dynamisch connecten möglich?

Alles zum Qt Framework für Java
Antworten
Forest
Beiträge: 26
Registriert: 22. Juni 2008 03:10

[gelöst] Signale dynamisch connecten möglich?

Beitrag von Forest »

Ich habe verschiedene Klassen, die alle ein und das selbe Signal

Code: Alles auswählen

public final Signal1<Integer> destroyedSignal = new Signal1<Integer>();
deklarieren.

Genauer gesagt sind es Klassen die alle ein Interface implementieren, welches vom Runnable Interface abgeleitet ist und alle Klassen sind von QSignalEmitter abgeleitet. Aber das spielt glaube ich nicht wirklich eine Rolle. Es geht ja ums Prinzip.

Ich möchte jetzt von zig Instanzen der Klassen immer von allen das destroyedSignal zu ein und derselben Methode in einer bestimmten anderen Klasse connecten. Ich denke obs immer zu derselben oder zu verschieden ist, spielt auch nicht wirklich eine Rolle.

Connecten will ich es in meinem Fall zu der klasse wo die Instanzen auch erzeugt werden und ich will es auch direkt aus dieser Erzeugungsklasse machen, da dort eh eine Schleife über alle läuft was aktuell erzeugt werden soll und ich auch nicht die Konstruktoren der erzeugten Klassen verändern will um die Erzeugungsklasse mitzugeben, damit dort das connecten stattfindet. Es könnte ja auch sein, dass man es zu einer anderen Klasse connecten will und die noch gar nicht existiert. Zudem ist es blöd in 20 Klassen alle Konstruktoren zu verändern und innerhalb immer die gleiche blöde connect Zeile copy und pasten. Das ist wahrlich keine Programmierkunst (aber aktuell meine Notlösung).

Ich spreche also alle neu erzeugten Instanzen der Klassen dynamisch über den Typ des Interface an. (diese werden tatsächlich auch in anderen Methoden erzeugt, die mir Objekte mit Typ des Interfaces zurückgeben. Was ich mache ist die ins Array vom Typ des Interfaces zu packen).

Das Problem ist jetzt aber, ich kann die Signale nicht connecten. Ich kann nicht der beliebigen instanz "a" der Klasse A, die Interface B implementiert, wobei "a" aktuell ja vom Typ B ist sagen: (weil Eclipse meckert)

Code: Alles auswählen

a.destroyed.connect(...);
Was ich jedoch machen kann ist

Code: Alles auswählen

((A) a).destroyed.connect(...);
Der Hacken ist jedoch letzteres kann ich ja nicht wirklich machen, da ich ja bereits die Objekte nach Erzeugung vom Typ B bekomme und was ja auch richtig so ist, da ich über zig verschiedene Instanzen von zig verschiedenen Klassen, die alle das Interface B implementieren, dynamisch in der Schleife durchgehe.

Macht QtJambi das nun futsch, oder kriegt man das irgendwie gebacken?
Fehlt einem fast sowas wie ein Interface über Signalen ... oder die Möglichkeit in Interfaces ausser Methoden noch Signale angeben zu können. Ich kann in meinem Fall übrigens auch nicht die Kommunikation über Methoden regeln, da in meinem Fall ja alle Instanzen irgendwelche Arten von Threads sind und ich ja deswegen nur per Signale aus denen heraus kommunizieren kann.

Hoffe mich hat einer verstanden, was ich meine. Ansonsten fragt nochmal nach :)
Muss doch irgendeinen Fachmann geben, der die Antwort kennt :roll:
ArneStocker
Beiträge: 300
Registriert: 3. November 2004 16:15
Wohnort: Berlin

Beitrag von ArneStocker »

Wenn ich es richtig verstehe möchtest Du ein connect über ein Interface durchführen ohne dass Du zu diesem Zeitpunkt weisst, zu welcher Klasse das Objekt gehört, dass dann später das Signal an Deinen Slot senden wird ?

Code: Alles auswählen

public interface MyInterface{
   public void ConnectSignal(QObject receiver, String slot);
}


public class MyClass1 implements MyInterface{
   Signal0 m_mySignal1 = new Signal0();

   public void ConnectSignal(QObject receiver, String slot) {
      m_mySignal1.connect(receiver,slot);
   }

   public void bla () {
      m_mySignal1.emit();
   }
}

public class MyClass2 implements MyInterface{
   Signal0 m_mySignal2 = new Signal0();

   public void ConnectSignal(QObject receiver, String slot) {
      m_mySignal2.connect(receiver,slot);
   }

   public void blabla () {
      m_mySignal2.emit();
   }
}

...

Interface class1= new MyClass1();
Interface class2= new MyClass2();

class1.ConnectSignal(this,"meinSlot()");
class1.ConnectSignal(this,"meinSlot()");
Das ganze geht natürlich auch mit anderen (nicht eigenen) Signalen. Oder meintest Du was anderes ? Dann zeig doch bitte mal Deine 'copy&paste' Lösung

Gruß arne
Forest
Beiträge: 26
Registriert: 22. Juni 2008 03:10

Beitrag von Forest »

Nee, das unten will ich haben, geht aber nicht wie im ersten Post erklärt.

Code: Alles auswählen

public interface MyInterface{
   egal_was_hier_steht
}


public class MyClass_1 implements MyInterface{
   Signal0 destroy = new Signal0();
 
   ...
}

public class MyClass_2 implements MyInterface{
   Signal0 destroy = new Signal0();
 
   ...
}

...

public class MyClass_n implements MyInterface{
   Signal0 destroy = new Signal0();
 
   ...
}

class EineKlasse {
     meinSlot() {...}
}

class MyMy {
EineKlasse o;
...
ein_Slot() {
...
     while(!stop) {
           MyInterface m = gibMirDieNaechsteInstanz();
           m.destroy.connect(o, "meinSlot()");
     }
}
...
}

daher mache ich also total umständlich "n" mal:

Code: Alles auswählen

public class MyClass_1 implements MyInterface{
   Signal0 destroy = new Signal0();
   Konstruktor(..., EineKlasse instanz) {
   destroy.connect(intanz, "meinSlot()");)
   ...
}

public class MyClass_2 implements MyInterface{
   Signal0 destroy = new Signal0();
   Konstruktor(..., EineKlasse instanz) {
   destroy.connect(intanz, "meinSlot()");)
   ...
}

public class MyClass_n implements MyInterface{
   Signal0 destroy = new Signal0();
   Konstruktor(..., EineKlasse instanz) {
   destroy.connect(intanz, "meinSlot()");)
   ...
}

class EineKlasse {
     meinSlot() {...}
}

class MyMy {
EineKlasse o;
...
ein_Slot() {
...
     while(!stop) {
           MyInterface m = gibMirDieNaechsteInstanz();
           // m.destroy.connect(o, "meinSlot()");
     }
}
...
}
ArneStocker
Beiträge: 300
Registriert: 3. November 2004 16:15
Wohnort: Berlin

Beitrag von ArneStocker »

hm...

Da dem Interface das Member m_signal nicht bekannt ist, kanns Du natürlich auch nicht darauf zugreifen und ein Member für ein Interface gibt es m.E. nicht.

Versuch doch mal eine Methode im Interface zu implementieren

Code: Alles auswählen

public Signal0 GetSignal() ;
die Du dann in jeder Deiner Klasse implementiert. Und zum Schluss

Code: Alles auswählen

   while(!stop) {
           MyInterface m = gibMirDieNaechsteInstanz();
           m.GetSignal().connect(o, "meinSlot()");
     } 
Gruß Arne
Forest
Beiträge: 26
Registriert: 22. Juni 2008 03:10

Beitrag von Forest »

stimmt du hast recht, so muss es gehen. (auch wenns nicht 1 Zeile für alle Klassen ist, sondern wieder ca. naja 1 Zeile je Klasse).

Ich hab jetzt aber doch noch andere Signale je nach Klasse reinmachen müssen und daher eh den Konstruktor jeweils aufblähen müssen. Und ob ich jetzt die Sache dann im Konstruktor mache und die instanz dem Konstruktor übergebe, oder aber aus der Erzeugungsklasse die getSignal Methode aufrufe und dann je nachdem welche klasse es ist, diese entsprechend verbinde... das ist dann nun auch egal.

Aber danke für die Antwort. Hat sich wohl dann damit erledigt.
ArneStocker
Beiträge: 300
Registriert: 3. November 2004 16:15
Wohnort: Berlin

Beitrag von ArneStocker »

Und ob ich jetzt die Sache dann im Konstruktor mache und die instanz dem Konstruktor übergebe, oder aber aus der Erzeugungsklasse die getSignal Methode aufrufe und dann je nachdem welche klasse es ist, diese entsprechend verbinde... das ist dann nun auch egal.
Naja, nicht ganz. Wenn Du z.B. bei einem Redesign den Slot "meinSlot()" ändern würdes, müsstest Du das in allen Konstruktoren tun. Das wäre dann ein ein Einfallstor für sog. Seiteneffekte, wenn Du es an irgendeiner Stelle vergißt.

Im übrigen besteht natürlich noch die Möglichkeit, eine gemeinsame Basisklasse einzuziehen, das wäre hier wohl auch gerechtfertigt.

Gruß Arne
Forest
Beiträge: 26
Registriert: 22. Juni 2008 03:10

Beitrag von Forest »

ArneStocker hat geschrieben:
Und ob ich jetzt die Sache dann im Konstruktor mache und die instanz dem Konstruktor übergebe, oder aber aus der Erzeugungsklasse die getSignal Methode aufrufe und dann je nachdem welche klasse es ist, diese entsprechend verbinde... das ist dann nun auch egal.
Naja, nicht ganz. Wenn Du z.B. bei einem Redesign den Slot "meinSlot()" ändern würdes, müsstest Du das in allen Konstruktoren tun. Das wäre dann ein ein Einfallstor für sog. Seiteneffekte, wenn Du es an irgendeiner Stelle vergißt.

Im übrigen besteht natürlich noch die Möglichkeit, eine gemeinsame Basisklasse einzuziehen, das wäre hier wohl auch gerechtfertigt.

Gruß Arne
naja, dafür gibts es ja das refactoring bei eclipse. Wenn ich den Namen des Signals ändere, müsste ich es in allen Fallbehandlungen machen ;) Ne, dein Vorschlag ist aufjedenfall gut, aber in meinem Fall lass ichs jetzt so wie es ist. Bei einem neueren Projekt werd ich deinen Vorschlag aufjedenfall in Erwägung ziehen.

Was meinst du mit Basisklasse? Von der sollen die ganzen Klassen ableiten? Ich hab leider bei all den klassen keine Möglichkeit mehr abzuleiten.
ArneStocker
Beiträge: 300
Registriert: 3. November 2004 16:15
Wohnort: Berlin

Beitrag von ArneStocker »

Was meinst du mit Basisklasse? Von der sollen die ganzen Klassen ableiten? Ich hab leider bei all den klassen keine Möglichkeit mehr abzuleiten.
wenn Du Deine Klassen von einer Fremdklasse (aus einer Lib) ableitest, dann wohl nicht, weil es in Java keine Mehrfachvererbung gibt.

Wenn Du aber alle Klassen selbst geschaffen (und damit von Object abgeleitet) hast, dann könnstest Du als kleinsten gemeinsamen Nenner eine

Code: Alles auswählen

public class SignalObject
als unterste Klasse einziehen, die nur ein Signal als Member hat und die Methode ConnectIrgendwas enthält

Gruß Arne
Forest
Beiträge: 26
Registriert: 22. Juni 2008 03:10

Beitrag von Forest »

ich bin übrigens über folgendes für Qt das gleiche Thema betreffend gestossen:
http://doc.trolltech.com/qq/qq16-dynamicqobject.html
Der Text ist mir aber aktuell etwas zu lang. Und keine Ahnung ob man damit auch was für Qt Jambi anfangen kann. Werds mir ggf. aber sobald ich wieder mehr Zeit habe durchschauen/lesen.
Antworten