gtkmm: Code organisieren



  • Hallo,

    ich verstricke mich gerade ziemlich...

    Also: Es gibt mehrere Fenster, in denen Einstellungen vorgenommen werden, unter anderem in einem TreeModel. Es gibt eine Singleton-Klasse, die alle relevanten Widgets als Membervariablen hat. So ist das Abspeichern sehr einfach: die Schreib-Funktion holt sich eine Instanz des Singletons und schreibt alle Werte in eine Datei. Soweit einfach.

    Jetzt kommt das Einlesen und die Probleme fangen an:
    Meine Idee war, eine neue Instanz der Singleton-Klasse zu erzeugen.
    Probleme:
    - woher wissen die Fenster, dass sie neu initialisiert werden müssen?
    - das TreeModel ist ein Glib::RefPtr, wird also erst gelöscht, wenn der Container gelöscht wird. Das passiert aber nicht, also wird weiter der alte Tree angezeigt.
    - womöglich gibt es Speicherlecks?

    Nun dachte ich, man müsste das, was in main() passiert, wiederholen: Einfach alle Fenster neu erzeugen. Vorher muss man sicher sein, dass das alte wirklich weg ist.

    Unten ist ein stark vereinfachter Code, der ausführbar ist und das Problem verdeutlicht: Man ändert den Text im TreeView und klickt dann auf "Öffnen".
    Der Entry verschwindet und der TreeView zeigt den eingegebenen Text an. Gewünscht ist, dass alles wie nach einem Neustart aussieht. Am Besten auch im Speicher...

    Nun versuche ich, beantwortbare Fragen zu stellen:
    - Ist generell die Idee mit dem Singleton sinnvoll oder gibt es eine andere, einfachere Standard-Lösung für sowas?
    - Vielleicht kann man mit Signalen den Fenstern mitteilen, sich zu initialisieren. Wie könnte die Funktionsweise sein?
    - Gibt es eine Methode, quasi einen kompletten Neustart der Anwendung zu erreichen? Das wäre vielleicht die sicherste Methode.
    - Oder wie könnte eine While-Schleife in main() gestaltet sein?

    #include <gtkmm.h>
    
    // classes 
    class ModelComponents
    {
    private:
        ModelComponents();
        static ModelComponents* instance;
    public:
        static ModelComponents* getInstance();
        static ModelComponents* getFreshInstance();
        virtual ~ModelComponents();
    
        Gtk::Entry m_Entry_projectData;
    
        Glib::RefPtr<Gtk::TreeStore> m_refTreeModel; 
        class MyColumnRecord : public Gtk::TreeModel::ColumnRecord
        {public:
            Gtk::TreeModelColumn<std::string> m_name;
            MyColumnRecord() { add(m_name); }
        };
        MyColumnRecord m_MyColumnRecord;
    };
    
    class WindowMain : public Gtk::Window
    {
    public:
        WindowMain();
        virtual ~WindowMain();
        virtual void on_button_open_clicked();
        virtual void on_button_quit_clicked();
    protected:
        virtual void configure();
        // Public widgets:
        ModelComponents *m_Pglob_model;
        Gtk::Entry *m_PEntry_projectData;
        Glib::RefPtr<Gtk::TreeStore> m_refTreeModel; // model ...
        ModelComponents::MyColumnRecord *m_PMyColumnRecord;
        // Child widgets:
        Gtk::VBox m_VBox;
        Gtk::HButtonBox m_HButtonbox;
        Gtk::Button m_Button_open, m_Button_quit;
        Gtk::TreeView m_TreeView;                    // ... and view
    };
    
    // global functions
    int main(int argc, char* argv[])
    {
        Gtk::Main kit(argc, argv);
        WindowMain window;
        Gtk::Main::run(window);
    
        return 0;
    }
    void project_read( const std::string & fname )
    {
        ModelComponents* Pglob_model = ModelComponents::getFreshInstance();
        Pglob_model->m_Entry_projectData.set_text("project data read from a file");
    }
    
    // implementations
    ModelComponents::ModelComponents()
    {
        m_refTreeModel = Gtk::TreeStore::create(m_MyColumnRecord);
    }
    ModelComponents::~ModelComponents(){}
    
    ModelComponents* ModelComponents::instance = NULL;
    ModelComponents* ModelComponents::getInstance()
    {
        if( instance == NULL )
        {
            instance = new ModelComponents();
        }
        return instance;
    }
    ModelComponents* ModelComponents::getFreshInstance()
    {
        delete instance;
        instance = new ModelComponents();
        return instance;
    }
    
    WindowMain::WindowMain()
    {
        configure();
    }
    void WindowMain::configure()
    {
        m_Pglob_model = ModelComponents::getInstance();
        m_refTreeModel = m_Pglob_model->m_refTreeModel;
        m_PMyColumnRecord = &(m_Pglob_model->m_MyColumnRecord);
    
        Gtk::TreeModel::Row row = *(m_refTreeModel->append());
        row[m_PMyColumnRecord->m_name] = "Fresh";
    
        m_TreeView.set_model(m_refTreeModel);
        m_TreeView.get_selection()->set_mode(Gtk::SELECTION_SINGLE);
        m_TreeView.set_headers_visible(true);
    
        m_TreeView.append_column_editable("Name", m_PMyColumnRecord->m_name);
    
        m_TreeView.show();
    
        m_PEntry_projectData = &(m_Pglob_model->m_Entry_projectData);
        m_PEntry_projectData->show();
    
        m_Button_quit.signal_clicked().connect(sigc::mem_fun(*this,
            &WindowMain::on_button_quit_clicked) );
        m_Button_quit.set_label("Beenden");
        m_Button_quit.show();
        m_Button_open.signal_clicked().connect(sigc::mem_fun(*this,
            &WindowMain::on_button_open_clicked) );
        m_Button_open.set_label("\xC3\x96""ffnen");
        m_Button_open.show();
    
        m_HButtonbox.add(m_Button_quit);
        m_HButtonbox.add(m_Button_open);
        m_HButtonbox.show();
    
        m_VBox.pack_start(*m_PEntry_projectData, false, false, 5);
        m_VBox.pack_start(m_TreeView, true, true, 5);
        m_VBox.pack_start(m_HButtonbox, false, false, 5);
        m_VBox.show();
    
        add(m_VBox);
        show();
    }
    
    void WindowMain::on_button_quit_clicked()
    { 
        hide(); 
    }
    
    void WindowMain::on_button_open_clicked()
    {
        project_read( "/some/file/name.txt" );
    }
    
    WindowMain::~WindowMain(){}
    

    Editiert: letzte Tippfehler beseitigt...

    ... Vielen Dank für alle Antworten!



  • Meine Idee war, eine neue Instanz der Singleton-Klasse zu erzeugen.

    Hm.. das versteh ich nicht. Wozu?



  • Die meisten Default-Werte entstehen durch die Default-Konstruktoren der Widgets. Das wäre dann weiter so bequem.



  • namtel schrieb:

    Die meisten Default-Werte entstehen durch die Default-Konstruktoren der Widgets. Das wäre dann weiter so bequem.

    Da du beim lesen ja eigentlich das gleiche wie beim schreiben auswertest, ist das doch eigentlich egal, oder?



  • Stimmt. Also ich nutze weiter das bisherige Singleton-Objekt.


Anmelden zum Antworten