wxWidgets (newbie): wie erfährt ein Frame von seinem member?



  • Hi!
    ne (anfänger)frage zu wxWidgets:
    ich hab ein Frame, das hat einen member pListBox, also einen pointer auf ne listbox.
    über einen menupunkt öffnet sich die listbox.
    wie kann das Frame davon erfahren, falls ich die listbox schliesse? 😕 die listbox ist nicht modal!

    (ich würde den pointer dann nämlich ganz gerne wieder auf 0 setzen..)


  • Mod

    Hä ?

    Also, ich habe in der regel einen Sizer auf dem Frame,
    und tue die Controls mittels sizer->Add(mycontrol) darauf.

    Könntest du mal deutlicher ausdrücken was du machen willst ?
    Oder evtl. etwas Code posten ?



  • also, vielleicht bin ich ja auch vernagelt, und man kann das alles ganz anders lösen...
    ich denke, man müsste da was mit event.Skip() machen können, aber da blick ich nicht so ganz durch..

    meine listbox ist nicht immer offen. es wird irgendwann auch mehrere listboxen geben und je nachdem,was der user sehen will, ist die eine oder die andere oder mehrere offen.

    also mein haupfenster enthält jetzt einen pointer auf eine klasse die eine listbox enthält. diese klasse (DriverListBox) erbt von wxDialog.

    wenn das programm startet wird die listbox mit einigen namen geöffnet. der user kann die listbox aber auch schliessen. falls der user dies tut, sollte mein MainFrame irgendwie davon erfahren, damit der pointer wieder auf 0 gesetzt werden kann.(was ja nix anderes bedeutet, als das die listbox gerade nicht geöffnet ist.)

    wenn jetzt über ein menu ein neuer name hinzugefügt wird, soll die listBox upgedated werden, dazu müssen alle namen aus einer sortierten liste von einträgen ausgelesen werden und in die listbox übertragen werden. ( aber nur falls diese überhaupt offen ist.)

    hier ein auszug aus der hauptfensterklasse:

    class MainFrame: public wxFrame
    {
    private:
       DriverListBox* driverList;  //<-das hier ist die klasse, die die listbox enthält (erbt von wxDialog). 
    public:
       MainFrame(const wxChar* title, int xpos, int ypos, int width, int height);
       ~MainFrame();
    
       wxMenuBar*  menuBar;
       wxMenu*     fileMenu;
       wxMenu*     editMenu;
       wxMenu*     showMenu;
       wxMenu*     helpMenu;
    
       //fileMenu funs..
       void OnOpenFile(wxCommandEvent& event);
       void OnSave    (wxCommandEvent& event);
       void OnSaveAs  (wxCommandEvent& event);
       void OnExit    (wxCommandEvent& event);
       //editMenu funs..
       void OnEditDriver(wxCommandEvent& event);
       //showMenu funs..
       void OnShowDrivers(wxCommandEvent&event);
       //KontextMenu funs..
       void OnRightClick(wxMouseEvent& event);
       //helpMenu funs..
       void OnAbout   (wxCommandEvent& event);   
    
       DECLARE_EVENT_TABLE()
    };
    

    so, ich fürchte die verwirrung ist jetzt noch schlimmer??

    mfg


  • Mod

    Die Listbox ist also in einem eigenständigen Dialog ?
    Falls du es auf den Frame packen willst, solltest du wxPanel
    als Basisklasse nehmen. Aber weshalb hast du überhaupt
    die ListBox in eine andere Klasse gekapselt ?



  • weils ein dialog sein soll, der bei bedarf auf und zu gemacht werden kann. und es soll ein eigenes frame sein, das man nach belieben hin und her schieben kann.
    teilweise aus übersichtlichkeitsgründen. (damit mainframe.cpp nicht tausende zeilen code enthält).
    teilweise weil ichs ausm tutorial habe und meinen bedürfnissen angepasst habe.

    was ich am liebsten will, ist dass beim schliessen des listboxdialogs ein event erzeugt wird, das in der kapselnden klasse (MainFrame) bemerkt wird und dadurch darauf reagiert werden kann. mit EVT_CLOSE und skip kann das wohl nicht gehen...?
    das event system wird mir anhand der doku noch nicht so ganz klar...



  • prokaion schrieb:

    was ich am liebsten will, ist dass beim schliessen des listboxdialogs ein event erzeugt wird, das in der kapselnden klasse (MainFrame) bemerkt wird und dadurch darauf reagiert werden kann. mit EVT_CLOSE und skip kann das wohl nicht gehen...?
    das event system wird mir anhand der doku noch nicht so ganz klar...

    wie machst du den Dialog zu?
    Mittels "wxWindow::Close()" oder über das X oder das Systemmenü?

    Habs nicht getestet, aber dann müsste das mittels

    EVT_CLOSE(func)

    funktionieren.

    Die Handlerfunktion kriegt ein wxCloseEvent mit.
    Da dieses von wxEvent abgeleitet ist, kann man mit der Methode
    "GetId()" die Id von dem Objekt abfragen, das das Event ausgelöst hat.

    Was ich allerdings nicht kapiert hab, ist, wie eine ListBox offen sein kann...



  • offene listBox? ok, vielleicht hab ich mich blöd ausgedrückt...

    die listbox ist bestandteil eines von mir definierten dialogs. die klasse heisst DriverListBox und erbt von wxDialog. es ist ein eigenes frame, hat eine eigene event-table usw..
    und diesen dialog kann man auf und zu machen. (über ein menu aufmachen (im MainFrame)) und über das X auf dem dialog-fenster zu machen..
    hier die .h -datei. der code ist gerad etwas wirr, weil ich da was rumprobiert habe..

    //DriverListBox.h
    class DriverListBox : public wxDialog
    {
    public:
       explicit DriverListBox(wxFrame* pframe);
       void init();
       void close() { Close(); }
    protected:
       void OnClose(wxCloseEvent& event);
       void OnClick(wxCommandEvent& event);
    
       DECLARE_EVENT_TABLE()
    private:
       enum
       {
          ID_LISTBOX = 1000
       };
    
       wxListBox* _pListBox;
    
    };
    

    ok, das mit der id des objektes, das das close ausgelöst hat, könnte mir vielleicht weiterhelfen.

    danke erstmal, mal ausprobieren!
    mfg
    prokaion



  • nö, klappt erstmal nicht. wenn ich in der doku richtig verstehe, haben closeevents auch gar keine id....
    eigentlich bräuchte ich ein commandEvent. weiss nur nicht, wie ich das erzeugen soll..
    die ergebnisse der tests sind allerdings ziemlich verwirrend 😕



  • ok, hab mich etz a bissl gespielt.
    Ist zwar nicht ganz sauber, aber funktionieren tuts:

    im Frame wird der Dialog erzeugt:

    DriverListBox * d = new DriverListBox(this, myDialogId);
    d->Show(true);
    

    Jetzt im Dialog mit EVT_CLOSE das Closeevent abfangen und einen handler dafür bauen:

    BEGIN_EVENT_TABLE(DriverListBox, wxDialog)
    	EVT_CLOSE(DriverListBox::onClose)
    END_EVENT_TABLE()
    
    void DriverListBox::onClose(wxCloseEvent & Event)
    {
    	// Wenn möglich, den Frame nur unsichtbar machen, 
    	// andernfalls zerstören
    	if (Event.CanVeto() == true)
    	{
    	Event.Veto();
    	Show(false);
    	}
    	else
    	{
    	wxMessageBox("Frame destroyed");
    	Destroy();
    	}
    
    // jetzt ein Event für den Frame auslösen, und das ist das unschöne an der Sache:
    // hab keinen Schimmer, wie/ob man eigene Events bauen kann, darum wird hier das
    // wxEVT_COMMAND_TEXT_UPDATED - Event missbraucht, um dem Parentframe mitzuteilen, dass
    // der Dialog geschlossen wurde
    
    // Event bauen
    wxCommandEvent e(wxEVT_COMMAND_TEXT_UPDATED, GetId());
    
    // dieses Object als Auslöser angeben
    // (kann dann im Eventhandler mit "GetEventObject()" abgeholt werden
    e.SetEventObject(this);
    
    // Event für den Frame auslösen
    GetParent()->GetEventHandler()->ProcessEvent(e);
    }
    

    zurück im Frame:

    EVT_TEXT(myDialogId, myFrame::onDialogClose)
    
    myFrame::onDialogClose(wxCommandEvent & Event)
    {
    ShowMessage("Dialog wurde geschlossen");
    
    }
    

    Anmerkung zu dem Destroy() in DriverListBox::onClose()

    man kann sich dort die Abfrage auch schenken, und in jedem Fall ein "Destroy()"
    aufrufen.
    Allerdings wird dadurch der Dialog zerstört, und es gibt keinen Zugriff mehr auf
    die Elemente (z. B. die Listbox).
    Drum im Idealfall das "Destroy()" erst im Eventhandler aufrufen, nachdem man
    die Daten ausgelsen hat.
    Alternativ kann man den Dialog auch einfach nur versteckt lassen und bei Bedarf dann
    wieder anzeigen (Statusabfrage mit "IsShown()")
    Somit "merkt" sich der Dialog schon von selbst, ob er sichtbar ist oder nicht.

    Allerdings ist es so wie oben gezeigt auch nicht ganz richtig.
    Wenn in DriverListBox::onClose() schon ein "Destroy()" aufgerufen wird,
    dann darf das natürlich im Frame nicht nochmal gemacht werden.
    Um das zu Verhindern, müsste man wohl zwei verschiedene Events erzeugen
    und entsprechend drauf reagieren.

    mfg
    Martin



  • aha...
    naja, was mit event selbst erzeugen hab ich zwischendurch auch probiert, das hat aber bei mir nicht geklappt, auch weil ich in der doku nix über wxTYPE gefunden habe. dein wxEVT_COMMAND_TEXT_UPDATED scheint ja wahrscheinlich so ein wxTYPE zu sein!? ich wusste also nicht genau wie ich ein event constructen soll...

    abgesehen davon war ich wirklich vernagelt! im ctor vom DriverListBox wird ja ein pointer auf das parentFrame(Mainframe) mit übergeben. über den kann ich dann ja ziemlich einfach (musste ihn noch nach MainFrame casten, weil er vom Typ wxFrame war) auf die member von MainFrame zugreifen. vielleicht auch nicht die feinste englische art, aber etwas sauberer und verständlicher als die eventerzeugungsmethode ist es schon...

    am ende sahs einfach so aus:

    void DriverListBox::OnClose(wxCloseEvent& event)
    {
    Destroy();
    ((MainFrame*)_parent->resetDriverListPtr(); //<-setzt den pointer auf 0..
    }
    

    ob ich es lieber mit Close oder Destroy zumachen sollte, weiss ich aber auch noch nicht so genau, das muss ich mir noch mal genau reinziehen... 😕


Anmelden zum Antworten