# Προβολή δένδρου (Treeview) με αποθήκη καταλόγου (ListStore) (JavaScript)

Taryn Fox
jewelfox@fursona.net 2012
Ένα γραφικό στοιχείο που εμφανίζει μια ξεχωριστή λίστα στοιχείων
Ελληνική μεταφραστική ομάδα GNOME
team@gnome.gr 2012-2015
Δημήτρης Σπίγγος
dmtrs32@gmail.com 2012, 2013
Μαρία Θουκιδίδου
marablack3@gmail.com 2014
Θάνος Τρυφωνίδης
tomtryf@gmail.com 2014, 2015

# Προβολή δένδρου (Treeview) με αποθήκη καταλόγου (ListStore)

Μια προβολή δένδρου (TreeView) μοιάζει με ένα παράθυρο στα περιεχόμενα είτε μιας αποθήκης καταλόγου (ListStore) είτε μιας προβολής δένδρου. Μια αποθήκη καταλόγου μοιάζει με ένα υπολογιστικό φύλλο: μια "επίπεδη", διδιάστατη λίστα πραγμάτων διαιρεμένη σε γραμμές και στήλες. Μια προβολή δένδρου, στο μεταξύ, μπορεί να διακλαδωθεί σε διαφορετικές κατευθύνσεις όπως κάνει ένα δένδρο. Σε αυτό το παράδειγμα, δημιουργήσαμε μια προβολή δένδρου που εμφανίζει τα περιεχόμενα μιας αποθήκης καταλόγου με (εικονικά) ονόματα και αριθμούς τηλεφώνου σε αυτό, και ρυθμίστηκε έτσι ώστε η ετικέτα στο τέλος του παραθύρου να εμφανίζει περισσότερες πληροφορίες σχετικά με οποιοδήποτε όνομα πατάτε.

Η προβολή δένδρου (TreeView) δεν είναι απλά ένα μονό γραφικό στοιχείο, αλλά περιέχει έναν αριθμό μικρότερων γραφικών στοιχείων:

Τα γραφικά στοιχεία στήλης προβολής δένδρου (TreeViewColumn) εμφανίζουν κάθε (κάθετη) στήλη πληροφορίας από τη αποθήκη καταλόγων (ListStore). Καθένα έχει έναν τίτλο που μπορεί να προβληθεί στην κορυφή της στήλης, όπως στο στιγμιότυπο.

Τα γραφικά στοιχεία απεικονιστές κελιού (CellRenderer) "συσκευάζονται" σε κάθε στήλη προβολής δένδρου (TreeViewColumn) και περιέχουν τις οδηγίες πώς να εμφανίσουν κάθε ξεχωριστό "κελί" ή στοιχείο από τη ListStore. Υπάρχουν πολλοί διαφορετικοί τύποι, συμπεριλαμβανόμενου του κειμένου απεικονιστή κελιών (CellRendererText) που χρησιμοποιείται εδώ και του CellRendererPixbuf, που εμφανίζει μια εικόνα "ενδιάμεση μνήμη εικονοστοιχείου").

Τελικά, πρόκειται να χρησιμοποιήσουμε ένα αντικείμενο που λέγεται TreeIter, που δεν είναι γραφικό στοιχείο τόσο πολύ όσο ένας αόρατος δρομέας που δείχνει σε μια (οριζόντια) γραμμή στη ListStore. Οποτεδήποτε πατάτε σε ένα όνομα στον τηλεφωνικό κατάλογο, για παράδειγμα, δημιουργούμε ένα TreeIter που δείχνει τη γραμμή που επιλέχτηκε και έπειτα χρησιμοποιήστε το για να πείτε στη ListStore ποιας εγγραφής θέλουμε η ετικέτα να εμφανίσει περισσότερες πληροφορίες σχετικά.

Η TreeView είναι προφανώς το πιο περίπλοκο γραφικό στοιχείο Gtk, λόγω των πολλών μερών που έχει και του τρόπου συνεργασίας τους. Δώστε στον εαυτό σας τον χρόνο να μάθετε πώς δουλεύει και πειραματιστείτε μαζί του, ή δοκιμάστε πρώτα κάτι ευκολότερο εάν έχετε πρόβλημα.

# Βιβλιοθήκες για εισαγωγή

#!/usr/bin/gjs

const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; const Lang = imports.lang; const Pango = imports.gi.Pango;

Αυτές είναι οι βιβλιοθήκες που χρειαζόμαστε να εισάγουμε αυτήν την εφαρμογή για να εκτελεστεί. Να θυμόσαστε ότι η γραμμή που λέει στο GNOME ότι χρησιμοποιούμε Gjs χρειάζεται πάντοτε να πάει στην αρχή.

# Δημιουργία του παραθύρου εφαρμογής

const TreeViewExample = new Lang.Class({ Name: 'TreeView Example with Simple ListStore',

// Δημιουργία της εφαρμογής αυτής καθεαυτής _init: function() { this.application = new Gtk.Application({ application_id: 'org.example.jstreeviewsimpleliststore' });

// Σύνδεση των σημάτων 'activate' και 'startup' με τις συναρτήσεις επανάκλησης this.application.connect('activate', Lang.bind(this, this._onActivate)); this.application.connect('startup', Lang.bind(this, this._onStartup)); },

// Η συνάρτηση επανάκλησης για το σήμα 'activate' παρουσιάζει παράθυρο όταν είναι ενεργή _onActivate: function() { this._window.present(); },

// Η συνάρτηση επανάκλησης για το σήμα 'startup' δομεί τη διεπαφή χρήστη _onStartup: function() { this._buildUI (); },

Όλος ο κώδικας για αυτό το παράδειγμα πηγαίνει στην κλάση TreeViewExample. Ο παραπάνω κώδικας δημιουργεί μια Gtk.Application για να μπουν μέσα τα γραφικά στοιχεία μας και τα παράθυρα.

// Δόμηση της διεπαφής χρήστη της εφαρμογής _buildUI: function() {

// Δημιουργία του παραθύρου της εφαρμογής this._window = new Gtk.ApplicationWindow({ application: this.application, window_position: Gtk.WindowPosition.CENTER, default_height: 250, default_width: 100, border_width: 20, title: "My Phone Book"});

Η συνάρτηση _buildUI είναι εκεί που βάζουμε όλον τον κώδικα για να δημιουργήσουμε τη διεπαφή χρήστη της εφαρμογής. Το πρώτο βήμα δημιουργεί ένα νέο Gtk.ApplicationWindow για να βάλουμε μέσα τα γραφικά στοιχεία μας.

# Δημιουργία της αποθήκης λιστών (ListStore)

// Δημιουργία της υποκείμενης αποθήκης καταλόγου για τον τηλεφωνικό κατάλογο this._listStore = new Gtk.ListStore (); this._listStore.set_column_types ([ GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING]);

Δημιουργούμε πρώτα την αποθήκη καταλόγου (ListStore) όπως θα κάναμε με κάθε γραφικό στοιχείο. Έπειτα καλούμε τη μέθοδο της set_column_types και την περνάμε σε έναν πίνακα τύπου δεδομένων GObject. (Θα μπορούσαμε να βάλουμε όλους τους τύπους σε μια γραμμή, αλλά εδώ τα διαιρούμε για διευκόλυνση της ανάγνωσης.)

Οι τύποι δεδομένων GObject που μπορείτε να χρησιμοποιήσετε περιλαμβάνουν:

GObject.TYPE_BOOLEAN -- αληθές ή ψευδές

GObject.TYPE_FLOAT -- Ένας αριθμός κινητής υποδιαστολής (ένας με δεκαδική υποδιαστολή)

GObject.TYPE_STRING -- Μια συμβολοσειρά γραμμάτων και αριθμών

gtk.gdk.Pixbuf -- Μια εικόνα

Σε αυτήν την περίπτωση, κάνουμε μια ListStore των τεσσάρων στηλών, καθεμιά περιέχει τιμές συμβολοσειράς.

Χρειάζεται να βάλετε τη γραμμή const GObject = imports.gi.GObject; στην αρχή του κώδικα της εφαρμογή σας, όπως κάναμε σε αυτό το παράδειγμα, εάν θέλετε να μπορείτε να χρησιμοποιήσετε τύπους GObject.

// Δεδομένα για εισαγωγή στον τηλεφωνικό κατάλογο this.phonebook = let phonebook = [{ name: "Jurg", surname: "Billeter", phone: "555-0123", description: "A friendly person."}, { name: "Johannes", surname: "Schmid", phone: "555-1234", description: "Easy phone number to remember."}, { name: "Julita", surname: "Inca", phone: "555-2345", description: "Another friendly person."}, { name: "Javier", surname: "Jardon", phone: "555-3456", description: "Bring fish for his penguins."}, { name: "Jason", surname: "Clinton", phone: "555-4567", description: "His cake's not a lie."}, { name: "Random J.", surname: "Hacker", phone: "555-5678", description: "Very random!"}];

Εδώ έχουμε την πληροφορία μετάβασης στην αποθήκη καταλόγων (ListStore). Είναι ένας πίνακας αντικειμένων, που καθένα αντιστοιχεί σε μια μοναδική εγγραφή στον τηλεφωνικό κατάλογο.

Σημειώστε ότι η προβολή δένδρου (TreeView) στο στιγμιότυπο δεν εμφανίζει πράγματι τα δεδομένα από τις ιδιότητες "description". Στη θέση της, αυτή η πληροφορία εμφανίζεται στην ετικέτα από κάτω της, για κάθε γραμμή που πατάτε. Αυτό συμβαίνει επειδή η προβολή δένδρου και η αποθήκη καταλόγου (ListStore) είναι δύο ξεχωριστά πράγματα και μια προβολή δένδρου μπορεί να εμφανίσει όλο ή μέρος της αποθήκης καταλόγου και προβάλλει τι είναι σε αυτή με διαφορετικούς τρόπους. Μπορείτε ακόμα να έχετε πολλαπλά γραφικά στοιχεία που εμφανίζουν πράγματα από την ίδια την αποθήκη καταλόγου, όπως την ετικέτα στο παράδειγμά μας ή ακόμα μια δεύτερη προβολή δένδρου.

for (i = 0; i < phonebook.length; i++ ) { let contact = phonebook [i]; this._listStore.set (this._listStore.append(), [0, 1, 2, 3], [contact.name, contact.surname, contact.phone, contact.description]); }

Αυτός ο βρόχος for βάζει τις συμβολοσειρές από τον τηλεφωνικό κατάλογό μας στη ListStore μας σε σειρά. Για να περάσουμε την μέθοδο ορισμού της ListStore στην επανάληψη που δείχνει στη σωστή γραμμή, χρειάζεται ένας πίνακας που λέει ποιες στήλες θέλουμε να ορίσουμε και ένας πίνακας που περιέχει τα δεδομένα που θέλουμε να βάλουμε σε αυτές τις στήλες.

Μια μέθοδος append της ListStore προσθέτει μια οριζόντια γραμμή σε αυτή (ξεκινά χωρίς καμία) και επιστρέφει μια TreeIter που δείχνει σε αυτήν τη γραμμή όπως ένας δρομέας. Έτσι περνώντας το this._listStore.append() στη ListStore ως μια ιδιότητα, δημιουργούμε μια νέα γραμμή και λέμε στη μέθοδο set ποια γραμμή να ορίσει τα δεδομένα ταυτόχρονα.

# Δημιουργία της προβολής δένδρου (TreeView)

// Δημιουργία της προβολής δένδρου this._treeView = new Gtk.TreeView ({ expand: true, model: this._listStore });

Εδώ δημιουργούμε ένα βασικό γραφικό στοιχείο TreeView, που επεκτείνεται οριζόντια και κάθετα για να χρησιμοποιήσει όσο χώρο χρειάζεται. Το ορίζουμε να χρησιμοποιήσει τη ListStore που δημιουργήσαμε ως το "model" του, ή το πράγμα που θα μας δείξει το υλικό.

// Δημιουργία των στηλών για το βιβλίο διευθύνσεων let firstName = new Gtk.TreeViewColumn ({ title: "First Name" }); let lastName = new Gtk.TreeViewColumn ({ title: "Last Name" }); let phone = new Gtk.TreeViewColumn ({ title: "Phone Number" });

Τώρα δημιουργούμε καθεμιά από τις κάθετες TreeViewColumns που βλέπουμε στην TreeView. Ο τίτλος για καθεμιά πηγαίνει στην κορυφή, όπως μπορείτε να δείτε στο στιγμιότυπο.

// Δημιουργία μιας απεικόνισης κελιού για όταν χρειάζεται έντονο κείμενο let bold = new Gtk.CellRendererText ({ weight: Pango.Weight.BOLD });

// Δημιουργία μιας απεικόνισης κελιού για κανονικό κείμενο let normal = new Gtk.CellRendererText ();

// Συσκευασία των απεικονίσεων κελιού στις στήλες firstName.pack_start (bold, true); lastName.pack_start (normal, true); phone.pack_start (normal, true);

Εδώ δημιουργούμε τους απεικονιστές κελιών (CellRenderers) που θα χρησιμοποιήσουμε για την εμφάνιση του κειμένου από τη ListStore μας και τους πακετάρουμε στις TreeViewColumns. Κάθε CellRendererText χρησιμοποιείται για όλες τις καταχωρίσεις σε αυτήν τη στήλη. Το κανονικό μας CellRendererText απλά δημιουργεί απλό κείμενο, ενώ το έντονο κείμενο χρησιμοποιεί κείμενο βαρύτερου πάχους. Το βάζουμε στη στήλη πρώτου ονόματος και λέμε στα άλλα δύο να χρησιμοποιήσουμε αντίγραφα του κανονικού. Το "αληθές" χρησιμοποιείται ως η δεύτερη παράμετρος για τη μέθοδο pack_start που του λέει να επεκτείνει τα κελιά όταν είναι δυνατό, αντί να τα κρατήσει συμπαγή.

Εδώ είναι μια λίστα των άλλων ιδιοτήτων του κειμένου που μπορείτε να δείτε. Για να χρησιμοποιήσετε αυτές τις σταθερές Pango, βεβαιωθείτε ότι βάλατε τη γραμμή const Pango = imports.gi.Pango; στην αρχή του κώδικα σας όπως κάναμε.

firstName.add_attribute (bold, "text", 0); lastName.add_attribute (normal, "text", 1); phone.add_attribute (normal, "text", 2);

// Εισαγωγή των στηλών στην προβολή δένδρου this._treeView.insert_column (firstName, 0); this._treeView.insert_column (lastName, 1); this._treeView.insert_column (phone, 2);

Τώρα που έχουμε βάλει τους απεικονιστές κελιών (CellRenderers) στις στήλες προβολής δένδρου (TreeViewColumns), χρησιμοποιούμε τη μέθοδο add_attribute για να πει σε κάθε στήλη να σύρει το κείμενο από το πρότυπό μας προβολής δένδρου (TreeView) που ορίστηκε για χρήση· σε αυτήν την περίπτωση, την αποθήκη καταλόγου (ListStore) με τον τηλεφωνικό κατάλογο.

Η πρώτη παράμετρος είναι όποια απεικόνιση κελιών (CellRenderer) πρόκειται να χρησιμοποιήσουμε για απόδοση του τι σύρουμε.

Η δεύτερη παράμετρος είναι τι είδος πληροφορίας πρόκειται να σύρουμε. Σε αυτήν την περίπτωση, την αφήνουμε να μάθει ότι αποδίδουμε κείμενο.

Η τρίτη παράμετρος είναι σε ποια στήλη της ListStore σύρουμε αυτήν την πληροφορία.

Αφού το ρυθμίσουμε, χρησιμοποιούμε τη μέθοδο insert_column του TreeView για να βάλουμε τις TreeViewColumns μας μέσα του σε σειρά. Η TreeView μας είναι τώρα πλήρης.

Κανονικά, θα μπορούσατε να θελήσετε να χρησιμοποιήσετε έναν βρόχο για αρχικοποίηση την TreeView σας, αλλά σε αυτό το παράδειγμα εξηγούμε λεπτομερώς τα πράγματα βήμα-βήμα για διευκόλυνση της κατανόησης.

# Δημιουργία της υπόλοιπης διεπαφής χρήστη

// Δημιουργία της ετικέτας που εμφανίζει λεπτομέρειες για το όνομα που διαλέξατε this._label = new Gtk.Label ({ label: "" });

// Λήψη όποιου στοιχείου επιλέγεται this.selection = this._treeView.get_selection();

// Όταν επιλέγεται κάτι νέο, call _on_changed this.selection.connect ('changed', Lang.bind (this, this._onSelectionChanged));

Η μέθοδος get_selection της TreeView επιστρέφει ένα αντικείμενο που λέγεται TreeSelection. Μια TreeSelection είναι όπως μια TreeIter στο ότι είναι βασικά ένας δρομέας που δείχνει σε μια συγκεκριμένη γραμμή, εκτός από το ότι αυτό που δείχνει είναι αυτό που είναι ορατά επισημασμένο καθώς επιλέχτηκε.

Αφού πάρουμε την TreeSelection που πηγαίνει με την TreeView μας, της ζητάμε να μας πει όταν αλλάζει σε ποια γραμμή δείχνει. Το κάνουμε συνδέοντας τι σήμα της changed στη συνάρτηση _onSelectionChanged που γράψαμε. Αυτή η συνάρτηση αλλάζει το εμφανιζόμενο κείμενο με την ετικέτα που μόλις κάναμε.

// Δημιουργία πλέγματος για οργάνωση όλων μέσα του this._grid = new Gtk.Grid;

// Προσάρτηση της προβολής δένδρου και της ετικέτας στο πλέγμα this._grid.attach (this._treeView, 0, 0, 1, 1); this._grid.attach (this._label, 0, 1, 1, 1);

// Προσθήκη του πλέγματος στο παράθυρο this._window.add (this._grid);

// Εμφάνιση του παραθύρου και όλων των θυγατρικών γραφικών στοιχείων this._window.show_all(); },

Αφού το έχουμε βγάλει εκτός, δημιουργούμε ένα πλέγμα για να τα βάλουμε όλα μέσα, έπειτα το προσθέτουμε στο παράθυρό μας και λέμε στο παράθυρο να εμφανίσει τον εαυτόν του και τα περιεχόμενα του.

# Η συνάρτηση που χειρίζεται μια αλλαγμένη επιλογή

_onSelectionChanged: function () {

// Σύλληψη ενός treeiter που δείχνει στην τρέχουσα επιλογή let [ isSelected, model, iter ] = this.selection.get_selected();

// Ορισμός της ετικέτας για ανάγνωση των αποθηκευμένων τιμών στην τρέχουσα επιλογή this._label.set_label ("\n" + this._listStore.get_value (iter, 0) + " " + this._listStore.get_value (iter, 1) + " " + this._listStore.get_value (iter, 2) + "\n" + this._listStore.get_value (iter, 3));

}

});

Η γραμμή του κώδικα με την δήλωση let είναι λίγο μπερδεμένη, αλλά παρόλα αυτά είναι ο άριστος τρόπος να κάνετε την TreeIter να δείχνει στην ίδια γραμμή όπως η TreeSelection μας. Πρέπει να δημιουργήσουμε λίγες άλλες αναφορές αντικειμένου, αλλά η iter είναι το μόνο που χρειαζόμαστε.

Αφού το τελειώσουμε, καλούμε τη συνάρτηση της ετικέτας set_label και χρησιμοποιούμε τη συνάρτηση της ListStore get_value λίγες φορές για να συμπληρώσουμε τα δεδομένα που θέλουμε να τα εισάγουμε. Οι παράμετροι της είναι μια TreeIter που δείχνει στη γραμμή από όπου θέλουμε να πάρουμε δεδομένα και τη στήλη.

Εδώ, θέλουμε να πάρουμε δεδομένα και από τις τέσσερις στήλες, συμπεριλαμβάνοντας την "κρυφή" που δεν είναι μέρος της TreeView. Έτσι, μπορούμε να χρησιμοποιήσουμε την ετικέτα μας για να εμφανίσουμε συμβολοσειρές που είναι υπερβολικά μεγάλες για προσαρμογή στη TreeView και που δεν χρειαζόμαστε να δούμε με μια ματιά.

// Εκτέλεση της εφαρμογής let app = new TreeViewExample (); app.application.run (ARGV);

Τελικά, δημιουργούμε ένα νέο παράδειγμα της τελειωμένης κλάσης TreeViewExample και εκτελούμε την εφαρμογή.

# Δείγμα πλήρους κώδικα

#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';

const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; const Pango = imports.gi.Pango;

class TreeViewExample { // Create the application itself constructor() { this.application = new Gtk.Application({ application_id: 'org.example.jstreeviewsimpleliststore' });

// Connect 'activate' and 'startup' signals to the callback functions this.application.connect('activate', this._onActivate.bind(this)); this.application.connect('startup', this._onStartup.bind(this)); }

// Callback function for 'activate' signal presents window when active _onActivate() { this._window.present(); }

// Callback function for 'startup' signal builds the UI _onStartup() { this._buildUI(); }

// Build the application's UI _buildUI() { // Create the application window this._window = new Gtk.ApplicationWindow({ application: this.application, window_position: Gtk.WindowPosition.CENTER, default_height: 250, default_width: 100, border_width: 20, title: "My Phone Book"});

// Create the underlying liststore for the phonebook this._listStore = new Gtk.ListStore (); this._listStore.set_column_types ([ GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING]);

// Data to go in the phonebook let phonebook = [{ name: "Jurg", surname: "Billeter", phone: "555-0123", description: "A friendly person."}, { name: "Johannes", surname: "Schmid", phone: "555-1234", description: "Easy phone number to remember."}, { name: "Julita", surname: "Inca", phone: "555-2345", description: "Another friendly person."}, { name: "Javier", surname: "Jardon", phone: "555-3456", description: "Bring fish for his penguins."}, { name: "Jason", surname: "Clinton", phone: "555-4567", description: "His cake's not a lie."}, { name: "Random J.", surname: "Hacker", phone: "555-5678", description: "Very random!"}];

// Put the data in the phonebook for (let i = 0; i < phonebook.length; i++ ) { let contact = phonebook [i]; this._listStore.set (this._listStore.append(), [0, 1, 2, 3], [contact.name, contact.surname, contact.phone, contact.description]); }

// Create the treeview this._treeView = new Gtk.TreeView ({ expand: true, model: this._listStore });

// Create the columns for the address book let firstName = new Gtk.TreeViewColumn ({ title: "First Name" }); let lastName = new Gtk.TreeViewColumn ({ title: "Last Name" }); let phone = new Gtk.TreeViewColumn ({ title: "Phone Number" });

// Create a cell renderer for when bold text is needed let bold = new Gtk.CellRendererText ({ weight: Pango.Weight.BOLD });

// Create a cell renderer for normal text let normal = new Gtk.CellRendererText ();

// Pack the cell renderers into the columns firstName.pack_start (bold, true); lastName.pack_start (normal, true); phone.pack_start (normal, true);

// Set each column to pull text from the TreeView's model firstName.add_attribute (bold, "text", 0); lastName.add_attribute (normal, "text", 1); phone.add_attribute (normal, "text", 2);

// Insert the columns into the treeview this._treeView.insert_column (firstName, 0); this._treeView.insert_column (lastName, 1); this._treeView.insert_column (phone, 2);

// Create the label that shows details for the name you select this._label = new Gtk.Label ({ label: "" });

// Get which item is selected this.selection = this._treeView.get_selection();

// When something new is selected, call _on_changed this.selection.connect ('changed', this._onSelectionChanged.bind(this));

// Create a grid to organize everything in this._grid = new Gtk.Grid;

// Attach the treeview and label to the grid this._grid.attach (this._treeView, 0, 0, 1, 1); this._grid.attach (this._label, 0, 1, 1, 1);

// Add the grid to the window this._window.add (this._grid);

// Show the window and all child widgets this._window.show_all(); }

_onSelectionChanged() { // Grab a treeiter pointing to the current selection let [ isSelected, model, iter ] = this.selection.get_selected();

// Set the label to read off the values stored in the current selection this._label.set_label ("\n" + this._listStore.get_value (iter, 0) + " " + this._listStore.get_value (iter, 1) + " " + this._listStore.get_value (iter, 2) + "\n" + this._listStore.get_value (iter, 3) ); } };

// Run the application let app = new TreeViewExample (); app.application.run (ARGV);

# Τεκμηρίωση σε βάθος

Σε αυτό το παράδειγμα χρησιμοποιήσαμε τα παρακάτω:

Gtk.Application

Gtk.ApplicationWindow

Gtk.CellRendererText

Gtk.ListStore

Gtk.TreeIter

Gtk.TreeSelection

Gtk.TreeView

Gtk.TreeViewColumn