[gtkmm] Wie funktioniert der ListStore?



  • Hi Leute,

    kann mir einer von euch mal erklären, wie man den ListStore verwendet? Ich hab mir das Beispiel in der Dokumentation durchgelesen, aber ich steig da irgendwie nicht so ganz durch. Hat da einer von euch vielleicht ein einfacheres Beispiel? Wäre sehr nett von euch. ^^ Danke schonmal...

    MfG Apo



  • Na ja, die Listen- bzw. Baumwidgets sind in gtkmm der härteste Brocken. Sie sind sehr flexibel und mächtig (zudem toll, um Design Patterns im Einsatz zu sehen 😉 ), allerdings auch komplex und etwas unhandlich.
    Ein viel einfacheres Beispiel als das des Tutorials kann ich dir auch nicht geben. Was genau verstehst du denn nicht?



  • Ich bekomm es nicht mal hin, dass das ListStore angezeigt wird. Hast kannst du mir da vielleicht eine ganz kurze Einweisung geben? Ich musst das vererben, soweit bin ich schon, aber ich raff das nicht so richtig, wie das dann machen soll. xD

    Wäre nett...

    MfG Apo



  • Okay, ich werde mal ein einfaches Beispiel zusammenbasteln und beschreiben. Dauert aber evtl. etwas.



  • Schau mal hier: http://www.c-plusplus.net/forum/viewtopic-var-p-is-1000591.html#1000591
    Ist teilweise kommentiert, aber ansonsten einfach zu verstehen.

    Die inner Klasse "ModelColumns" repräsentiert die Spalten der Tabelle, jenachdem kann man dort dann mehrere Spalten einfügen.
    Kannst ja mal mit dem Code was rumspielen 😉



  • OMG..., danke! Das sieht schon wesentlich einfacherer aus. Damit werde ich bestimmt zurecht kommen. Danke.

    MfG Apo



  • Gut, weniger Arbeit für mich 😃



  • Habe dank dem kurzen Tut von KasF geschafft eine Liste zu erstellen. Nun würde ich es gern so machen, dass wenn ich auf ein Listenelement klicke, dass die Daten zu der jeweiligen Person, aus einem Array des Typs Person*, ausgelesen werden und in den jeweiligen Textfeldern ausgegeben werden . Mein bisheriger Quelltext sieht so aus:

    telefonbuch.hpp

    //--- Definitionen ----------------------------------------
    #ifndef _TELEFONBUCH_HPP
    #define _TELEFONBUCH_HPP
    
    //--- Header-Dateien --------------------------------------
    #include <gtkmm/alignment.h>
    #include <gtkmm/box.h>
    #include <gtkmm/button.h>
    #include <gtkmm/entry.h>
    #include <gtkmm/label.h>
    #include <gtkmm/liststore.h>
    #include <gtkmm/scrolledwindow.h>
    #include <gtkmm/treemodelcolumn.h>
    #include <gtkmm/treeview.h>
    #include <gtkmm/window.h>
    #include "ModelColumns.hpp"
    #include "person.hpp"
    
    //--- Klasse Telfonbuch -----------------------------------
    class Telefonbuch : public Gtk::Window
    {
    public:
        // Konstruktor und Destruktor
        Telefonbuch();
        virtual ~Telefonbuch();
    
        // Spalten
        ModelColumns m_Columns;
    
    protected:
        // anzeigen der Personendaten nach der Auswahl
        virtual void on_person_select();
    
        // beenden des Programms
        virtual void on_button_beenden();
    
        // Widgets
        Gtk::ScrolledWindow m_ScrolledWindow;
        Gtk::Alignment m_Alignment;
        Gtk::HBox   m_hboxNachname, m_hboxVorname, m_hboxStrasse,
                    m_hboxHNr, m_hboxPLZ, m_hboxOrt, m_hboxTelefon, m_hboxHandy,
                    m_hboxEMail, m_hboxButtons;
        Gtk::VBox   m_vboxOuter, m_vboxPersDaten;
        Gtk::Label  m_lblNachname, m_lblVorname, m_lblStrasse, m_lblHNr,
                    m_lblPLZ, m_lblOrt, m_lblTelefon, m_lblHandy, m_lblEMail;
        Gtk::Entry  m_txtNachname, m_txtVorname, m_txtStrasse, m_txtHNr,
                    m_txtPLZ, m_txtOrt, m_txtTelefon, m_txtHandy, m_txtEMail;
        Gtk::Button m_btnNeu, m_btnSpeichern, m_btnBeenden;
        Gtk::TreeView m_tview;
        Glib::RefPtr<Gtk::ListStore> m_refTreeModel;
        Person* pPersonen[300];
        unsigned int m_uiAnzPersonen;
    };
    
    #endif // _TELFONBUCH_HPP
    

    telefonbuch.cpp

    //--- Header-Dateien --------------------------------------
    #include <fstream>
    #include <string>
    #include "telefonbuch.hpp"
    
    //--- Konstruktor -----------------------------------------
    Telefonbuch::Telefonbuch()
    : m_lblNachname("Nachname:"), m_lblVorname("Vorname:"), m_lblStrasse("Straße:"),
      m_lblHNr("Hausnummer:"), m_lblPLZ("PLZ:"), m_lblOrt("Ort:"),
      m_lblTelefon("Telefon:"), m_lblHandy("Handy:"), m_lblEMail("E-Mail:"),
      m_btnNeu("Neu"), m_btnSpeichern("Speichern"), m_btnBeenden("Beenden"),
      m_uiAnzPersonen(0)
    {
        // personen.dat zum Lesen öffnen
        std::ifstream fin("personen.dat");
    
        // deklarieren der benötigten Variablen
        std::string     strNName, strVName, strStrasse, strHNr, strPLZ, strOrt,
                        strTelefon, strHandy, strEMail;
    
        // Erstdaten auslesen
        fin >> strNName >> strVName >> strStrasse >> strHNr >> strPLZ >> strOrt
            >> strTelefon >> strHandy >> strEMail;
    
        // neue Person erzeugen
        pPersonen[m_uiAnzPersonen++] = new Person(strNName, strVName, strStrasse, strHNr,
                                                  strPLZ, strOrt, strTelefon, strHandy,
                                                  strEMail);
    
        do
        {
            // weitere Daten auslesen
            fin >> strNName >> strVName >> strStrasse >> strHNr >> strPLZ >> strOrt
                >> strTelefon >> strHandy >> strEMail;
    
            // weitere Person erzeugen
            pPersonen[m_uiAnzPersonen++] = new Person(strNName, strVName, strStrasse,
                                                      strHNr, strPLZ, strOrt,
                                                      strTelefon, strHandy, strEMail);
        } while(fin.eof());
    
        // Spalten definieren
        m_refTreeModel = Gtk::ListStore::create(m_Columns);
        m_tview.set_model(m_refTreeModel);
    
        // Spalten mit Zeilen füllen
        Gtk::TreeModel::Row row;
    
        for(unsigned int i = 0; i < m_uiAnzPersonen; i++)
        {
            row = *(m_refTreeModel->append());
            row[m_Columns.m_ID]       = i+1;
            row[m_Columns.m_Nachname] = pPersonen[i]->GetNName();
            row[m_Columns.m_Vorname]  = pPersonen[i]->GetVName();
        }
    
        // Spalten dem Treeview hinzufügen
        m_tview.append_column("ID", m_Columns.m_ID);
        m_tview.append_column("Nachname", m_Columns.m_Nachname);
        m_tview.append_column("Vorname", m_Columns.m_Vorname);
    
        // Fenstertitel setzen
        set_title("Telefonbuch");
    
        // Rahmenabstand festlegen
        set_border_width(10);
    
        // Abstände zwischen den äußeren Bogen
        m_vboxOuter.set_spacing(15);
    
        // Scrollbars nur anzeigen, wenn sie gebraucht werden
        m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    
        // Klick auf eine Person
        m_tview.signal_clicked().connect(sigc::mem_fun(*this, &Telefonbuch::on_person_select));
    
        // Klick auf den Button "Beenden"
        m_btnBeenden.signal_clicked().connect(sigc::mem_fun(*this, &Telefonbuch::on_button_beenden));
    
        // Größe der Boxen homogenisieren
        m_vboxOuter.set_homogeneous();
        m_hboxNachname.set_homogeneous();
        m_hboxVorname.set_homogeneous();
        m_hboxStrasse.set_homogeneous();
        m_hboxHNr.set_homogeneous();
        m_hboxPLZ.set_homogeneous();
        m_hboxOrt.set_homogeneous();
        m_hboxTelefon.set_homogeneous();
        m_hboxHandy.set_homogeneous();
        m_hboxEMail.set_homogeneous();
        m_hboxButtons.set_homogeneous();
        m_vboxPersDaten.set_homogeneous();
    
        // Labels ausrichten
        m_lblNachname.set_alignment(0.05, 0.5);
        m_lblVorname.set_alignment(0.05, 0.5);
        m_lblStrasse.set_alignment(0.05, 0.5);
        m_lblHNr.set_alignment(0.05, 0.5);
        m_lblPLZ.set_alignment(0.05, 0.5);
        m_lblOrt.set_alignment(0.05, 0.5);
        m_lblTelefon.set_alignment(0.05, 0.5);
        m_lblHandy.set_alignment(0.05, 0.5);
        m_lblEMail.set_alignment(0.05, 0.5);
    
        // Fenster zusammensetzen
        m_ScrolledWindow.add(m_tview);
        m_vboxOuter.pack_start(m_ScrolledWindow);
        m_vboxOuter.pack_start(m_vboxPersDaten);
        m_vboxPersDaten.pack_start(m_hboxNachname);
        m_vboxPersDaten.pack_start(m_hboxVorname);
        m_vboxPersDaten.pack_start(m_hboxStrasse);
        m_vboxPersDaten.pack_start(m_hboxHNr);
        m_vboxPersDaten.pack_start(m_hboxPLZ);
        m_vboxPersDaten.pack_start(m_hboxOrt);
        m_vboxPersDaten.pack_start(m_hboxTelefon);
        m_vboxPersDaten.pack_start(m_hboxHandy);
        m_vboxPersDaten.pack_start(m_hboxEMail);
        m_vboxPersDaten.pack_start(m_hboxButtons);
        m_vboxPersDaten.pack_start(m_btnBeenden);
    
        // Entries, Labels und Buttons hinzufügen
        m_hboxNachname.pack_start(m_lblNachname);
        m_hboxNachname.pack_start(m_txtNachname);
        m_hboxVorname.pack_start(m_lblVorname);
        m_hboxVorname.pack_start(m_txtVorname);
        m_hboxStrasse.pack_start(m_lblStrasse);
        m_hboxStrasse.pack_start(m_txtStrasse);
        m_hboxHNr.pack_start(m_lblHNr);
        m_hboxHNr.pack_start(m_txtHNr);
        m_hboxPLZ.pack_start(m_lblPLZ);
        m_hboxPLZ.pack_start(m_txtPLZ);
        m_hboxOrt.pack_start(m_lblOrt);
        m_hboxOrt.pack_start(m_txtOrt);
        m_hboxTelefon.pack_start(m_lblTelefon);
        m_hboxTelefon.pack_start(m_txtTelefon);
        m_hboxHandy.pack_start(m_lblHandy);
        m_hboxHandy.pack_start(m_txtHandy);
        m_hboxEMail.pack_start(m_lblEMail);
        m_hboxEMail.pack_start(m_txtEMail);
        m_hboxButtons.pack_start(m_btnNeu);
        m_hboxButtons.pack_start(m_btnSpeichern);
    
        // äußere Box hinzufügen
        add(m_vboxOuter);
    
        // alle Widgets anzeigen
        show_all_children();
    }
    
    //--- Destruktor ------------------------------------------
    Telefonbuch::~Telefonbuch()
    {
    }
    
    //--- anzeigen der Personendaten nach der Auswahl ---------
    void Telefonbuch::on_person_select()
    {
        // herausfinden, welcher Datensatz ausgewählt ist
        Glib::RefPtr<Gtk::TreeSelection> refTreeSelection = m_tview.get_selection();
        Gtk::TreeModel::iterator iter = refTreeSelection->get_selected();
    
        // testen, ob etwas ausgewählt wurde
        if(iter)
        {
            // ID des ausgewählen Items holen
            Gtk::TreeModel::Row row = *iter;
            unsigned int uiIndex = row[m_Columns.m_ID];
    
            // Daten der ausgewählen Person ausgeben
            m_txtNachname.set_text(pPersonen[uiIndex]->GetNName()); // OB DAS SO GEHT, WEISS ICH AUCH NICHT!!!
        }
    }
    
    //--- beenden des Programms -------------------------------
    void Telefonbuch::on_button_beenden()
    {
        hide();
    }
    

    ModelColumns.hpp

    //--- Definitionen ----------------------------------------
    #ifndef _MODELCOLUMNS_HPP
    #define _MODELCOLUMNS_HPP
    
    //--- Header-Dateien --------------------------------------
    #include <gtkmm/treemodelcolumn.h>
    #include <gtkmm/treeview.h>
    
    //--- Klasse ModelColumns ---------------------------------
    class ModelColumns : public Gtk::TreeModel::ColumnRecord
    {
    public:
        // Konstruktor
        ModelColumns();
    
        // Widgets
        Gtk::TreeModelColumn<unsigned int> m_ID;
        Gtk::TreeModelColumn<Glib::ustring> m_Nachname;
        Gtk::TreeModelColumn<Glib::ustring> m_Vorname;
    };
    
    #endif // _MODELCOLUMNS_HPP
    

    ModelColumns.cpp

    //--- Header-Dateien --------------------------------------
    #include "ModelColumns.hpp"
    
    //--- Konstruktor -----------------------------------------
    ModelColumns::ModelColumns()
    {
        add(m_ID); add(m_Nachname), add(m_Vorname);
    }
    

    Das TreeView hat ja kein Klick-Signal. Aber irgendwie, muss doch mein Programm reagieren können, wenn ich auf einen Listenelement klicke. Wäre euch noch mal sehr dankbar, wenn ihr mir nochmals helfen könnten. 🙂

    MfG Apo



  • Das ganze sieht dann so aus:

    m_tview.signal_row_activated().connect( sigc::mem_fun(*this, &Telefonbuch::on_person_select) );
    //...
    
    void Telefonbuch::on_person_select(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column )
    {
      Gtk::TreeModel::iterator iter = m_refTreeModel->get_iter(path);
    
      if(iter)
      {
        Gtk::TreeModel::Row row = *iter;
    
        unsigned int uiIndex = row[m_Columns.m_ID];
        string name = row[m_Columns.m_Nachname];
        //...
      }
    
    }
    

    Warst also schon nahe dran 😉

    Zudem solltest du vllt überlegen, ob ein std::vector<Person> nicht schöner wäre als ein Person* p[300] und deine Schleife zum Auslesen der Datei sieht auch nicht irgendwie richtig aus und Erstdaten brauchst du auch nicht gesondert auszulesen.
    Machst besser so:

    while(fin >> strNName >> strVName >> strStrasse >> strHNr >> strPLZ >> strOrt
                >> strTelefon >> strHandy >> strEMail )
    {
            pPersonen[m_uiAnzPersonen++] = new Person(strNName, strVName, strStrasse,
                                                      strHNr, strPLZ, strOrt,
                                                      strTelefon, strHandy, strEMail);
    } 
    
    // oder
    while(!fin.eof() && !fin.fail())
    {
            fin >> strNName >> strVName >> strStrasse >> strHNr >> strPLZ >> strOrt
                >> strTelefon >> strHandy >> strEMail 
    
    		if(!fin.fail())                 // oder if(fin.fail()) break;
    		pPersonen[m_uiAnzPersonen++] = new Person(strNName, strVName, strStrasse,
                                                      strHNr, strPLZ, strOrt,
                                                      strTelefon, strHandy, strEMail);
    } 
    
    // oder mit std::vector<Person> persons(300);
    while(!fin.eof() && !fin.fail())
    {
            fin >> strNName >> strVName >> strStrasse >> strHNr >> strPLZ >> strOrt
                >> strTelefon >> strHandy >> strEMail 
    
    		if(!fin.fail())                 // oder if(fin.fail()) break;
    		persons.push_back( Person(strNName, strVName, strStrasse,
                                                      strHNr, strPLZ, strOrt,
                                                      strTelefon, strHandy, strEMail) );
    }
    

    Mal das durchlesen und aufjedenfall den Link am Ende ( der momentan leider nicht funktioniert ) : http://c-plusplus.net/forum/viewtopic-var-p-is-1319931.html

    🙂



  • lol..., war ja echt ganz nah dran. Habe das mit dem signal_row_activated() nirgendwo gefunden. Steht das irgendwo in der Dokumentation?

    Habe auch gestern Abend schon darüber nachgedacht einen std::vector<> zu verwenden und werde das umstellen, wenn ich mit dem Programm zum Größtenteil fertig bin.

    Und ich werde mir mal die Seite, die du noch angehängt hast, ansehen. Mal sehen, was da interessantes steht.

    MfG Apo



  • Apocalypse schrieb:

    Steht das irgendwo in der Dokumentation?

    Bei sowas immer bei jeweiligen Widget unter signals... nachschauen.
    http://www.gtkmm.org/docs/gtkmm-2.4/docs/reference/html/classGtk_1_1TreeView.html

    Apocalypse schrieb:

    Und ich werde mir mal die Seite, die du noch angehängt hast, ansehen. Mal sehen,
    was da interessantes steht.

    Der Link in meinem Link ( 🙂 )ist wesentlich interessanter, vllt hat ja GPC die PDF von dort, oder du wartest bis sie wieder funktioniert



  • PDF 😕 ???



  • Auf Hume's Seite kann man die FAQ auch als pdf runterladen 😉 , aber die Seite ist ehe wieder online, also hat sichs erledigt.



  • Okay..., werde mal gucken, ob ich dort eine PDF-Datei finde oder so etwas.

    Auf jedenfall funktioniert das nun und ich habe auch schon auf einen std::vector<> umgebastelt. Außerdem habe ich meine Dateiauslesung überarbeitet. Nun kann ich weiter arbeiten. ^^

    Das mit dem Auslesen habe ich so gemacht, weil wir das so in der Schule gelernt habe, aber man lernt ja bekanntlich nie aus. 😉

    MfG Apo


Anmelden zum Antworten