Editar texto con GTK y JavaScript

Este es uno de los capítulos del tutorial Aplicaciones nativas en JavaScript con GJS. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.

En el capítulo anterior del tutorial, ya viste como el usuario podía interactuar con tu aplicación. Eso si, las posibilidades de interacción eran básicas. Por el momento, tan solo podía pulsar botones. Eso si, botones que le permitían hasta elegir una tipografía concreta o un color. Sin embargo, esto no es suficiente. En ocasiones, necesitas que el usuario introduzca algo tan sencillo como su nombre. Para estos casos, para editar texto con Gtk, tienes a tu disposición dos clases muy interesantes como son Gtk.Entry y Gtk.TextView. Así, en este capítulo del tutorial te mostraré las opciones que puedes dar al usuario para editar texto.

Con estas dos clases, ya puedes crear formularios en cuadros de diálogo para que el usuario introduzca todo tipo de información y que pueda editar texto con GTK. Por supuesto, que no solo tienes estas dos, también tienes otras clases, combinación de algunas de las que has visto hasta el momento que te permiten introducir números mediante botones, como es Gtk.SpinButton.

Editar texto con GTK y JavaScript

Editar texto con GTK y JavaScript

Para poder ver la funcionalidad de cada una de las clases indicadas anteriormente, que te van a pertmitir editar texto con GTK, utilizaremos un sencillo ejemplo que, como siempre, puedes encontrar en el repositorio que existe para este tutorial.

En este caso, se trata de un cuadro de diálogo, con un par de botones de Aceptar y Cancelar, una etiqueta, donde se muestra lo que queremos que el usuario responda y la caja de texto, Gtk.Entry para que el usuario introduzca el valor.

En el caso de que el usuario pulse el botón aceptar, el valor que haya introducido en la caja de texto se imprimirá directamente en el log.

#!/usr/bin/env gjs

imports.gi.versions.Gtk = '3.0'
const {Gtk, GObject} = imports.gi;

Gtk.init(null);

var Dialog = GObject.registerClass(
    class Dialog extends Gtk.Dialog{
        _init(){
            super._init({
                defaultWidth:200,
                defaultHeight: 200
            });
            let layout = new Gtk.Grid({
                margin: 10,
                rowSpacing: 5,
                columnSpacing: 5
            });
            this.add_button("Aceptar", Gtk.ResponseType.OK);
            this.add_button("Cancelar", Gtk.ResponseType.CANCEL);
            this.get_content_area().add(layout);
            layout.attach(new Gtk.Label({
                label: "Nombre:"
            }), 0, 0, 1, 1);
            this.entry = new Gtk.Entry();
            layout.attach(this.entry, 1, 0, 1, 1);

            this.show_all();
        }
    }
);

let dialog = new Dialog();
if (dialog.run() == Gtk.ResponseType.OK){
    log(dialog.entry.get_text());
}

La parte importante, la que te interesa, y sobre la que hay que trabajar es simplemente la que aparece this.entry = new Gtk.Entry(). Y, por supuesto, la parte donde se devuelve el contenido de la caja de texto, que al final es lo que realmente te interesa.

Gtk.Entry

En este apartado puedes encontrar, como de costumbre, algunas de las propiedades de esta clase. Básicamente, las que he considerado mas interesantes o relevantes. Por supuesto, también encontrarás de la misma forma alguno de los métodos exclusivos de la clase, como de las señales.

Propiedades

Lo primero es modificar el ejemplo anterior, en la parte en la que defines la caja de texto, reemplazando this.entry = new Gtk.Entry(), por el siguiente código, que mas adelante paso a desgranar,

this.entry = new Gtk.Entry({
    text: "Lorenzo",
    editable: true,
    maxLength: 5,
    visibility: true,
    invisibleChar: "|",
    widthChars: 55,
    placeholderText: "Introduce tu nombre",
    xalign: 0.5,
    primaryIconTooltipText: "Borrar el contenido",
    primaryIconStock: Gtk.STOCK_DELETE,
    secondaryIconTooltipText: "Ayuda contextual",
    secondaryIconStock: Gtk.STOCK_CLEAR
});
  • text este propiedad se corresponde con el texto que se mostrará en el propio objeto.
  • editable en el caso de ser false el valor correspondiente a la propiedad text no puede ser modificada por el usuario. Solo es posible editarla vía código.
  • maxLength es el número máximo de caracteres que admite la propiedad text.
  • visibility esta propiedad es la que controla si el usuario ve exactamente lo que está escribiendo, o se muestra un carácter. Esta es la opción que tienes que utilizar para el caso de que quieras que el usuario introduzca una contraseña. Es posible cambiar el carácter que se muestra utilizando la propiedad invisibleChar.
  • widthChars te permite configurar el ancho del objeto Gtk.Entry en número de caracteres.
  • placeholderText es el texto de ayuda que se muestra en la caja de texto, cuando no has introducido ningún valor, o no hay ningún valor por defecto. Normalmente se suele utilizar o bien un valor de ejemplo, o bien, se utiliza una ayuda. Si, por ejemplo, estás preguntando el nombre del usuario, el placeholderText podría ser introduce aquí tu nombre.
  • xalign te ayuda a controlar la posición del texto dentro del Gkt.Entry, es decir, sería la alineación del texto. Se trata de un número real, con valor de 0.0 a 1.0. El valor 0.0 se corresponde a que el texto se sitúa a la izquierda, mientras que un valor de 1.0 situaría el texto completamente a la derecha. Si lo que quieres es que el texto aparezca centrado, tienes que utilizar 0.5, como seguramente ya te habrás imaginado.
  • primaryIconStock, esta propiedad controla el icono que aparece en la parte izquierda de la caja de texto. Normalmente este icono se utiliza para desencadenar determinadas acciones.
  • primaryIconTooltipText este es un texto de ayuda que se muestra cuando sitúas el ratón sobre el primaryIcon.
  • secondaryIconStock es exactamente igual que el primaryIconStock, pero es el que gestiona el icono que se sitúa en la parte derecha de la caja de texto.
  • secondaryIconTooltipText esta propiedad se encarga de mostrar la ayuda cuando sitúas el ratón sobre el secondaryIcon.

Métodos

Por supuesto los dos métodos por excelencia para un objeto de esta clase Gtk.Entry, son sin lugar a dudas, get_text y set_text, que te permiten obtener y establecer el texto del Gtk.Entry.

Señales

Dentro de las señales que te pueden resultar interesantes, para modificar el comportamiento de un objeto de la clase Gtk.Entry, tienes

  • activate se produce cuando el usuario pulsa la tecla Enter
  • backspace exactamente igual que la anterior pero para el caso para la tecla borrar
  • copy-clipboard, cut-clipboard y paste-clipboard controlan la interacción con el portapapeles, cuando se copia, se corta o se pega del portapapeles respectivamente.

Gtk.TextView

Esta clase te va a permitir crear objetos para introducir texto, pero donde vas a tener mucho mas control sobre que es lo que se introduce y como se introduce. En este caso, he modificado el ejemplo anterior, como te muestro a continuación,

this.entry = new Gtk.TextView({
    buffer: new Gtk.TextBuffer({
        text: "Este es un texto mas largo"
    }),
    editable: true,
    justification: Gtk.Justification.CENTER,
    leftMargin: 10,
    rightMargin: 10,
    pixelsAboveLines: 10,
    pixelsBelowLines: 10
});

Propiedades

Sin lugar a dudas, la propiedad mas importante de todas las anteriores es buffer que es la que gestiona y control el texto dentro de un Gtk.TextView. El resto de propiedades, algunas de las que he puesto en el ejemplo anterior, son de menor importancia, y tienen mas que ver como se muestra el texto dentro de un Gtk.TextView. Así tienes,

  • editable para definir si el contenido es modificable o no.
  • justification te permite establecer donde se alinea el texto, a la derecha, a la izquierda o centrado
  • leftMargin y rightMargin te ayuda a establecer el espacio en pixel que dejas a izquierda y derecha respectivamente.
  • pixelsAboveLines y pixelsBelowLines definen los pixel que dejas por la parte superior y por la parte inferior de un párrafo.

Métodos

De nuevo de entre los métodos que tiene la clase Gtk.TextView los que destaca son los referentes a conseguir el buffer, que son básicamente get_buffer y set_buffer. Pero también tiene otros interesantes, como

  • scroll_to_iter que permite desplazar el scroll hasta una posición definida por un Gtk.TextIter
  • scroll_to_mark igual que el caso anterior pero para un Gtk.TextMark
  • get_iter_location devuelve un rectángulo que delimita el carácter que se encuentra en la posición Gtk.TextIter.
  • get_iter_at_location devuelve el Gtk.TextIter que se encuentra en unas coordenads determinadas dentro del texto.

Señales

Un objeto de la clase Gtk.TextView tiene algunas señales similares a las de Gtk.TextEntry, como pueden ser las relativas al portapapeles, y otras específicas como move-cursor, mov-focus, move-viewport.

Gtk.TextBuffer

Esta clase es la encargada de guardar y gestionar el texto que se muestra en un Gtk.TextView.

Propiedades

De entre las propiedades de esta clase, cabe destacar dos principalmente,

  • text, básicamente el contenido de un Gtk.TextBuffer.
  • cursorPosition que indica la posición del cursor y es de solo lectura.

Métodos

La clase Gtk.TextBuffer tiene una gran cantidad de métodos que te permiten gestionar perfectamente el texto que contiene. Sin embargo, hay algunos de ellos, que son imprescindibles hasta para lo más básico, como es el simple hecho de obtener el texto que contiene el objeto.

Además de la clase Gtk.TextBuffer, tienes que tener presente una clase mas como es Gtk.TextIter. Esta clase apunta una ubicación dentro de la clase Gtk.TextBuffer. Por ejemplo, si quieres obtener el inicio del Gtk.TextBuffer tienes que utilizar el método get_start_iter, mientras que si quieres obtener el final, tendrías que utilizar el método get_end_iter. De esta forma para obtener el texto contenido en un Gtk.TextBuffer, tienes que utilizar algo como lo que te muestro a continuación,

let buffer = dialog.entry.get_buffer();
let inicio = buffer.get_start_iter();
let fin = buffer.get_end_iter();
print(buffer.get_text(inicio, fin, false));

Esto que parece algo engorroso, lo cierto es que te da muchas opciones y posibilidades, dado que Gtk.TextBuffer pone a tu alcance diferentes herramientas y clases como son las marcas Gtk.TextMark que se conservan a pesar de las modificaciones que se produzcan. También tienes las etiquetas Gtk.TextTag, que te permiten aplicar atributos al texto.

Así algunas de las herramientas que puedes utilizar con Gtk.TextBuffer, además de la que te he comentado para extraer el texto son,

  • delete te permite borrar texto entre dos Gtk.TextIter
  • insert para insertar texto en un Gtk.TextIter
  • insert_at_cursor igual que el anterior, pero en este caso insertará el texto en la posición del cursor.

Además puedes realizar diferentes operaciones relacionadas con el portapapeles, como

  • copy_clipboard para copiar al portapapeles
  • cut_clipboard en el caso de que quieras cortar
  • paste_clipboard para pegar desde el portapapeles en la posición indicada por un Gtk.TextIter.

Señales

Por supuesto que Gtk.TextBuffer viene cargado de señales que te van a facilitar la interacción con este objeto. De las mas interesantes, por supuesto, es changed que te informa cuando se ha producido un cambio en el contenido. Por ejemplo, si quieres ver el contenido cada vez que se produce un cambio puedes utilizar el siguiente código,

this.buffer.connect('changed', (tb)=>{
    let inicio = tb.get_start_iter();
    let fin = tb.get_end_iter();
    print(tb.get_text(inicio, fin, false));
});

Pero, por supuesto tienes otras señales como apply-tag, insert-text, insert-pixbuf, mark-deleted, mark-set, paste-done.

Conclusiones

Ya has visto algunas de las opciones que puedes ofrecer a un usuario para introducir y editar texto con GTK y JavaScript, en tus aplicaciones. Desde la solución mas sencilla, que te ofrece Gtk.Entry a una algo mas compleja como es Gtk.TextView.

Estas, no son las únicas, pero son las que utilizarás, en principio, con mas frecuencia.


Imagen de portada de Michelle Miralles en Unsplash

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *