<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:xi="http://www.w3.org/2001/XInclude" type="guide" style="task" id="treeview_simple_liststore.js" xml:lang="el">
  <info>
  <title type="text">Treeview με ListStore (JavaScript)</title>
    <link type="guide" xref="beginner.js#treeview"/>
    <link type="seealso" xref="GtkApplicationWindow.js"/>
    <link type="seealso" xref="grid.js"/>
    <link type="seealso" xref="label.js"/>
    <revision version="0.1" date="2012-07-04" status="draft"/>

    <credit type="author copyright">
      <name>Taryn Fox</name>
      <email>jewelfox@fursona.net</email>
      <years>2012</years>
    </credit>

    <desc>Ένα γραφικό συστατικό που εμφανίζει μια ξεχωριστή λίστα στοιχείων</desc>
  </info>

  <title>Treeview με ListStore</title>
  <media type="image" mime="image/png" src="media/treeview_simple_liststore_penguins.png"/>
  <p>Μια TreeView μοιάζει με ένα παράθυρο στα περιεχόμενα είτε μιας ListStore είτε μιας TreeStore. Μια ListStore μοιάζει με ένα υπολογιστικό φύλλο: μια "επίπεδη", διδιάστατη λίστα πραγμάτων διαιρεμένη σε γραμμές και στήλες. Μια TreeStore, στο μεταξύ, μπορεί να διακλαδωθεί σε διαφορετικές κατευθύνσεις όπως κάνει ένα δένδρο. Σε αυτό το παράδειγμα, δημιουργήσαμε μια TreeView που εμφανίζει τα περιεχόμενα μιας ListStore με (εικονικά) ονόματα και αριθμούς τηλεφώνου σε αυτό, και ρυθμίστηκε έτσι ώστε η <link xref="label.js">ετικέτα</link> στο τέλος του παραθύρου να εμφανίζει περισσότερες πληροφορίες σχετικά με οποιοδήποτε όνομα πατάτε.</p>
  <p>Η TreeView δεν είναι απλά ένα μονό γραφικό συστατικό, αλλά περιέχει έναν αριθμό μικρότερων γραφικών συστατικών:</p>
  <list>
    <item><p>Τα γραφικά συστατικά TreeViewColumn εμφανίζουν κάθε (κάθετη) στήλη πληροφορίας από τη ListStore. Καθένα έχει έναν τίτλο που μπορεί να προβληθεί στην κορυφή της στήλης, όπως στο στιγμιότυπο.</p></item>
    <item><p>Τα γραφικά συστατικά CellRenderer "πακετάρονται" σε κάθε TreeViewColumn και περιέχουν τις οδηγίες πώς να εμφανίσουν κάθε ξεχωριστό "κελί" ή στοιχείο από τη ListStore. Υπάρχουν πολλοί διαφορετικοί τύποι, συμπεριλαμβανόμενου του CellRendererText που χρησιμοποιείται εδώ και του CellRendererPixbuf, που εμφανίζει μια εικόνα "ενδιάμεση μνήμη εικονοστοιχείου").</p></item>
  </list>
  <p>Τελικά, πρόκειται να χρησιμοποιήσουμε ένα αντικείμενο που λέγεται TreeIter, που δεν είναι γραφικό συστατικό τόσο πολύ όσο ένας αόρατος δρομέας που δείχνει σε μια (οριζόντια) γραμμή στη ListStore. Οποτεδήποτε πατάτε σε ένα όνομα στον τηλεφωνικό κατάλογο, για παράδειγμα, δημιουργούμε ένα TreeIter που δείχνει τη γραμμή που επιλέχτηκε και έπειτα χρησιμοποιήστε το για να πείτε στη ListStore ποιας εγγραφής θέλουμε η ετικέτα να εμφανίσει περισσότερες πληροφορίες σχετικά.</p>
  <note><p>Η TreeView είναι προφανώς το πιο περίπλοκο γραφικό συστατικό Gtk, λόγω των πολλών μερών που έχει και του τρόπου συνεργασίας τους. Δώστε στον εαυτό σας τον χρόνο να μάθετε πώς δουλεύει και πειραματιστείτε μαζί του, ή δοκιμάστε πρώτα κάτι ευκολότερο εάν έχετε πρόβλημα.</p></note>
    <links type="section"/>

  <section id="imports">
    <title>Βιβλιοθήκες για εισαγωγή</title>
    <code mime="application/javascript"><![CDATA[
#!/usr/bin/gjs

const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
]]></code>
    <p>Αυτές είναι οι βιβλιοθήκες που χρειαζόμαστε να εισάγουμε αυτήν την εφαρμογή για να εκτελεστεί. Να θυμόσαστε ότι η γραμμή που λέει στο GNOME ότι χρησιμοποιούμε Gjs χρειάζεται πάντοτε να πάει στην αρχή.</p>
  </section>

  <section id="applicationwindow">
    <title>Δημιουργία του παραθύρου εφαρμογής</title>
    <code mime="application/javascript"><![CDATA[
const TreeViewExample = new Lang.Class({
    Name: 'TreeView Example with Simple ListStore',

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

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

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

    // Callback function for 'startup' signal builds the UI
    _onStartup: function() {
        this._buildUI ();
    },
]]></code>
    <p>Όλος ο κώδικας για αυτό το παράδειγμα πηγαίνει στην κλάση TreeViewExample. Ο παραπάνω κώδικας δημιουργεί μια <link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Gtk.Application</link> για να μπουν μέσα τα γραφικά συστατικά μας και τα παράθυρα.</p>
    <code mime="application/javascript"><![CDATA[
    // Build the application's UI
    _buildUI: function() {

        // 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"});
]]></code>
    <p>Η συνάρτηση _buildUI είναι εκεί που βάζουμε όλον τον κώδικα για να δημιουργήσουμε τη διεπαφή χρήστη της εφαρμογής. Το πρώτο βήμα δημιουργεί ένα νέο <link xref="GtkApplicationWindow.js">Gtk.ApplicationWindow</link> για να βάλουμε μέσα τα γραφικά συστατικά μας.</p>
  </section>

  <section id="liststore">
    <title>Δημιουργία της ListStore</title>
    <code mime="application/javascript"><![CDATA[
        // 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]);
]]></code>
    <p>Δημιουργούμε πρώτα τη ListStore όπως θα κάναμε με κάθε γραφικό συστατικό. Έπειτα καλούμε τη μέθοδο της set_column_types και την περνάμε σε έναν πίνακα τύπου δεδομένων GObject. (Θα μπορούσαμε να βάλουμε όλους τους τύπους σε μια γραμμή, αλλά εδώ τα διαιρούμε για διευκόλυνση της ανάγνωσης.)</p>
    <p>Οι τύποι δεδομένων GObject που μπορείτε να χρησιμοποιήσετε περιλαμβάνουν:</p>
    <list>
      <item><p><file>GObject.TYPE_BOOLEAN</file> -- αληθές ή ψευδές</p></item>
      <item><p><file>GObject.TYPE_FLOAT</file> -- Ένας αριθμός κινητής υποδιαστολής (ένας με δεκαδική υποδιαστολή)</p></item>
      <item><p><file>GObject.TYPE_STRING</file> -- Μια συμβολοσειρά γραμμάτων και αριθμών</p></item>
      <item><p><file>gtk.gdk.Pixbuf</file> -- Μια εικόνα</p></item>
    </list>
    <p>Σε αυτήν την περίπτωση, κάνουμε μια ListStore των τεσσάρων στηλών, καθεμιά περιέχει τιμές συμβολοσειράς.</p>
    <note><p>Χρειάζεται να βάλετε τη γραμμή <file>const GObject = imports.gi.GObject;</file> στην αρχή του κώδικα της εφαρμογή σας, όπως κάναμε σε αυτό το παράδειγμα, εάν θέλετε να μπορείτε να χρησιμοποιήσετε τύπους GObject.</p></note>

    <code mime="application/javascript"><![CDATA[
        // Data to go in the phonebook
        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!"}];
]]></code>
    <p>Εδώ έχουμε την πληροφορία μετάβασης στη ListStore. Είναι ένας πίνακας αντικειμένων, που καθένα αντιστοιχεί σε μια μοναδική εγγραφή στον τηλεφωνικό κατάλογο.</p>
    <p>Σημειώστε ότι η TreeView στο στιγμιότυπο δεν εμφανίζει πράγματι τα δεδομένα από τις ιδιότητες "description". Στη θέση της, αυτή η πληροφορία εμφανίζεται στην ετικέτα από κάτω της, για κάθε γραμμή που πατάτε. Αυτό συμβαίνει επειδή η TreeView και η ListStore είναι δύο ξεχωριστά πράγματα και μια TreeView μπορεί να εμφανίσει όλο ή μέρος της ListStore και προβάλλει τι είναι σε αυτή με διαφορετικούς τρόπους. Μπορείτε ακόμα να έχετε πολλαπλά γραφικά συστατικά που εμφανίζουν πράγματα από την ίδια ListStore, όπως την ετικέτα στο παράδειγμά μας ή ακόμα μια δεύτερη TreeView.</p>

    <code mime="application/javascript"><![CDATA[
        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]);
        }
]]></code>
    <p>Αυτός ο βρόχος <file>for</file> βάζει τις συμβολοσειρές από τον τηλεφωνικό κατάλογό μας στη ListStore μας σε σειρά. Για να περάσουμε την μέθοδο ορισμού της ListStore στην επανάληψη που δείχνει στη σωστή γραμμή, χρειάζεται ένας πίνακας που λέει ποιες στήλες θέλουμε να ορίσουμε και ένας πίνακας που περιέχει τα δεδομένα που θέλουμε να βάλουμε σε αυτές τις στήλες.</p>
    <p>Μια μέθοδος <file>append</file> της ListStore προσθέτει μια οριζόντια γραμμή σε αυτή (ξεκινά χωρίς καμία) και επιστρέφει μια TreeIter που δείχνει σε αυτήν τη γραμμή όπως ένας δρομέας. Έτσι περνώντας το <file>this._listStore.append()</file> στη ListStore ως μια ιδιότητα, δημιουργούμε μια νέα γραμμή και λέμε στη μέθοδο <file>set</file> ποια γραμμή να ορίσει τα δεδομένα ταυτόχρονα.</p>

  </section>

  <section id="treeview">
    <title>Δημιουργία της TreeView</title>
    <code mime="application/javascript"><![CDATA[
        // Create the treeview
        this._treeView = new Gtk.TreeView ({
            expand: true,
            model: this._listStore });
]]></code>
    <p>Εδώ δημιουργούμε ένα βασικό γραφικό συστατικό TreeView, που επεκτείνεται οριζόντια και κάθετα για να χρησιμοποιήσει όσο χώρο χρειάζεται. Το ορίζουμε να χρησιμοποιήσει τη ListStore που δημιουργήσαμε ως το "model" του, ή το πράγμα που θα μας δείξει το υλικό.</p>

    <code mime="application/javascript"><![CDATA[
        // 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" });
]]></code>
    <p>Τώρα δημιουργούμε καθεμιά από τις κάθετες TreeViewColumns που βλέπουμε στην TreeView. Ο τίτλος για καθεμιά πηγαίνει στην κορυφή, όπως μπορείτε να δείτε στο στιγμιότυπο.</p>

    <code mime="application/javascript"><![CDATA[
        // 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);
]]></code>
    <p>Εδώ δημιουργούμε τους CellRenderers που θα χρησιμοποιήσουμε για την εμφάνιση του κειμένου από τη ListStore μας και τους πακετάρουμε στις TreeViewColumns. Κάθε CellRendererText χρησιμοποιείται για όλες τις καταχωρίσεις σε αυτήν τη στήλη. Το κανονικό μας CellRendererText απλά δημιουργεί απλό κείμενο, ενώ το έντονο κείμενο χρησιμοποιεί κείμενο βαρύτερου πάχους. Το βάζουμε στη στήλη πρώτου ονόματος και λέμε στα άλλα δύο να χρησιμοποιήσουμε αντίγραφα του κανονικού. Το "αληθές" χρησιμοποιείται ως η δεύτερη παράμετρος για τη μέθοδο <file>pack_start</file> που του λέει να επεκτείνει τα κελιά όταν είναι δυνατό, αντί να τα κρατήσει συμπαγή.</p>
    <note><p><link href="http://www.pygtk.org/docs/pygtk/pango-constants.html">Εδώ είναι μια λίστα</link> των άλλων ιδιοτήτων του κειμένου που μπορείτε να δείτε. Για να χρησιμοποιήσετε αυτές τις σταθερές Pango, βεβαιωθείτε ότι βάλατε τη γραμμή <file>const Pango = imports.gi.Pango;</file> στην αρχή του κώδικα σας όπως κάναμε.</p></note>

    <code mime="application/javascript"><![CDATA[
        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);
]]></code>
    <p>Τώρα που έχουμε βάλει τους CellRenderers στις TreeViewColumns, χρησιμοποιούμε τη μέθοδο <file>add_attribute</file> για να πει σε κάθε στήλη να σύρει το κείμενο από το πρότυπό μας TreeView που ορίστηκε για χρήση· σε αυτήν την περίπτωση, τη ListStore με τον τηλεφωνικό κατάλογο.</p>
    <list>
      <item><p>Η πρώτη παράμετρος είναι όποια CellRenderer πρόκειται να χρησιμοποιήσουμε για απόδοση του τι σύρουμε.</p></item>
      <item><p>Η δεύτερη παράμετρος είναι τι είδος πληροφορίας πρόκειται να σύρουμε. Σε αυτήν την περίπτωση, την αφήνουμε να μάθει ότι αποδίδουμε κείμενο.</p></item>
      <item><p>Η τρίτη παράμετρος είναι σε ποια στήλη της ListStore σύρουμε αυτήν την πληροφορία.</p></item>
    </list>
    <p>Αφού το ρυθμίσουμε, χρησιμοποιούμε τη μέθοδο <file>insert_column</file> του TreeView για να βάλουμε τις TreeViewColumns μας μέσα του σε σειρά. Η TreeView μας είναι τώρα πλήρης.</p>
    <note><p>Κανονικά, θα μπορούσατε να θελήσετε να χρησιμοποιήσετε έναν βρόχο για αρχικοποίηση την TreeView σας, αλλά σε αυτό το παράδειγμα εξηγούμε λεπτομερώς τα πράγματα βήμα-βήμα για διευκόλυνση της κατανόησης.</p></note>
  </section>

  <section id="ui">
    <title>Δημιουργία της υπόλοιπης διεπαφής χρήστη</title>
    <code mime="application/javascript"><![CDATA[
        // 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', Lang.bind (this, this._onSelectionChanged));
]]></code>
    <p>Η μέθοδος <file>get_selection</file> της TreeView επιστρέφει ένα αντικείμενο που λέγεται TreeSelection. Μια TreeSelection είναι όπως μια TreeIter στο ότι είναι βασικά ένας δρομέας που δείχνει σε μια συγκεκριμένη γραμμή, εκτός από το ότι αυτό που δείχνει είναι αυτό που είναι ορατά επισημασμένο καθώς επιλέχτηκε.</p>
    <p>Αφού πάρουμε την TreeSelection που πηγαίνει με την TreeView μας, της ζητάμε να μας πει όταν αλλάζει σε ποια γραμμή δείχνει. Το κάνουμε συνδέοντας τι σήμα της <file>changed</file> στη συνάρτηση _onSelectionChanged που γράψαμε. Αυτή η συνάρτηση αλλάζει το εμφανιζόμενο κείμενο με την ετικέτα που μόλις κάναμε.</p>

    <code mime="application/javascript"><![CDATA[
        // 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();
    },
]]></code>
    <p>Αφού το έχουμε βγάλει εκτός, δημιουργούμε ένα <link xref="grid.js">πλέγμα</link> για να τα βάλουμε όλα μέσα, έπειτα το προσθέτουμε στο παράθυρό μας και λέμε στο παράθυρο να εμφανίσει τον εαυτόν του και τα περιεχόμενα του.</p>
  </section>

  <section id="function">
    <title>Η συνάρτηση που χειρίζεται μια αλλαγμένη επιλογή</title>

    <code mime="application/javascript"><![CDATA[
    _onSelectionChanged: function () {

        // 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));

    }

});
]]></code>
    <p>Η γραμμή του κώδικα με την δήλωση let είναι λίγο μπερδεμένη, αλλά παρόλα αυτά είναι ο άριστος τρόπος να κάνετε την TreeIter να δείχνει στην ίδια γραμμή όπως η TreeSelection μας. Πρέπει να δημιουργήσουμε λίγες άλλες αναφορές αντικειμένου, αλλά η <file>iter</file> είναι το μόνο που χρειαζόμαστε.</p>
    <p>Αφού το τελειώσουμε, καλούμε τη συνάρτηση της ετικέτας <file>set_label</file> και χρησιμοποιούμε τη συνάρτηση της ListStore <file>get_value</file> λίγες φορές για να συμπληρώσουμε τα δεδομένα που θέλουμε να τα εισάγουμε. Οι παράμετροι της είναι μια TreeIter που δείχνει στη γραμμή από όπου θέλουμε να πάρουμε δεδομένα και τη στήλη.</p>
    <p>Εδώ, θέλουμε να πάρουμε δεδομένα και από τις τέσσερις στήλες, συμπεριλαμβάνοντας την "κρυφή" που δεν είναι μέρος της TreeView. Έτσι, μπορούμε να χρησιμοποιήσουμε την ετικέτα μας για να εμφανίσουμε συμβολοσειρές που είναι υπερβολικά μεγάλες για προσαρμογή στη TreeView και που δεν χρειαζόμαστε να δούμε με μια ματιά.</p>

    <code mime="application/javascript"><![CDATA[
// Run the application
let app = new TreeViewExample ();
app.application.run (ARGV);
]]></code>
    <p>Τελικά, δημιουργούμε ένα νέο παράδειγμα της τελειωμένης κλάσης TreeViewExample και εκτελούμε την εφαρμογή.</p>
  </section>

  <section id="complete">
    <title>Δείγμα πλήρους κώδικα</title>
<code mime="application/javascript" style="numbered"><xi:include href="samples/treeview_simple_liststore.js" parse="text"><xi:fallback/></xi:include></code>
  </section>

  <section id="in-depth">
    <title>Τεκμηρίωση σε βάθος</title>
<p>Σε αυτό το παράδειγμα χρησιμοποιήσαμε τα παρακάτω:</p>
<list>
  <item><p><link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Εφαρμογή Gtk</link></p></item>
  <item><p><link href="http://developer.gnome.org/gtk3/stable/GtkApplicationWindow.html">Gtk.ApplicationWindow</link></p></item>
  <item><p><link href="www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.CellRendererText.html">Gtk.CellRendererText</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.ListStore.html">Gtk.ListStore</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.TreeIter.html">Gtk.TreeIter</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.TreeSelection.html">Gtk.TreeSelection</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.TreeView.html">Gtk.TreeView</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.TreeViewColumn.html">Gtk.TreeViewColumn</link></p></item>
</list>
  </section>
</page>
