Un «TextView» es realmente (o al menos generalmente) un conjunto anidado de tres objetos.
En la parte inferior hay un Búfer de texto. Este almacena el texto.
En el medio está el TextView, que es un widget que le permite ver y editar el texto en el búfer. Cambia su tamaño automáticamente dependiendo de cuánto texto hay.
Dado que el cambio de tamaño automático puede hacer un «TextView» difícil de manejar, normalmente se ubica dentro de una «ScrolledWindow». A pesar de su nombre, no es una ventana real en términos de tener una barra de título y un botón «X»; es un widget en el que pone la aplicación que está haciendo, que actúa como una ventana sobre un pedazo más manejable de un «TextView». Si el texto en el búfer es demasiado grande para entrar, aparecerán barras de desplazamiento.
Si quiere cambiar el texto que se muestra en el «TextView», actúe en el búfer de texto, dado que es lo que realmente contiene al texto. Es lo mismo si quiere ver lo que se ha introducido en él. Esta aplicación de ejemplo le permite hablar con un pingüino de fantasía, y verifica el búfer de texto para ver si ha introducido la palabra «fish» en él.
Las poblaciones de pingüinos reales están decayendo rápidamente, porque el cambio climático está derritiendo el hielo en el que viven y matando a los peces que comen. Si le interesa jugar a un juego de GNOME algo tonto basado en esta premisa, échele un vistazo a Pingus.
#!/usr/bin/gjs
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
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.
const TextViewExample = new Lang.Class ({
Name: 'TextView Example',
// Create the application itself
_init: function () {
this.application = new Gtk.Application ({
application_id: 'org.example.jstextview' });
// 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 ();
},
Todo el código de este ejemplo va en la clase «TextViewExample». El código anterior crea una Gtk.Application para poner los widgets y la ventana.
// 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: "Talk to a Penguin",
default_height: 400,
default_width: 440,
border_width: 20 });
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 a label for the penguin to talk to you
this._penguin = new Gtk.Label ({
height_request: 180,
width_request: 400,
label: "Squaaaak?",
wrap: true });
El primer paso en este ejemplo es crear la Label que el pingüino usará para hablarle. Se configura para que tenga ajuste de línea estableciendo su propiedad «wrap» a «true», pero usaremos un método distinto en el «TextView» propio que permite un control más preciso.
// Create a textview for you to talk to the penguin
this.buffer = new Gtk.TextBuffer();
this._textView = new Gtk.TextView ({
buffer: this.buffer,
editable: true,
wrap_mode: Gtk.WrapMode.WORD });
El primer paso es crear un «TextBuffer» para poner dentro las palabras. Después de eso se crea el «TextView», y se le dice que use el «TextBuffer» que se creó como su búfer. También se configura para que sea editable, dado que se quiere poder introducir cosas nuevas dentro.
La propiedad «wrap_mode» le permite elegir entre cuatro Modos de ajuste de línea diferentes. «Gtk.WrapMode.CHAR», por ejemplo, salta de línea en el medio de una palabra si sigue escribiendo cuando llega al borde. La mayoría de la gente está probablemente acostumbrada a «Gtk.WrapMode.WORD», que pondrá la palabra que está escribiendo en la línea siguiente automáticamente si es demasiado larga.
// Create a "scrolled window" to put your textview in so it will scroll
this._scrolled = new Gtk.ScrolledWindow ({
hscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
shadow_type: Gtk.ShadowType.ETCHED_IN,
height_request: 180,
width_request: 400, });
// Put the textview into the scrolled window
this._scrolled.add_with_viewport (this._textView);
Aquí se crea una «ScrolledWindow», y se configura para que se desplace automáticamente si se vuelve demasiado grande horizontal o verticalmente. También se le da un borde bonito ETCHED_IN. Después de eso, se pone el «TextView» dentro, y se hace que la «ScrolledWindow» dé un punto de vista sobre él.
// Create a grid to organize them in
this._grid = new Gtk.Grid ({
halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER });
// Put the label and textview in the grid one on top of the other
this._grid.attach (this._penguin, 0, 0, 1, 1);
this._grid.attach (this._scrolled, 0, 1, 1, 1);
La primera Rejilla que se crea sólo tiene dentro la etiqueta y la «ScrolledWindow».
// Create a button to send your message to the penguin
this._send = new Gtk.Button ({
halign: Gtk.Align.END,
margin_top: 20,
label: "Send" });
this._send.connect ('clicked', Lang.bind (this, this._chat));
// Create a grid that will have the other grid on top and the button on bottom
this._mainGrid = new Gtk.Grid ({
halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER });
// Add the other grid and the button to the main grid
this._mainGrid.attach (this._grid, 0, 0, 1, 1);
this._mainGrid.attach (this._send, 0, 1, 1, 1);
Se crea un Botón para enviar su mensaje al pingüino, y una rejilla nueva que tiene la otra en su parte superior y el botón en la parte inferior. El botón tiene un margen en su parte superior, para que no se aplaste contra la «ScrolledWindow».
// Attach the main grid to the window
this._window.add (this._mainGrid);
// Show the window and all child widgets
this._window.show_all();
},
Finalmente, se adjunta la rejilla principal a la ventana, después se le dice a la ventana y a todo lo que tiene dentro de ella que se vuelva visible cuando se ejecute la aplicación.
_chat: function () {
// Create a random number to determine what the penguin says
this.number = Math.floor ((Math.random() * 3) + 1);
// Did you actually say anything?
if (this.buffer.text) {
// Did you mention fish?
if (this.buffer.text.match (/fish/gi)) {
// Have the penguin squaak about fish
if (this.number == 1)
this._penguin.set_label ("FISH!");
else if (this.number == 2)
this._penguin.set_label ("Fish fish fish fish. Fish!");
else
this._penguin.set_label ("Fish? Fish fish fish. Fish fish. FISH!");
}
// I guess you didn't mention fish
else {
// Have the penguin talk about penguinny stuff
if (this.number == 1)
this._penguin.set_label ("SQUAAK!");
else if (this.number == 2)
this._penguin.set_label ("Ork ork ork ork squaak. Squaak squaak! *waves flippers*");
else
this._penguin.set_label ("Ork ork ork ork ork?");
}
}
// Clear the buffer
this.buffer.text = "";
// Give focus back to the textview so you don't have to click it again
this._textView.has_focus = true;
}
});
Aquí se usan algunas funciones básicas de JavaScript para que el pingüino diga algo aleatorio. Sin embargo, a los pingüinos les gusta el pescado, por lo que se quiere que si se menciona «fish», el pingüino responda. Para hacer eso, se usa el método «match» del objeto de cadena de JavaScript sobre
Dado que se quiere limpiar el búfer de texto después de cada vez que pulsa «Send», se configura
// Run the application
let app = new TextViewExample ();
app.application.run (ARGV);
Finalmente, se crea una instancia nueva de la clase «TextViewExample» terminada, y se ejecuta la aplicación.
#!/usr/bin/gjs
imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;
class TextViewExample {
// Create the application itself
constructor() {
this.application = new Gtk.Application({
application_id: 'org.example.jstextview'
});
// 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: "Talk to a Penguin",
default_height: 400,
default_width: 440,
border_width: 20 });
// Create a label for the penguin to talk to you
this._penguin = new Gtk.Label ({
height_request: 180,
width_request: 400,
label: "Squaaaak?",
wrap: true });
// Create a textview for you to talk to the penguin
this.buffer = new Gtk.TextBuffer();
this._textView = new Gtk.TextView ({
buffer: this.buffer,
editable: true,
wrap_mode: Gtk.WrapMode.WORD });
// Create a "scrolled window" to put your textview in so it will scroll
this._scrolled = new Gtk.ScrolledWindow ({
hscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
shadow_type: Gtk.ShadowType.ETCHED_IN,
height_request: 180,
width_request: 400, });
// Put the textview into the scrolled window
this._scrolled.add_with_viewport (this._textView);
// Create a grid to organize them in
this._grid = new Gtk.Grid ({
halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER });
// Put the label and textview in the grid one on top of the other
this._grid.attach (this._penguin, 0, 0, 1, 1);
this._grid.attach (this._scrolled, 0, 1, 1, 1);
// Create a button to send your message to the penguin
this._send = new Gtk.Button ({
halign: Gtk.Align.END,
margin_top: 20,
label: "Send" });
this._send.connect ('clicked', this._chat.bind(this));
// Create a grid that will have the other grid on top and the button on bottom
this._mainGrid = new Gtk.Grid ({
halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER });
// Add the other grid and the button to the main grid
this._mainGrid.attach (this._grid, 0, 0, 1, 1);
this._mainGrid.attach (this._send, 0, 1, 1, 1);
// Attach the main grid to the window
this._window.add (this._mainGrid);
// Show the window and all child widgets
this._window.show_all();
}
_chat() {
// Create a random number to determine what the penguin says
this.number = Math.floor ((Math.random() * 3) + 1);
// Did you actually say anything?
if (this.buffer.text) {
// Did you mention fish?
if (this.buffer.text.match (/fish/gi)) {
// Have the penguin squaak about fish
if (this.number == 1)
this._penguin.set_label ("FISH!");
else if (this.number == 2)
this._penguin.set_label ("Fish fish fish fish. Fish!");
else
this._penguin.set_label ("Fish? Fish fish fish. Fish fish. FISH!");
}
// I guess you didn't mention fish
else {
// Have the penguin talk about penguinny stuff
if (this.number == 1)
this._penguin.set_label ("SQUAAK!");
else if (this.number == 2)
this._penguin.set_label ("Ork ork ork ork squaak. Squaak squaak! *waves flippers*");
else
this._penguin.set_label ("Ork ork ork ork ork?");
}
}
// Clear the buffer
this.buffer.text = "";
// Give focus back to the textview so you don't have to click it again
this._textView.has_focus = true;
}
};
// Run the application
let app = new TextViewExample ();
app.application.run (ARGV);
Gtk.Application
Gtk.ApplicationWindow
Gtk.Button
Gtk.Grid
Gtk.Label
Gtk.RadioButton
Gtk.ScrolledWindow
Gtk.TextBuffer
Gtk.TextView