Seite 1 von 1

Ereignisprogrammierung

Verfasst: Di Jul 06, 2010 2:07 am
von Bebu
Huhu zusammen, ich bin schon eine Weile auf der Suche danach, wie man Ereignisse programmieren kann. Google hat mir bisher nichts brauchbares/verständliches ausgespuckt.

Genauer gesagt, möchte ich in meine Filesearcherklasse von Dedupe verschiedene Ereignisse einbauen, z. B. ein Ereignis für Suche beendet, Fehler, Suche gestartet usw. Leider habe ich keine Ahnung wie ich das Hinkriegen soll. Könnte mir jemand die Grundzüge anhand eines Beispiels erklären? Nur das keine Missverständnisse aufkommen, ich weiß was ein Ereignis ist, aber ich weiß nicht, wie ich meine Klasse dazu bringen kann, eines auszulösen.

PS: @Xin: Die Abwesenheit ist hiermit noch nicht aufgehoben ;)

Re: Ereignisprogrammierung

Verfasst: Di Jul 06, 2010 8:06 am
von cloidnerux
Im Grunde genommen hast du eine Liste an Funktionspointern, die bei einem Bestimmten Ereignis aufgerufen werden.
Das heißt, du könntest dir eine Hilfsklasse "event" programmieren, die eine Liste für Funktionspointer enthält, eine Methode zum Hinzufügen und Entfernen von Funktionspointern und eine Methode zum Starten mit entsprechenden Parametern. Diese klasse kannst du dann für jeden Zweck spezialisieren.

Code: Alles auswählen

class event
{
    List<void*(int, int)> eventMethods;  //<-- Pointer so richtig?
    ...
    public bool AddToEvent(void (*func)(int, int))
    ....
    public bool RemoveFromEvent(void (*func)(int, int))
    public void Start(int int);
};
...
event myEvent;
myEvent.AddToEvent(my_func);
...
//Hier könntest du z.B fertig mit der Suche sein
myEvent.Start(a, b);
Das ist alles nicht getestet und dient nur der Anschauung.

Re: Ereignisprogrammierung

Verfasst: Di Jul 06, 2010 8:47 am
von Xin
cloidnerux hat geschrieben:Im Grunde genommen hast du eine Liste an Funktionspointern, die bei einem Bestimmten Ereignis aufgerufen werden.
Das heißt, du könntest dir eine Hilfsklasse "event" programmieren, die eine Liste für Funktionspointer enthält, eine Methode zum Hinzufügen und Entfernen von Funktionspointern und eine Methode zum Starten mit entsprechenden Parametern. Diese klasse kannst du dann für jeden Zweck spezialisieren.
Das wäre ein Event-Handler, der ein einziges Ereignis an beliebig viele Listener übermittelt.


Statt einer einzelnen Funktion, lässt sich alternativ aber auch ein Listener Objekt konstruieren. Das wäre eine abstrakte Klasse, die von den Empfängern der Nachricht implementiert wird. Der Sender erhält so die Kontrolle und ruft nur noch die Funktionen des Empfänger-Objektes auf. Das Empfängerobjekt hat damit also auch keine Kontrolle darüber, was rundum passiert.

Möglichkeit 3 habe ich kürzlich ins Repository eingecheckt: Man fragt den Sender, ob es schon was Neues gibt. Der Sender liefert einen Hinweis darauf, was anliegt und überlässt dem Empfänger die Nachricht zu bearbeiten oder es sein zu lassen.

In Kombination mit cloidnerux Liste ergibt sich so die Möglichkeit viele Empfänger mit vielen Ereignissen zu versorgen. Da wir aber vermutlich hinter jeder Oberfläche nur ein Programm laufen haben, können wir uns vermutlich auch auf einen Empfänger beschränken.
Bebu hat geschrieben:PS: @Xin: Die Abwesenheit ist hiermit noch nicht aufgehoben
Heißt das, ich hätte die Frage noch nicht beantworten dürfen? ;-)

Re: Ereignisprogrammierung

Verfasst: Mi Jul 07, 2010 12:46 am
von Bebu
Xin hat geschrieben:
Statt einer einzelnen Funktion, lässt sich alternativ aber auch ein Listener Objekt konstruieren. Das wäre eine abstrakte Klasse, die von den Empfängern der Nachricht implementiert wird. Der Sender erhält so die Kontrolle und ruft nur noch die Funktionen des Empfänger-Objektes auf. Das Empfängerobjekt hat damit also auch keine Kontrolle darüber, was rundum passiert.

Möglichkeit 3 habe ich kürzlich ins Repository eingecheckt: Man fragt den Sender, ob es schon was Neues gibt. Der Sender liefert einen Hinweis darauf, was anliegt und überlässt dem Empfänger die Nachricht zu bearbeiten oder es sein zu lassen.

In Kombination mit cloidnerux Liste ergibt sich so die Möglichkeit viele Empfänger mit vielen Ereignissen zu versorgen. Da wir aber vermutlich hinter jeder Oberfläche nur ein Programm laufen haben, können wir uns vermutlich auch auf einen Empfänger beschränken.
Und jetzt so, das es ein Nichtinformatiker auch versteht...
Na schön, Spass beiseite, ich hab zwar nicht alles davon verstanden, aber ich vermute mal es heißt, dass das was cloidnerux vorgeschlagen hat, für unsere Zwecke ausreicht. Oder? :(
Xin hat geschrieben:Heißt das, ich hätte die Frage noch nicht beantworten dürfen? ;-)
Heißt eigentlich, ich hätte die Frage gar nicht stellen dürfen :P

Re: Ereignisprogrammierung

Verfasst: Mi Jul 07, 2010 10:06 am
von Xin
Bebu hat geschrieben:Und jetzt so, das es ein Nichtinformatiker auch versteht...
Du gibst das Programm als Objekt an die GUI und wenn die GUI was befielt, wird die entsprechende Funktion des Programms aufgerufen - ohne, dass dem Programm Details der GUI bekannt sind.
Bebu hat geschrieben:Na schön, Spass beiseite, ich hab zwar nicht alles davon verstanden, aber ich vermute mal es heißt, dass das was cloidnerux vorgeschlagen hat, für unsere Zwecke ausreicht. Oder? :(
Nicht direkt... eher, dass cloidnerux ein Problem vielfacht löst, wir aber eher viele Probleme haben, die einmalig gelöst werden müssen.
Bebu hat geschrieben:
Xin hat geschrieben:Heißt das, ich hätte die Frage noch nicht beantworten dürfen? ;-)
Heißt eigentlich, ich hätte die Frage gar nicht stellen dürfen :P
Das ist ein Lernprojekt - es geht darum, Fragen zu stellen - und beantwortet zu bekommen.

Re: Ereignisprogrammierung

Verfasst: Mi Jul 07, 2010 4:56 pm
von Bebu
Xin hat geschrieben: Nicht direkt... eher, dass cloidnerux ein Problem vielfacht löst, wir aber eher viele Probleme haben, die einmalig gelöst werden müssen.
Na gut, könntest du mir dafür einen praktischen Ansatz liefern, wie ich das ganze sinnvoll in meine Klasse integrieren kann? Ich habe zwar jetzt eine grobe Idee, aber damit kriege ich das auch nicht in den Code, wenn mir die Grundlagen fehlen. Ich würde ja auch gerne das Konzept dahinter verstehen und für meine zukünftigen Programme anwenden können.

Re: Ereignisprogrammierung

Verfasst: Do Jul 08, 2010 8:05 pm
von Xin
Bebu hat geschrieben:
Xin hat geschrieben: Nicht direkt... eher, dass cloidnerux ein Problem vielfacht löst, wir aber eher viele Probleme haben, die einmalig gelöst werden müssen.
Na gut, könntest du mir dafür einen praktischen Ansatz liefern, wie ich das ganze sinnvoll in meine Klasse integrieren kann? Ich habe zwar jetzt eine grobe Idee, aber damit kriege ich das auch nicht in den Code, wenn mir die Grundlagen fehlen. Ich würde ja auch gerne das Konzept dahinter verstehen und für meine zukünftigen Programme anwenden können.
Eine Möglichkeit habe ich ja bereits im Code verewigt.

Ansonsten machst Du eine Klasse Controller, die alle relevanten Befehle des Programms kennt, die der User mit der Benutzeroberfläche auslösen kann

Code: Alles auswählen

class Controller
{
  public:
    void AddFile( DedupeFile & newFile );
    void RemoveFile( DedupeFile & toRemove );

    bool Quit( void );
    void CreateIndex( std::list< DedupeFile * > files );
    ...
}
Das Objekt übergibt man der GUI und die GUI ruft die entsprechenden Funktionen auf, z.B. Quit() wenn das X gedrückt wird. Das Programm sichert alle Einstellungen usw... Die GUI fragt ab, ob true zurückkommt und beendet sich dann. Wir sind wieder in der Hauptanwendung, die das GUI-Objekt killt und dann das Programm beendet.

Re: Ereignisprogrammierung

Verfasst: Fr Jul 09, 2010 2:43 am
von Bebu
Super danke, jetzt habe ich es auch verstanden, also das Konzept zumindest. Allerdings muss die Gui ja auch auf bestimmte Ereignisse warten, die über das Controllerobjekt gestartet werden. Als Beispiel sei eine Meldung genannt, die ausgegeben werden soll, wenn ein Suchvorgang abgeschlossen ist. Wie kann man das berücksichtigen? Oder stehe ich gerade mit beiden Füßen auf dem Schlauch?

Re: Ereignisprogrammierung

Verfasst: Fr Jul 09, 2010 9:09 am
von Xin
Bebu hat geschrieben:Super danke, jetzt habe ich es auch verstanden, also das Konzept zumindest. Allerdings muss die Gui ja auch auf bestimmte Ereignisse warten, die über das Controllerobjekt gestartet werden. Als Beispiel sei eine Meldung genannt, die ausgegeben werden soll, wenn ein Suchvorgang abgeschlossen ist. Wie kann man das berücksichtigen? Oder stehe ich gerade mit beiden Füßen auf dem Schlauch?
Der Controller baut die Software auf (Controller::Controller()), also erzeugt er auch ein GUI-Objekt.

Code: Alles auswählen

Controller::Controller()
{
  GUIInterface * myGUI;

  switch( prefs.GUI ) 
  { 
    case GUI::wxWidgets: myGUI = new wxWidgetsGUI( *this ); break;
    case GUI::Qt: myGUI = new QtGUI( *this ); break;

    default:
    case GUI::NCurses: myGUI = new NCursesGUI( *this ); break;
  }

  if( !myGUI )
    fprintf( stderr, "No Gui\n" );
  else
    myGUI.TakeOver( *this );
}

Controller::AddFile( DedupeFile & newFile )
{
  /* Die TakeOver-Funktion eines beliebigen GUIs hat vom User gesagt bekommen, dass er ''newFile'' in die Liste aufnehmen soll,
      darum ruft sie nun diese Funktion */
}