# ComboBox (JavaScript)

Taryn Fox
jewelfox@fursona.net 2012
A customizable drop-down menu
Luc Rebert,
traduc@rebert.name 2011
Alain Lojewski,
allomervan@gmail.com 2011-2012
Luc Pionchon
pionchon.luc@gmail.com 2011
Bruno Brouard
annoa.b@gmail.com 2011-12
Luis Menina
liberforce@freeside.fr 2014

# ComboBox

A ComboBox is an extremely customizable drop-down menu. It holds the equivalent of a TreeView widget that appears when you click on it, complete with a ListStore (basically a spreadsheet) that says what's in the rows and columns. In this example, our ListStore has the name of each option in one column, and the name of a stock icon in the other, which the ComboBox then turns into an icon for each option.

You select a whole horizontal row at a time, so the icons aren't treated as separate options. They and the text beside them make up each option you can click on.

Working with a ListStore can be time-consuming. If you just want a simple text-only drop-down menu, take a look at the ComboBoxText. It doesn't take as much time to set up, and is easier to work with.

# Bibliothèques à importer

#!/usr/bin/gjs

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

Ce sont les bibliothèques que nous devons importer pour faire fonctionner cette application. N'oubliez pas que la ligne qui informe GNOME que nous allons utiliser Gjs doit toujours se trouver au début.

# Création de la fenêtre de l'application

const ComboBoxExample = new Lang.Class ({ Name: 'ComboBox Example',

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

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

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

All the code for this sample goes in the ComboBoxExample class. The above code creates a Gtk.Application for our widgets and window to go in.

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

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

La fonction _buildUI est l'endroit où nous mettons tout le code nécessaire à la création de l'interface utilisateur de l'application. La première étape consiste à créer une Gtk.ApplicationWindow pour y mettre tous nos éléments graphiques.

# Création du 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]);

This ListStore works like the one used in the TreeView example. We're giving it two columns, both strings, because one of them will contain the names of stock Gtk icons.

If we'd wanted to use our own icons that weren't already built in to GNOME, we'd have needed to use the gtk.gdk.Pixbuf type instead. Here are a few other types you can use:

GObject.TYPE_BOOLEAN -- true ou false

GObject.TYPE_FLOAT -- un nombre à virgule flottante

GObject.TYPE_STRING -- une chaîne de caractères (lettres ou chiffres)

Pour pouvoir utiliser les types GObject, vous devez placer la ligne const GObject = imports.gi.GObject; au début du code de votre application, comme nous l'avons fait dans cet exemple.

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

Here we create an array of the text options and their corresponding icons, then put them into the ListStore in much the same way we would for a TreeView's ListStore. We only want to put an icon in if there's actually an icon in the options array, so we make sure to check for that first.

"Select" isn't really an option so much as an invitation to click on our ComboBox, so it doesn't need an icon.

# Création de la ComboBox

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

Each ComboBox has an underlying "model" it takes all its options from. You can use a TreeStore if you want to have a ComboBox with branching options. In this case, we're just using the ListStore we already created.

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

This part, again, works much like creating CellRenderers and packing them into the columns of a TreeView. The biggest difference is that we don't need to create the ComboBox's columns as separate objects. We just pack the CellRenderers into it in the order we want them to show up, then tell them to pull information from the ListStore (and what type of information we want them to expect).

We use a CellRendererText to show the text, and a CellRendererPixbuf to show the icons. We can store the names of the icons' stock types as strings, but when we display them we need a CellRenderer that's designed for pictures.

Just like with a TreeView, the "model" (in this case a ListStore) and the "view" (in this case our ComboBox) are separate. Because of that, we can do things like have the columns in one order in the ListStore, and then pack the CellRenderers that correspond to those columns into the ComboBox in a different order. We can even create a TreeView or other widget that shows the information in the ListStore in a different way, without it affecting our ComboBox.

// 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', Lang.bind (this, this._onComboChanged));

We want the "Select" text to be the part people see at first, that gets them to click on the ComboBox. So we set it to be the active entry. We also connect the ComboBox's changed signal to a callback function, so that any time someone clicks on a new option something happens. In this case, we're just going to show a popup with a little haiku.

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

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

Enfin, ajoutons la ComboBox à la fenêtre et indiquons à la fenêtre de s'afficher avec ses éléments graphiques à l'intérieur.

# Fonction prenant en charge votre sélection

_selected: function () {

// 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."];

Nous allons créer une MessageDialog qui affiche un message en fonction de la distribution sélectionnée. Créons d'abord le tableau des réponses à utiliser. Comme la première chaîne de notre ComboBox est justement le message « Select distribution », laissons celle-ci vide.

// 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', Lang.bind (this, this._onDialogResponse));

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

},

Avant d'afficher une MessageDialog, vérifions d'abord que vous n'avez pas choisi le message « Select distribution ». Ensuite, définissons son texte comme étant l'entrée dans le tableau qui correspond à l'entrée active de notre ComboBoxText. Cela se fait avec la méthode get_active, qui renvoie l'identifiant numérique de votre sélection.

Other methods you can use include get_active_id, which returns the text ID assigned by append, and get_active_text, which returns the full text of the string you selected.

Une fois la MessageDialog terminée, connectons son signal de retour à la fonction _onDialogResponse et indiquons lui de s'afficher toute seule.

_onDialogResponse: function () {

this._popUp.destroy ();

}

});

Comme le seul bouton de la MessageDialog est le bouton OK, il n'est pas nécessaire de vérifier son response_id pour savoir quel bouton a été cliqué. Tout ce que nous faisons ici est détruire le message surgissant.

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

Finally, we create a new instance of the finished ComboBoxExample class, and set the application running.

# Exemple complet de code

#!/usr/bin/gjs

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

const ComboBoxExample = new Lang.Class ({ Name: 'ComboBox Example',

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

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

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

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

// 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', Lang.bind (this, this._onComboChanged));

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

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

_onComboChanged: function () {

// 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', Lang.bind (this, this._onDialogResponse));

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

},

_onDialogResponse: function () {

this._popUp.destroy ();

}

});

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

# Documentation approfondie

Dans cet exemple, les éléments suivants sont utilisés :

Gtk.Application

Gtk.ApplicationWindow

Gtk.CellRendererPixbuf

Gtk.CellRendererText

Gtk.ComboBox

Gtk.ListStore

Gtk.MessageDialog

Gtk.TreeIter