Un «ComboBox» es un menú desplegable extremadamente personalizable. Contiene el equivalente a un widget TreeView que aparece cuando lo pulsa, completo con un «ListStore» (básicamente una hoja de cálculo) que dice qué está en las filas y columnas. En este ejemplo, el «ListStore» tiene el nombre de cada opción en una columna, y el nombre de un elemento del almacén en la otra, que el «ComboBox» convierte en un icono para cada opción.
Puede seleccionar una fila horizontal a la vez, por lo que los iconos no se tratan como opciones separadas. Ellos y su texto forman una opción que puede pulsar.
Trabajar con un «ListStore» puede llevar tiempo. Si sólo quiere un menú desplegable de solo texto simple, échele un vistazo al ComboBoxText. No toma tanto tiempo configurarlo, y es más fácil trabajar con él.
#!/usr/bin/gjs
imports.gi.versions.Gtk = '3.0';
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
Estas son las bibliotecas que necesita importar para que esta aplicación se ejecute. Recuerde que la línea que le dice a GNOME que está usando Gjs siempre tiene que ir al principio.
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 ();
}
Todo el código de este ejemplo va en la clase «ComboBoxExample». El código anterior crea una Gtk.Application para que vayan los widgets y la ventana.
// 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 });
La función _buildUI es donde se pone todo el código que crea la interfaz de usuario de la aplicación. El primer paso es crear una Gtk.ApplicationWindow nueva para poner dentro todos los widgets.
// Create the liststore to put our options in
this._listStore = new Gtk.ListStore();
this._listStore.set_column_types ([
GObject.TYPE_STRING,
GObject.TYPE_STRING]);
Este «ListStore» funciona como el que se usó en el ejemplo del TreeView. Se le dan dos columnas, ambas cadenas, porque una contendrá los nombres de los iconos del almacén de GTK+.
Si quisiera usar sus propios iconos que no están incluidos en GNOME, tendría que usar el tipo
Necesita poner la línea
// 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]);
}
Aquí se crea una matriz de las opciones de texto y sus iconos correspondientes, después se ponen en el «ListStore» de forma parecida a cOmo se haría para un «ListStore» de un TreeView. Sólo se quiere poner un icono si hay uno en la matriz de opciones, por lo que primero hay que asegurarse de verificar esto.
«Select» no es realmente una opción, sino una invitación a pulsar en el «ComboBox», por lo que no necesita un icono.
// Create the combobox
this._comboBox = new Gtk.ComboBox({
model: this._listStore});
Cada «ComboBox» tiene un «modelo» subyacente del que toma todas sus opciones. Puede usar un «TreeStore» si quiere tener un «ComboBox» con opciones de bifurcación. En este caso, solo se está usando el «ListStore» que ya se creó.
// 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);
Esta parte, nuevamente, funciona de forma similar a crear «CellRenderer» y empaquetarlos en columnas de un TreeView. La principal diferencia es que no necesita crear las columnas del «ComboBox» como objetos separados. Sólo se empaquetan los «CellRenderer» en el orden en el que quiere que se muestren, y se les dice que obtengan información del «ListStore» (y qué tipo de información tienen que esperar).
Se usa un «CellRendererText» para mostrar el texto, y un «CellRendererPixbuf» para mostrar los iconos. Se pueden almacenar los nombres de los tipos del almacén de iconos como cadenas, pero cuando se muestran se necesita un «CellRenderer» diseñado para imágenes.
Al igual que con un «TreeView», el «modelo» (en este caso un «ListStore») y la «vista» (en este caso el «ComboBox») están separados. Es por esto que se pueden hacer cosas como tener las columnas en un orden en el «ListStore», y después empaquetar los «CellRenderer» que les corresponden en el «ComboBox» en un orden diferente. Incluso se puede crear un «TreeView» u otro widget que muestre la información en el «ListStore» de una manera diferente, sin afectar el «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', this._onComboChanged.bind(this));
Se quiere que el texto «Select» sea la parte que la gente ve al principio, que les haga pulsar el «ComboBox»; por lo que se establece como entrada activa. También se conecta la señal
// Add the combobox to the window
this._window.add (this._comboBox);
// Show the window and all child widgets
this._window.show_all();
}
Finalmente, se añade el «ComboBox» a la ventana, y se le dice que se muestre con todo lo que contiene.
_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."];
Se va a crear un MessageDialog emergente, que muestra un «haiku» tonto de acuerdo a qué distribución seleccione. Primero, se crea la matriz de «haiku». Dado que la primera cadena en el «ComboBox» es sólo el mensaje «Select», la primera cadena en la matriz se hace vacía.
// 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();
}
}
Antes de mostrar un «MessageDialog», primero se verifica que no se eligió el mensaje «Select». Después de eso, se establece su texto al «haiku» en la matriz que le corresponde a la entrada activa en el «ComboBoxText». Esto se hace usando el método
Otros métodos que puede usar incluyen
Después de crear el «MessageDialog», se conecta su señal «response» a la función «onDialogResponse», y se le dice que se muestre.
_onDialogResponse() {
this._popUp.destroy ();
}
};
Dado que el único botón que tiene el «MessageDialog» es un botón aceptar, no se necesita verificar su «response_id» para ver qué botón se pulsó. Todo lo que se hace aquí es destruir la ventana emergente.
// Run the application
let app = new ComboBoxExample ();
app.application.run (ARGV);
Finalmente, se crea una instancia nueva de la clase «ComboBoxExample» terminada, y se ejecuta la aplicación.
#!/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);
En este ejemplo se usa lo siguiente:
Gtk.Application
Gtk.ApplicationWindow
Gtk.CellRendererPixbuf
Gtk.CellRendererText
Gtk.ComboBox
Gtk.ListStore
Gtk.MessageDialog
Gtk.TreeIter