# ComboBox (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

# ComboBox

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

Επιλέγετε μια πλήρως οριζόντια γραμμή τη φορά, έτσι τα εικονίδια δεν συμπεριφέρονται ως ξεχωριστές επιλογές. Αυτές και το κείμενο δίπλα τους κατασκευάζουν κάθε επιλογή που μπορείτε να πατήσετε.

Η εργασία με μια αποθήκη λιστών μπορεί να είναι χρονοβόρα. Εάν θέλετε μόνο ένα απλό πτυσσόμενο μενού μόνο για κείμενο, ρίξτε μια ματιά στο ComboBoxText. Δεν παίρνει πολύ χρόνο για εγκατάσταση και δουλεύετε πιο εύκολα.

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

#!/usr/bin/gjs

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

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

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

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

class ComboBoxExample {

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

// 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 windows when active _onActivate() { this._window.present (); }

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

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

// Build the application's UI _buildUI() {

// Create the application window this._window = new Gtk.ApplicationWindow ({ application: this.application, window_position: Gtk.WindowPosition.CENTER, title: "Welcome to GNOME", default_width: 200, border_width: 10 });

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

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

// Create the liststore to put our options in this._listStore = new Gtk.ListStore(); this._listStore.set_column_types ([ GObject.TYPE_STRING, GObject.TYPE_STRING]);

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

Εάν θα θέλαμε να χρησιμοποιήσουμε τα δικά μας εικονίδια που δεν ήταν ήδη ενσωματωμένα στο GNOME, θα χρειαζόμασταν να χρησιμοποιήσουμε τον τύπο gtk.gdk.Pixbuf. Να μερικοί άλλοι τύποι που μπορείτε να χρησιμοποιήσετε:

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

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

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

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

// This array holds our list of options and their icons let options = [{ name: "Select" }, { name: "New", icon: Gtk.STOCK_NEW }, { name: "Open", icon: Gtk.STOCK_OPEN }, { name: "Save", icon: Gtk.STOCK_SAVE }];

// Put the options in the liststore for (let i = 0; i < options.length; i++ ) { let option = options[i]; let iter = this._listStore.append(); this._listStore.set (iter, [0], [option.name]); if ('icon' in option) this._listStore.set (iter, [1], [option.icon]); }

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

Η "Select" δεν είναι πραγματικά μια επιλογή όσο μια πρόσκληση να πατήσουμε στο ComboBox μας, έτσι δεν χρειάζεται ένα εικονίδιο.

# Δημιουργία των ComboBox

// Create the combobox this._comboBox = new Gtk.ComboBox({ model: this._listStore});

Κάθε σύνθετο πλαίσιο έχει ένα υποκείμενο "model" από όπου παίρνει όλες τις επιλογές του. Μπορείτε να χρησιμοποιήσετε μια αποθήκη δένδρου εάν θέλετε να έχετε ένα σύνθετο πλαίσιο με επιλογές διακλάδωσης. Σε αυτήν την περίπτωση, χρησιμοποιούμε απλά τη αποθήκη λιστών που ήδη δημιουργήσαμε.

// Create some cellrenderers for the items in each column let rendererPixbuf = new Gtk.CellRendererPixbuf(); let rendererText = new Gtk.CellRendererText();

// Pack the renderers into the combobox in the order we want to see this._comboBox.pack_start (rendererPixbuf, false); this._comboBox.pack_start (rendererText, false);

// Set the renderers to use the information from our liststore this._comboBox.add_attribute (rendererText, "text", 0); this._comboBox.add_attribute (rendererPixbuf, "stock_id", 1);

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

Χρησιμοποιούμε ένα κείμενο απεικονιστή κελιού (CellRendererText) για να εμφανίσουμε το κείμενο και έναν απεικονιστή κελιού Pixbuf (CellRendererPixbuf) για να προβάλουμε τα εικονίδια. Μπορούμε να αποθηκεύσουμε τα ονόματα τύπων παρακαταθήκης των εικονιδίων ως συμβολοσειρές, αλλά όταν τα εμφανίζουμε χρειαζόμαστε έναν απεικονιστή κελιού (CellRenderer) που σχεδιάστηκε για εικόνες.

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

// Set the first row in the combobox to be active on startup this._comboBox.set_active (0);

// Connect the combobox's 'changed' signal to our callback function this._comboBox.connect ('changed', this._onComboChanged.bind(this));

Θέλουμε το κείμενο "Select" να είναι το τμήμα που βλέπεται πρώτα, αυτό που τα δέχεται στο πάτημα του ComboBox. Έτσι το ορίζουμε να είναι η ενεργή καταχώριση. Επίσης συνδέουμε το σήμα changed του ComboBox σε μια συνάρτηση επανάκλησης, έτσι ώστε οποτεδήποτε κάποιος πατά σε μια νέα επιλογή κάτι να συμβαίνει. Σε αυτήν την περίπτωση, πρόκειται απλά να εμφανίσουμε ένα αναδυόμενο με ένα μικρό ποίημα.

// Add the combobox to the window this._window.add (this._comboBox);

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

Τελικά, προσθέτουμε το ComboBox στο παράθυρο, έπειτα λέμε στο παράθυρο να εμφανίσει τον εαυτόν του και όλα μέσα του.

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

_selected() {

// The silly pseudohaiku that we'll use for our messagedialog let haiku = ["", "You ask for the new\nwith no thought for the aged\nlike fallen leaves trod.", "Like a simple clam\nrevealing a lustrous pearl\nit opens for you.", "A moment in time\na memory on the breeze\nthese things can't be saved."];

Πρόκειται να δημιουργήσουμε ένα αναδυόμενο MessageDialog, που σας εμφανίζει ένα χαζό ποίημα με βάση ποια διανομή επιλέγετε. Πρώτα, δημιουργούμε τον πίνακα του ποιήματος για χρήση. Αφού η πρώτη συμβολοσειρά στο ComboBox μας είναι μόνο το μήνυμα "Select", κάνουμε την πρώτη συμβολοσειρά στον πίνακά μας κενή.

// Which combobox item is active? let activeItem = this._comboBox.get_active();

// No messagedialog if you choose "Select" if (activeItem != 0) { this._popUp = new Gtk.MessageDialog ({ transient_for: this._window, modal: true, buttons: Gtk.ButtonsType.OK, message_type: Gtk.MessageType.INFO, text: haiku[activeItem]});

// Connect the OK button to a handler function this._popUp.connect ('response', this._onDialogResponse.bind(this));

// Show the messagedialog this._popUp.show(); }

}

Πριν την προβολή ενός MessageDialog, δοκιμάζουμε πρώτα για να βεβαιωθούμε ότι δεν επιλέξατε το μήνυμα "Select". Μετά από αυτό, ορίζουμε το κείμενο του να είναι στο ποίημα στον πίνακα που αντιστοιχεί στην ενεργή καταχώριση στο ComboBoxText μας. Το κάνουμε χρησιμοποιώντας τη μέθοδο get_active, που επιστρέφει τον αριθμό ταυτότητας της επιλογής σας.

Άλλες μέθοδοι που μπορείτε να χρησιμοποιήσετε περιλαμβάνουν get_active_id, που επιστρέφει το αναγνωριστικό κειμένου που αποδόθηκε από append και get_active_text, που επιστρέφει το πλήρες κείμενο της επιλεγμένης συμβολοσειράς.

Μετά τη δημιουργία του MessageDialog, συνδέουμε το σήμα της απάντησής του στη συνάρτηση _onDialogResponse, έπειτα του λέμε να εμφανίσει τον εαυτόν του.

_onDialogResponse() {

this._popUp.destroy ();

}

};

Αφού το μόνο κουμπί που ο MessageDialog έχει είναι ένα κουμπί εντάξει, δεν χρειαζόμαστε να ελέγξουμε το response_id του για να δούμε ποιο κουμπί πατήθηκε. Αυτό που κάνουμε εδώ είναι η καταστροφή του αναδυόμενου.

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

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

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

#!/usr/bin/gjs

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

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

class ComboBoxExample {

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

// 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 windows 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, title: "Welcome to GNOME", default_width: 200, border_width: 10 });

// Create the liststore to put our options in this._listStore = new Gtk.ListStore(); this._listStore.set_column_types ([ GObject.TYPE_STRING, GObject.TYPE_STRING]);

// This array holds our list of options and their icons let options = [{ name: "Select" }, { name: "New", icon: Gtk.STOCK_NEW }, { name: "Open", icon: Gtk.STOCK_OPEN }, { name: "Save", icon: Gtk.STOCK_SAVE }];

// Put the options in the liststore for (let i = 0; i < options.length; i++ ) { let option = options[i]; let iter = this._listStore.append(); this._listStore.set (iter, [0], [option.name]); if ('icon' in option) this._listStore.set (iter, [1], [option.icon]); }

// Create the combobox this._comboBox = new Gtk.ComboBox({ model: this._listStore});

// Create some cellrenderers for the items in each column let rendererPixbuf = new Gtk.CellRendererPixbuf(); let rendererText = new Gtk.CellRendererText();

// Pack the renderers into the combobox in the order we want to see this._comboBox.pack_start (rendererPixbuf, false); this._comboBox.pack_start (rendererText, false);

// Set the renderers to use the information from our liststore this._comboBox.add_attribute (rendererText, "text", 0); this._comboBox.add_attribute (rendererPixbuf, "stock_id", 1);

// Set the first row in the combobox to be active on startup this._comboBox.set_active (0);

// Connect the combobox's 'changed' signal to our callback function this._comboBox.connect ('changed', this._onComboChanged.bind(this));

// Add the combobox to the window this._window.add (this._comboBox);

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

_onComboChanged() {

// The silly pseudohaiku that we'll use for our messagedialog let haiku = ["", "You ask for the new\nwith no thought for the aged\nlike fallen leaves trod.", "Like a simple clam\nrevealing a lustrous pearl\nit opens for you.", "A moment in time\na memory on the breeze\nthese things can't be saved."];

// Which combobox item is active? let activeItem = this._comboBox.get_active();

// No messagedialog if you choose "Select" if (activeItem != 0) { this._popUp = new Gtk.MessageDialog ({ transient_for: this._window, modal: true, buttons: Gtk.ButtonsType.OK, message_type: Gtk.MessageType.INFO, text: haiku[activeItem]});

// Connect the OK button to a handler function this._popUp.connect ('response', this._onDialogResponse.bind(this));

// Show the messagedialog this._popUp.show(); }

}

_onDialogResponse() {

this._popUp.destroy ();

}

};

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

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

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

Gtk.Application

Gtk.ApplicationWindow

Gtk.CellRendererPixbuf

Gtk.CellRendererText

Gtk.ComboBox

Gtk.ListStore

Gtk.MessageDialog

Gtk.TreeIter