[wxWidgets] Pluginfähige Anwendung und Events
-
Hallo zusammen,
ich entwickle im moment zum testen eine kleine Applikation die Plugins (mit GUI) laden und hinzufügen kann. Das hinzufügen von GUI Elementen (im moment einfach mal nur Menüpunkte) funktioniert soweit auch problemlos. Nun habe ich aber ein Problem dabei den Event der hinter dem Menüpunkt liegt auszulösen.
Vielleicht hat ja jemand ne Idee wie sich das bewerkstelligen ließe.
Der komplette Quellcode ist unter http://rapidshare.de/files/41241365/PluginApp.zip.html downloadbar.
-
Hi,
also wenn ich dich richtig verstehe, willst du, wenn auf den Menüpunkt geklickt wird, das Event zum entsprechenden Plugin weiterleiten.
So davon gehe ich jetzt einfach mal aus, da ich dann das selbe Problem hatte, bloß mit Pythonplugins anstatt dynamische Libs. Ich habe es so gelöst, dass ich das Observer Pattern genutzt habe, sprich alle Plugins sind Observer mit einer Update-Methode. So das Plugin registriert seinen Menüeintrag und wird dann in einen Container gepackt, was du ja auch schon mit deinem PluginBase vector gemacht hast. Allerdings muss das Plugin beim Menü registrieren eine ID übergeben, anhand derer das Plugin identifiziert werden kann. Dazu habe ich eine std::map genommen, die als Index die ID benutzt und als Wert den Observer speichert. Zu guter letzt noch muss dem Menuitem bei der Erstellung auch die ID zugewiesen werden. Okay abschließend brauchen wir noch eine OnMenuItemClick-Methode, die alle Klick Events jedes Menüpunkts erhält und überprüft ob die ID des Menuitems in der Map ist, wenn ja dann die Update Methode des dazugehörigen Observers/Plugins aufrufen, ansonsten das event skippen, damit es zum richtigen Click Handler kommt.
So das war jetzt wahrscheinlich nicht so verständlich deshalb hier mein Code dazu vllt. hilft er dir:class CSVExporter(LoW.Listener): def Update(self,Subject): //Die Pythonklasse leitet vom observer ab und definiert eine Update-Methode
Die Registrierung des Menüs:
CSVExporter = CSVExporter() LoW.UI.GetMenuBar().AppendMenu("embedd_test").AppendItem(500,"Test","test").OnClick(CSVExporter) //So wird eine Menü angehungen, mit der entsprechenden ID und bei Onclick wird der Observer aufgerufen
Nun die C++/wxWidgets Seite:
class MenuItem { private: wxMenu* m_Menu; public: [...] void OnClick(boost::python::object listener) { if( m_Menu == 0 ) { throw std::runtime_error("Das Menü ist nicht zugeordnet"); } l = boost::python::extract<Listener>(listener); static_cast<Lord_of_WareFrm*>(wxTheApp->GetTopWindow())->AddListener(ID,l); } //Es wird einfach der Frame hergecastet und dort die entsprechende Methode aufgerufen };
Diese Methode kommt nun:
void AddListener(int ID, const Listener& l) { listeners[ID]=l; //eine std::map<int,Observer> um die Zuordnung zu halten }
So nun zum Schluß kommt die allgemeine OnClick-Methode für MenüEvents
void Lord_of_WareFrm::PythonPluginClick(wxCommandEvent& e) { std::map<int,Listener>::iterator it; it = listeners.find(e.GetId()); //Gucken, ob die Menü ID einem Plugin/Observer zugeordnet ist if( it != listeners.end() ) { it->second.Update(&VarManager::Get()); //Wenn ja die Update Methode des Observers aufrufen } else e.Skip(); //Ansonsten das Event durchlaufen lassen, damit der richtige Handler vom Frame aufgerufen wird }
Somit wird also das Plugin bei einem von ihm registrierten Menü benachrichtigt.
Ich hoffe es hilft dir.
Gruß gate
-
Hi Gate,
danke für den Vorschlag. Dies wäre natürlich eine Lösungsmöglichkeit. Allerdings bin ich der festen Überzeugung das es auch anderster (so ähnlich wie ich es habe) gehen muß.
-
Ja, da hast du wohl recht, gerade da du die Plugins aus einer dynamischen Lib lädst, solltest du die Events zu deinen Plugins leiten können. Qie siegts denn aus wenn du die Connect()-Methode für die Events benutzt? Allerdings müssten deine Plugins dann wohl von wxEventHandler ableiten. Hmm, sorry ich kann dir wohl nicht weiterhelfen.
-
Gate schrieb:
Ja, da hast du wohl recht, gerade da du die Plugins aus einer dynamischen Lib lädst, solltest du die Events zu deinen Plugins leiten können. Qie siegts denn aus wenn du die Connect()-Methode für die Events benutzt? Allerdings müssten deine Plugins dann wohl von wxEventHandler ableiten. Hmm, sorry ich kann dir wohl nicht weiterhelfen.
Also, das Basis Plugin ist von der Klasse wxEventHandler abgeleitet und der Connect auf den Menüpunkt ist ebenfalls gesetzt. Aber anscheinend wird das ganze einfach nicht aufgerufen.
Schauen wir mal, vielleicht hat ja noch jemand anderes ne Lösungsidee. Über die Feiertage wird eventuell nicht unbedingt noch viel hier rumkommen, da die meisten ja weggefahren sind oder keine Zeit haben, aber ich geh mal davon aus nächstes Jahrvielleicht noch ne gute Idee zu kriegen.
-
Hat wirklich niemand anderes noch eine Idee für eine Lösung?!
-
Vielleicht hilft dir dieser Thread weiter:
http://wxforum.shadonet.com/viewtopic.php?t=8803
-
phlox81 schrieb:
Vielleicht hilft dir dieser Thread weiter:
http://wxforum.shadonet.com/viewtopic.php?t=8803Leider Nein. In dem Thread wird nur ein Element aus dem Plugin der Hauptapplikation hinzugefügt, was bei mir ja ebenfalls funktioniert. Nur das Event wird nicht ausgelöst wenn man drauf drückt.
Hier hab ich auch mal nen Thread (http://wxforum.shadonet.com/viewtopic.php?t=22392) aufgemacht. Wenn ich Recht verstanden habe, hats bei JimFairway funktioniert.
-
Linkst du dynamisch?
-
phlox81 schrieb:
Linkst du dynamisch?
Die DLL wird per wxDynamicLibrary geladen, oder meinst du das wxWidget Framework?
Betriebssystem ist Ubuntu 8.04 LTS, falls dir dies irgendwie weiterhilft?!
-
meinte wxWidgets.
-
Müsste meines wissens nach dynamisch sein...
-
In der wxDoku steht folgendes :
If the menu is part of a menubar, then wxMenuBar event processing is used.
In deinem Fall sollte also ein
pMenuBar->Connect(...)
genügen.
Die Connect-Routinen funktionieren immer, nur die Event-Emitter nicht immer trivial ersichtlich.
Gruß
wxNurF
-
@nurf
Danke, den Satz hab ich wohl übersehen.
Naja, hab das ganze nun mal abgeändert, aber passieren tut dennoch nichts. Es bleibt somit leider alles beim alten.
-
Ja das kenne ich zu gut.
Das wxEventSystem ist nicht trivial ...Am besten meldest du dich mal per ICQ bei mir.
Ansonsten kann ich pauschal noch debuggen empfehlen, das hilft nicht immer, aber in manchen Fällen, wird das wxEventProcessing klarer (internals).
-
Vielleicht postest du einfach mal den entsprechenden Code.
Weil so können wir auch nur rumraten.
-
phlox81 schrieb:
Vielleicht postest du einfach mal den entsprechenden Code.
Weil so können wir auch nur rumraten.Hier mal der Code der geänderten Funktion. Wenn noch mehr Code benötigt wird, einfach bescheid sagen...
void MyPlugin::CreateMenu(wxMenuBar *pMenuBar) { wxMenu *pPluginMenu = new wxMenu(); pPluginMenu->Append(1000, wxT("MyPlugin1")); pMenuBar->Append(pPluginMenu, wxT("Plugins")); pMenuBar->Connect( 1000, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MyPlugin::OnMenuClicked), NULL, this ); }
@nurf
Kann ich machen, kann aber ein paar Tage dauern...
-
Ähm, ist das denn der richtige Event für Menüs?
-
phlox81 schrieb:
Ähm, ist das denn der richtige Event für Menüs?
Ich denke doch mal schon. Es passier aber auch nichts wenn ich das ganze durch wxEVT_COMMAND_MENU_SELECTED ersetze...
-
guenni81 schrieb:
phlox81 schrieb:
Ähm, ist das denn der richtige Event für Menüs?
Ich denke doch mal schon. Es passier aber auch nichts wenn ich das ganze durch wxEVT_COMMAND_MENU_SELECTED ersetze...
Ja, wxEVT_COMMAND_MENU_SELECTED ist der korrekte event. Was sagt denn der Debugger?