Capítulo 15. Nuevos Controles de PyGTK 2.2

Tabla de contenidos

15.1. Portapapeles (Clipboard)
15.1.1. Creación de un objeto Clipboard (Portapapeles)
15.1.2. Utilización de Clipboards con elementos Entry, Spinbutton y TextView
15.1.3. Incorporación de datos en un portapapeles
15.1.4. Obtención de los Contenidos del Portapapeles
15.1.5. Ejemplo de Portapapeles

El objeto Clipboard (portapapeles) ha sido añadido en PyGTK 2.2. GtkClipboard estaba disponible en GTK+ 2.0 pero no era incluido en PyGTK 2.0 debido a que no se trataba de un GObject completo. Se añadieron también algunos objetos nuevos al módulo gtk.gdk en PyGTK 2.2 pero no se describirán en este tutorial. Véase el Manual de Referencia de PyGTK 2 para obtener información adicional sobre los objetos gtk.gdk.Display, gtk.gdk.DisplayManager y gtk.gdk.Screen.

15.1. Portapapeles (Clipboard)

Un Clipboard (portapapeles) aporta una zona de almacenamiento que permite compartir datos entre procesos o entre distintos controles del mismo proceso. Cada Clipboard se identifica con un nombre (una cadena de texto) codificada como un gdk.Atom. Es posible utilizar cualquier nombre para identificar un portapapeles (Clipboard) y se creará uno nuevo en caso de que no exista. Para que se pueda compartir un objeto Clipboard entre distintos procesos, es preciso que cada uno de ellos conozca el nombre del mismo.

Los elementosClipboard están hechos sobre las interfaces de selección y SelectionData. El portapapeles usado por defecto por los controles TextView, Label y Entry es "CLIPBOARD". Otros portapapeles comunes son "PRIMARY" y "SECONDARY", que se corresponden con las selecciones primaria y secundaria (Win32 las ignora). Estos objetos pueden igualmente ser especificados utilizando los objetos gtk.gdk.Atom siguientes: gtk.gdk.SELECTION_CLIPBOARD, gtk.gdk.SELECTION_PRIMARY y gtk.gdk.SELECTION_SECONDARY. Para mayor información véase la documentación de referencia de gtk.gdk.Atom.

15.1.1. Creación de un objeto Clipboard (Portapapeles)

Los objetos Clipboard se crean mediante el constructor:

  clipboard = gtk.Clipboard(display, selection)

donde display es el gtk.gdk.Display asociado con el Clipboard denominado por selection. La función auxiliar que sigue crea un portapapeles (Clipboard) haciendo del gtk.gdk.Display por defecto:

  clipboard = gtk.clipboard_get(selection)

Finalmente, un Clipboard también puede crearse utilizando el método de la clase Widget:

  clipboard = widget.get_clipboard(selection)

El control widget debe haber sido realizado y ha de formar parte de una ventana de una jerarquía de ventana de primer nivel.

15.1.2. Utilización de Clipboards con elementos Entry, Spinbutton y TextView

Los controles Entry, SpinButton y TextView poseen menús emergentes que proporcionan la capacidad de copiar y pegar el texto seleccionado desde el portapapeles 'CLIPBOARD' así como pegarlo desde el mismo. Además, se dispone de combinaciones de teclas que sirven de atajos para cortar, copiar y pegar. Cortar se activa con Control+X; copiar con Control+C; y pegar con Control+V.

Esos controles (Entry y SpinButton) implementan la interfaz Editable, de manera que poseen los siguientes métodos para cortar, copiar y pegar de y hacia el portapapeles "CLIPBOARD":

  editable.cut_clipboard()
  editable.copy_clipboard()
  editable.paste_clipboard()

Una etiqueta Label que sea seleccionable (su propiedad "selectable" es TRUE) también permite la copia del texto seleccionado al portapapeles "CLIPBOARD" utilizando un menú emergente o la combinación de teclas rápidas Control+C.

Los TextBuffers poseen métodos simiares, aunque permiten indicar el portapapeles que se ha de usar:

  textbuffer.copy_clipboard(clipboard)

El texto de la selección será copiado al portapapeles especificado por clipboard.

  textbuffer.cut_clipboard(clipboard, default_editable)

El texto seleccionado será copiado a clipboard. Si default_editable es TRUE, entonces el texto seleccionado será borrado del TextBuffer. En otro caso, cut_clipboard() funcionará como el método copy_clipboard().

  textbuffer.paste_clipboard(clipboard, override_location, default_editable)

Si default_editable es TRUE, los contenidos del portapapeles clipboard serán insertados en el TextBuffer en la posición indicada por el iterador TextIter override_location. Si default_editable es FALSE, entonces paste_clipboard() no insertará los contenidos de clipboard. Si override_location es None los contenidos del portapapeles clipboard se insertarán en la posición del cursor.

Los TextBuffers también tienen dos métodos para gestionar un conjunto de objetos Clipboard que se establecen de forma automática con los contenidos de la selección vigente:

  textbuffer.add_selection_clipboard(clipboard) # añadir portapapeles de selección
  textbuffer.remove_selection_clipboard(clipboard) # eliminar portapapeles de selección

Cuando se añade un TextBuffer a una vista de texto (TextView) se añade automáticamente el portapapeles "PRIMARY" a los portapapeles de selección. La aplicación puede añadir otros portapapeles a conveniencia (por ejemplo, el portapapeles "CLIPBOARD").

15.1.3. Incorporación de datos en un portapapeles

Se pueden establecer los datos de un portapapeles Clipboard de forma programática utilizando los métodos:

  clipboard.set_with_data(targets, get_func, clear_func, user_data)

  clipboard.set_text(text, len=-1)

El método set_with_data() indica que destinos se soportan para los datos seleccionados y proporciona las funciones (get_func y clear_func), que se llaman al solicitar o cuando cambian los datos del portapapeles. user_data se pasa a get_func o clear_func cuando son llamadas. targets es una lista de tuplas de tres elementos que contiene:

  • una cadena que representa un destino soportado por el portapapeles.
  • un valor de banderas utilizado para arrastrar y soltar (úsese 0).
  • un entero asignado por la aplicación que se pasa como parámetro al manejador de señal para ayudar en la identificación del tipo de destino.

Las signaturas de get_func y clear_func son:

  def get_func(clipboard, selectiondata, info, data):

  def clear_func(clipboard, data):

donde clipboard es el portapapeles de la clase Clipboard, selectiondata es un objeto SelectionData en el que poner los datos, info es el entero asignado por la aplicación asignado al destino, y data son datos de usuario user_data.

set_text() es un método auxiliar que usa a su vez el método set_with_data() para asignar los datos de texto en un portapapeles Clipboard con los destinos: "STRING" (cadena), "TEXT" (texto), "COMPOUND_TEXT" (texto compuesto), y "UTF8_STRING" (cadena UTF-8). Usa funciones internas get y clear para gestionar los datos. set_text() equivale a:

  def my_set_text(self, text, len=-1):
      targets = [ ("STRING", 0, 0),
                  ("TEXT", 0, 1),
                  ("COMPOUND_TEXT", 0, 2),
                  ("UTF8_STRING", 0, 3) ]
      def text_get_func(clipboard, selectiondata, info, data):
          selectiondata.set_text(data)
          return
      def text_clear_func(clipboard, data):
          del data
          return
      self.set_with_data(targets, text_get_func, text_clear_func, text)
      return

Una vez que se introducen datos en un portapapeles, éstos estarán disponibles hasta que se termine el programa o se cambien los datos en el portapapeles.

Para proporcionar el comportamiento típico de cortar al portapapeles la aplicación tendrá que eliminar el texto u objeto correspondiente tras copiarlo al portapapeles.

15.1.4. Obtención de los Contenidos del Portapapeles

Los contenidos de un portapapeles Clipboard se pueden obtener utilizando los siguientes métodos:

  clipboard.request_contents(target, callback, user_data=None)

Los contenidos especificados por target son obtenidos de forma asíncrona en la función indicada por callback, que es llamada con user_data. La signatura de callback es:

  def callback(clipboard, selectiondata, data):

donde selectiondata es un objeto SelectionData con los contenidos del portapapeles clipboard. data son datos de usuario user_data. El método request_contents() es la forma más general de obtener los contenidos de un portapapeles Clipboard. El siguiente método auxiliar recupera los contenidos de texto de un portapapeles Clipboard:

  clipboard.request_text(callback, user_data=None)

Se devuelve la cadena de texto a la retrollamada en vez de un objeto Selectiondata. Se puede comprobar los destinos disponibles para el portapapeles Clipboard utilizando el método:

  clipboard.request_targets(callback, user_data=None)

Los destinos se devuelven a la función de retrollamada como tuplas de objetos gtk.gdk.Atom.

Se proporcionan dos métodos auxiliares que devuelven los contenidos del portapapeles Clipboard de forma síncrona:

  selectiondata = clipboard.wait_for_contents(target)

  text = clipboard.wait_for_text()

15.1.5. Ejemplo de Portapapeles

Para ilustrar el uso de un portapapeles Clipboard el programa de ejemplo clipboard.py sigue los elementos de texto que se copian o cortan al cortapapeles "CLIPBOARD" y guarda las últimas diez entradas del cortapapeles. Hay diez botones que proporcionan acceso al texto de las entradas guardadas. La etiqueta del botón muestra los primeros dieciseis caracteres del texto almacenado y las etiquetas de ayuda (pistas) muestran los destinos que tenía la entrada original. Cuando se pulsa un botón de entrada se carga el texto correspondiente, que puede ser editado. A su vez, ell botón bajo la ventana de texto permite guardar los contenidos de la ventana de texto al portapapeles..

Figura 15.1, “Programa de ejemplo de Portapapeles” ilustra el resultado de la ejecución del programa clipboard.py:

Figura 15.1. Programa de ejemplo de Portapapeles

Programa de ejemplo de Portapapeles

El programa de ejemplo consulta el portapapeles cada 1.5 segundos para ver si los contenidos han cambiado. El programa podría modificarse para duplicar el conjunto completo de destinos disponibles y tomar luego control del portapapeles utilizando el método set_with_data(). Posteriormente, si otro programa fija los contenidos del portapapeles, se llamará a la función clear_func, que se puede usar para recargar los contenidos del portapapeles y retomar la propiedad del mismo.