13.3. Buffers de Texto

El TextBuffer (Buffer de Texto) es el componente principal del sistema de edición de texto de PyGTK. Contiene el texto, las TextTag (Etiquetas de Texto) en una TextTagTable (Tabla de Etiquetas de Texto) y las TextMark (Marcas de Texto) que juntos describen cómo debe visualizarse el texto y permiten la modificación del texto de forma interactiva. Como ya se dijo en la sección anterior, un TextBuffer está asociado con una o más TextView (Vistas de Texto), que muestran el contenido del TextBuffer.

Un TextBuffer se puede crear automáticamente cuando se crea una TextView o se puede crear con la función:

  textbuffer = TextBuffer(tabla=None)

donde tabla es una TextTagTable. Si no se especifica tabla (o si es None) se creará una TextTagTable para el Buffer de Texto.

Existen numerosos métodos que se pueden usar para:

13.3.1. Información de estado de un Buffer de Texto

Se puede conocer el número de líneas en un textbuffer usando el método:

  line_count = textbuffer.get_line_count()

De manera análoga es posible saber el número de caracteres en el textbuffer usando:

  char_count = textbuffer.get_char_count()

Cuando el contenido del textbuffer cambia la bandera de modificación del buffer de texto se activa. El estado de la bandera de modificación se puede consultar usando el método:

  modified = textbuffer.get_modified()

Si el programa guarda el contenido del buffer de texto el siguiente método se puede usar para reiniciar la bandera de modificación:

  textbuffer.set_modified(setting)

13.3.2. Creación de Iteradores de Texto

Un TextIter se usa para especificar una localización dentro de un TextBuffer entre dos caracteres. Los métodos de TextBuffer que manipulan texto usan Iteradores de Texto TextIter para especificar dónde se aplicará el método. Los Iteradores de Texto TextIter tienen un gran número de métodos que se describen en la sección TextIter.

Los métodos básicos del TextBuffer que se usan para crear TextIters son:

  iter = textbuffer.get_iter_at_offset(char_offset)

  iter = textbuffer_get_iter_at_line(line_number)

  iter = textbuffer.get_iter_at_line_offset(line_number, line_offset)

  iter = textbuffer.get_iter_at_mark(mark)

get_iter_at_offset() crea un iterador que se situa después de tantos caracteres como diga el argumento char_offset a partir del comienzo del buffer de texto.

get_iter_at_line() crea un iterador que está justo antes del primer caracter en la línea que diga el parámetro line_number.

get_iter_at_line_offset() crea un iterador que está justo detrás del carácter especificado por el parámetro line_offset en la línea especificada por el parámetro line_number.

get_iter_at_mark() crea un iterador que está en la misma posición que la marca especificada por el parámetro mark.

Los siguientes métodos crean uno o más iteradores en localizaciones específicas del buffer de texto:

  startiter = textbuffer.get_start_iter()

  enditer = textbuffer_get_end_iter()

  startiter, enditer = textbuffer.get_bounds()

  start, end = textbuffer.get_selection_bounds()

get_start_iter() crea un iterador que está justo antes del primer caracter en el buffer de texto.

get_end_iter() crea un iterador que está justo después del último caracter en el buffer de texto.

get_bounds() crea una tupla de dos iteradores que están justo antes del primer caracter y justo detrás del último caracter del buffer de texto respectivamente.

get_selection_bounds() crea una tupla de dos iteradores que están en las mismas posiciones que las marcas insert y selection_bound en el buffer de texto.

13.3.3. Inserción, Obtención y Eliminación de Texto

El texto de un TextBuffer se puede fijar con el método:

  textbuffer.set_text(text)

Este método reemplaza el contenido actual del buffer de texto con el texto text que se le pasa como parámetro.

El método más general para insertar caracteres en un buffer de texto es:

  textbuffer.insert(iter, text)

el cual inserta el texto text en la posición del buffer de texto especificada por el iterador iter.

Si quieres simular la inserción de texto que produciría un usuario interactivo usa este método:

  result = textbuffer.insert_interactive(iter, text, default_editable)

el cual inserta el texto text en la posición del buffer de texto especificada por el iterador iter pero sólo si la posición es editable (es decir, no tiene una etiqueta que especifique que el texto no es editable) y el argumento default_editable es TRUE. El resultado indica si el texto fue insertado o no.

El argumento default_editable indica si es editable o no cuando el texto no tiene una etiqueta que lo especifique; default_editable normalmente se determina llamando al método get_editable() de TextView.

Otros métodos que insertan texto son:

  textbuffer.insert_at_cursor(text)

  result = textbuffer.insert_at_cursor_interactive(text, default_editable)

  textbuffer.insert_range(iter, start, end)

  result = textbuffer.insert_range_interactive(iter, start, end, default_editable)

insert_at_cursor() es una función auxiliar que inserta el texto en la posición actual del cursor (señalada por insert).

insert_range() copia el texto, pixbuffers y etiquetas entre start y end de un TextBuffer (si las etiquetas pertenecen a otro buffer de texto la tabla de etiquetas debe ser la misma) y los inserta en el buffer de texto en la posición especificada por iter.

Las versiones interactivas de estos métodos funcionan de la misma forma excepto que sólo insertarán el texto si las posiciones son editables.

Finalmente, el texto se puede insertar y asociar a etiquetas al mismo tiempo usando los métodos:

  textbuffer.insert_with_tags(iter, text, tag1, tag2, ...)
  
  textbuffer.insert_with_tags_by_name(iter, text, tagname1, tagname2, ...)

insert_with_tags() inserta el texto text en el buffer de texto en la posición especificada por iter y le aplica las etiquetas especificadas.

insert_with_tags_by_name() hace lo mismo pero te permite especificar las etiquetas por su nombre.

El texto de un buffer de texto se puede borrar usando los métodos:

  textbuffer.delete(start, end)
  
  result = textbuffer.delete_interactive(start, end, default_editable)

delete() borra el texto entre los iteradores TextIter start y end en el buffer de texto.

delete_interactive() borra todo el texto editable (determinado por las etiquetas de texto aplicables y el argumento default_editable) entre start y end.

Puedes obtener una copia del texto de un buffer de texto usando los métodos:

  text = textbuffer.get_text(start, end, include_hidden_chars=TRUE)

  text = textbuffer.get_slice(start, end, include_hidden_chars=TRUE)

get_text() devuelve una copia del texto en el buffer de texto entre start y end; si el argumento include_hidden_chars es FALSE el texto que no se visualice no se devuelve. Los caracteres que representan imágenes incrustadas o controles, son excluidos.

get_slice() es igual que get_text() excepto que el texto que devuelve incluye un carácter 0xFFFC por cada imágene incrustada o control.

13.3.4. Marcas de Texto (TextMark)

Las TextMarks (Marcas de Texto) son similares a los TextIter ya que también especifican posiciones en un TextBuffer entre dos caracteres. Sin embargo, las Marcas de Texto TextMark mantienen su posición aunque el buffer cambie. Los métodos de las Marcas de Texto TextMark se describirán en la sección TextMark.

Un buffer de texto contiene de serie dos marcas predeterminadas: la marca insert (insertar) y la marca selection_bound (límite de la selección). La marca insert es la posición predeterminada de inserción del texto y la marca selection_bound combinada con la marca insert define un rango de selección.

Las marcas predeterminadas de serie se pueden obtener con los métodos:

  insertmark = textbuffer.get_insert()

  selection_boundmark = textbuffer.get_selection_bound()

Las marcas insert y selection_bound se pueden colocar simultáneamente en una posición usando el método:

  textbuffer.place_cursor(where)

donde where es un iterador de texto que especifica la posición. El método place_cursor() es necesario para evitar crear una selección temporal si las marcas se movieran individualmente.

Las TextMarks se crean usando el método:

  mark = textbuffer.create_mark(mark_name, where, left_gravity=FALSE)

donde mark_name es el nombre que se le asigna a la marca (puede ser None para crear una marca anónima), where es el iterador de texto que especifica la posición de la marca en el buffer de texto y left_gravity indica dónde se pondrá la marca cuando se inserte texto en la marca (a la izquierda si es TRUE o a la derecha si es FALSE).

Se puede mover una marca en el buffer de texto usando los métodos:

  textbuffer.move_mark(mark, where)

  textbuffer.move_mark_by_name(name, where)

mark especifica la marca que se va a mover. name especifica el nombre de la marca que se va a mover. where es un iterador de texto qeu especifica la nueva posición.

Una marca se puede borrar de un buffer de texto usando los métodos:

  textbuffer.delete_mark(mark)

  textbuffer.delete_mark_by_name(name)

Se puede recuperar una marca a partir de su nombre con el método:

  mark = textbuffer.get_mark(name)

13.3.5. Creación y Uso de Etiquetas de Texto

Las TextTags (Etiquetas de Texto) contienen uno o más atributos (por ejemplo, colores de frente y de fondo, fuentes de texto, editabilidad) que se pueden aplicar a uno o más rangos de texto en un buffer de texto. Los atributos que se pueden especificar mediante propiedades de una TextTag se describirán en la sección TextTag.

Una TextTag se puede crear con atributos e instalada en la TextTagTable (Tabla de Etiquetas de Texto) de un TextBuffer (Buffer de Texto) usando el siguiente método:

  tag = textbuffer.create_tag(name=None, attr1=val1, attr2=val2, ...)

donde name es una cadena de texto que especifica el nombre de la etiqueta o None si la etiqueta es una etiqueta anónima y los pares de clave-valor especifican los atributos que tendrá la etiqueta. Mira la sección TextTag para obtener más información acerca de qué atributos se pueden establecer mediante las propiedades de una TextTag.

Una etiqueta se puede aplicar a un rango de texto en un buffer de texto usando los métodos:

  textbuffer.apply_tag(tag, start, end)

  textbuffer.apply_tag_by_name(name, start, end)

tag es la etiqueta que se va a aplicar al texto. name es el nombre de la etiqueta a aplicar. start (comienzo) y end (final) son los iteradores de texto que especifican el rango de texto que será afectado por la etiqueta.

Se puede borrar una etiqueta de un rango de texto usando los métodos:

  textbuffer.remove_tag(tag, start, end)

  textbuffer.remove_tag_by_name(name, start, end)

Se pueden borrar todas las etiquetas de un rango de texto usando el método:

  textbuffer.remove_all_tags(start, end)

13.3.6. Inserción de Imágenes y Controles

Además de texto, un TextBuffer puede contener imágenes y un punto de anclaje para controles. Se puede añadir un control a una TextView en un punto de anclaje. Se puede añadir un control diferente en cada TextView que tenga un buffer con un punto de anclaje.

Se puede insertar un pixbuf con el siguiente método:

  textbuffer.insert_pixbuf(iter, pixbuf)

donde iter especifica la posición en el textbuffer donde insertar el pixbuf. La imagen contará como un caracter y será representada en lo que devuelve get_slice() (pero no en lo que devuelve get_text() ) como el caracter Unicode "0xFFFC".

Se puede insertar un control GTK+ en una TextView en una posición del buffer especificada por un TextChildAnchor (Anclaje de Hijo del Texto). El TextChildAnchor contará como un carácter representado por "0xFFFC" de manera similar a un pixbuf.

El TextChildAnchor se puede crear e insertar en el buffer usando este método:

  anchor = text_buffer.create_child_anchor(iter)

donde iter es la posición del anclaje.

También se puede crear e insertar un TextChildAnchor con dos operaciones por separado:

  anchor = gtk.TextChildAnchor()

  text_buffer.insert_child_anchor(iter, anchor)

Después se puede añadir el control al TextView en la posición del anclaje usando el método:

  text_view.add_child_at_anchor(child, anchor)

Se puede obtener la lista de controles en una posición especifica del buffer usando el método:

  widget_list = anchor.get_widgets()

También se puede añadir un control al TextView usando el método:

  text_view.add_child_in_window(child, which_window, xpos, ypos)

donde el control child se coloca en la ventana which_window en la posición especificada por xpos e ypos. El parámetro which_window indica en cuál de las ventanas que componen el control TextView se colocará el control:

  gtk.TEXT_WINDOW_TOP     # ventana superior del texto
  gtk.TEXT_WINDOW_BOTTOM  # ventana inferior del texto
  gtk.TEXT_WINDOW_LEFT    # ventana izquierda del texto
  gtk.TEXT_WINDOW_RIGHT   # ventana derecha del texto
  gtk.TEXT_WINDOW_TEXT    # ventana de texto del texto
  gtk.TEXT_WINDOW_WIDGET  # ventana de control del texto