[pygtk-docs] 2010-03-16 Rafael Villar Burke <pachi rvburke com>



commit bab20402742efad54f4e8b1b17d000f1c2280a4d
Author: Rafael Villar Burke <pachi rvburke com>
Date:   Tue Mar 16 15:37:07 2010 +0100

    2010-03-16  Rafael Villar Burke  <pachi rvburke com>
    
    		* README: Fix typo
    		* README-es: Add Spanish README
    		* tut-es/TipsForWritingPygtkApplications.xml: add newer content.

 ChangeLog                                  |    6 +
 README                                     |    2 +-
 README-es                                  |   19 ++
 tut-es/TipsForWritingPygtkApplications.xml |  448 +++++++++++++++++++++++++++-
 4 files changed, 473 insertions(+), 2 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 9805fe1..2e005c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2010-03-16  Rafael Villar Burke  <pachi rvburke com>
+
+		* README: Fix typo
+		* README-es: Add Spanish README
+		* tut-es/TipsForWritingPygtkApplications.xml: add newer content.
+
 2009-07-07  John Finlay  <finlay moeraki com>
 
 	* pygtk-docs.doap: Add file.
diff --git a/README b/README
index da4995b..1112798 100644
--- a/README
+++ b/README
@@ -5,7 +5,7 @@ simply do:
 
 When adding an example, put it in the examples subdirectory.  Be aware
 that a link to it in the generate HTML will 404 until you remake the
-links in pygtktutorial/examples.  The easiest way to forcxe this is to
+links in pygtktutorial/examples.  The easiest way to force this is to
 do:
 
    make clean; make tut-html
diff --git a/README-es b/README-es
new file mode 100644
index 0000000..bb2c6c8
--- /dev/null
+++ b/README-es
@@ -0,0 +1,19 @@
+El tutorial PyGTK esta mantenido con XML-DocBook. Para construir una versión
+HTML, simplemente haz:
+
+    make tut-html
+
+Cuando añadas un ejemplo, ponlo en el subdirectorio de ejemplos. Ten cuidado
+que un enlace en él para la generación del HTML no produzca 404 hasta que tu
+rehagas los enlaces en pygtktutorial/examples. La manera más fácil de forzar
+esto es hacer:
+
+    make clean; make tut-html
+
+La numerácion en línea mostrada en los ejemplos esta hecha con nl(1), sin
+opciones.
+
+El entorno requerido para construir el HTML incluye xsltproc, el DocBook de las
+hojas de estilos, el programa GNU pic2graph (parte de la distribución groff)
+que es usada para contruir diagramas de cajas-y-flecha y GraphicsMagick (para
+el programa convert(1) necesario para pic2graph).
diff --git a/tut-es/TipsForWritingPygtkApplications.xml b/tut-es/TipsForWritingPygtkApplications.xml
index c2a0856..9c9009a 100644
--- a/tut-es/TipsForWritingPygtkApplications.xml
+++ b/tut-es/TipsForWritingPygtkApplications.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
 "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
 
 <!-- ********************************************************************** -->
@@ -11,4 +11,450 @@ de estilo generales y trucos para crear buenas aplicaciones PyGTK. Actualmente
 esta sección es muy corta, pero espero que se vaya haciendo más larga en
 futuras ediciones de este tutorial.</para>
 
+<!-- ===================================================================== -->
+    <sect1>
+    <title>El usario debería manejar la interfaz, no al contrario</title>
+
+<para>PyGTK, como otros conjuntos de herramientas, te proporciona maneras de
+invocar widgets, tales como la bandera <constant>DIALOG_MODAL</constant>
+que se pasa a los dialogos, que requiere una respuesta desde el usuario
+antes de que el resto de la aplicación continúe. En Python, como en otros
+lenguajes, es una buena práctica evitar el uso de elementos de interfaz
+modales.</para>
+
+<para>En cada interacción modal la aplicación fuerza un
+flujo particular en el usuario y, si bien esto es en algún momento
+inevitable, como regla general debe evitarse, ya que la aplicación debe
+tratar de adaptarse al flujo de trabajo preferido por el usuario.</para>
+
+<para>Un caso particularmente frecuente de esto es la solicitud de
+confirmación. Cada una de ellas debería correponder a un punto en el que
+se debería porporcionar la posibilidad de deshacer los cambios. GIMP, la
+aplicación para la que se desarrolló inicialmente GTk+, evita muchas
+operaciones que necesitarían detenerse y solicitar confirmación del
+usuario mediante una instrucción de deshacer que permite deshacer
+cualquier operación que ejecuta.</para>
+
+    </sect1>
+
+<!-- ===================================================================== -->
+    <sect1>
+    <title>Separa el modelo de datos de la interfaz</title>
+
+<para>El sistema de objetos flexible e implícito de Python reduce el coste
+de la toma de decisiones sobre la arquitectura de la aplicación en comparación
+con otros lenguajes más rígidos (sí, <emphasis>estamos</emphasis> pensando en C++).
+Una de ellas es la cuidadosa separación del modelo de datos (las clases y
+estructuras de datos que representan el estado para los que la aplicación está
+diseñada para manejar) del controlador (las clases que implementan la interfaz
+de usuario).</para>
+
+<para>En Python, un patrón de uso habitual es el de tener una clase principal
+editora/controladora que encapsula la interfaz de usuario
+(con, probablemente, pequeñas clases para controles que mantengan su estado) y
+una clase de modelo principal que encapsula el estado de la aplicación
+(probablemente con algunos miembros que son en sí mismos instancias de
+pequeñas clases para representación de datos).
+
+La clase controladora (controlador) llama a métodos de la clase modelo
+(el modelo) para realizar su manipulación de datos. A su vez, el modelo
+delega la representación en pantalla y el procesado de entrada de datos al
+controlador.</para>
+
+<para>Reducir la interfaz entre el modelo y el controlador facilita evitar
+quedar atrapado en decisiones iniciales sobre la relación entre cualquiera
+de ambas partes. También hace más sencillo el mantenimiento de la aplicación y
+el diagnóstico de fallos.</para>
+    </sect1>
+<!-- ===================================================================== -->
+<sect1>
+  <title>Cómo separar los Métodos de Retrollamada de los Manejadores de Señal</title>
+  <sect2>
+    <title>Introducción</title>
+
+    <para>
+        No es necesario almacenar todas las retrollamadas en un único archivo de
+        programa. Se pueden separar en clases independientes, en archivos
+        separados. De esta forma la aplicación principal puede derivar sus
+        métodos de esas clases mediante herencia. Al final se acaba con toda
+        la funcionalidad inicial con el beneficio de un mantenimiento más
+        sencillo, reusabilidad del código y menores tamaños de archivo, lo que
+        significa menor carga para los editores de texto.
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>Herencia</title>
+
+    <para>
+        La herencia es una forma de reutilizar el código. Una clase puede heredar
+        su funcionalidad de otras clases, y un aspecto estupendo de la herencia
+        es que podemos usarla para dividir un programa enorme en grupos lógicos
+        de partes menores, más fáciles de mantener.
+    </para>
+
+    <para>
+        Ahora, dediquemos un momento a la terminología. Una clase derivada,
+        también denominada subclase o clase hija, es una clase que deriva parte
+        de su funcionalidad de otras clases.
+
+        Una clase base, también llamada superclase o clase madre, es de dónde
+        hereda una clase derivada.
+    </para>
+
+    <para>
+        Abajo se muestra un pequeño ejemplo para familiarizarse con la
+        herencia. Es una buena idea probar esto en el intérprete de Python para
+        ganar experiencia de primera mano.
+    </para>
+
+    <para>
+      Creamos dos clases base:
+    </para>
+
+    <programlisting>
+class base1:
+   base1_attribute = 1
+   def base1_method(self):
+     return "hola desde la clase base 1"
+
+class base2:
+   base2_attribute = 2
+   def base2_method(self):
+     return "hola desde la clase base 2"
+    </programlisting>
+
+    <para>
+      Luego creamos una clase derivada que hereda de esas dos clases base:
+    </para>
+
+    <programlisting>
+class derived(base1, base2):  # clase derivada de dos clases base
+   var3 = 3
+    </programlisting>
+
+    <para>
+      Ahora la clase derivada tiene toda la funcionalidad de las clases base.
+    </para>
+
+    <programlisting>
+x = derived()        # crea una instancia de la clase derivada
+x.base1_attribute    # 1
+x.base2_attribute    # 2
+x.var3               # 3
+x.base1_method()     # hola desde la clase base 1
+x.base2_method()     # hola desde la clase base 2
+    </programlisting>
+
+    <para>
+        El objeto llamado x tiene la habilidad de acceder a las variables y métodos
+        de las clases base porque ha heredado su funcionalidad. Ahora apliquemos este
+        concepto a una aplicación de PyGTK.
+    </para>
+
+  </sect2>
+
+
+  <sect2>
+    <title>Herencia aplicada a PyGTK</title>
+
+    <para>
+      Crea un archivo llamado gui.py, y luego copia este código en él:
+    </para>
+
+    <programlisting>
+#Un archivo llamado: gui.py
+
+import pygtk
+import gtk
+
+# Crea una definición de clase llamada gui
+class gui:
+  #
+  #          MÉTODOS DE RETROLLAMADA
+  #------------------------------------
+  def open(self, widget):
+    print "abre cosas"
+  def save(self, widget):
+    print "guarda cosas"
+  def undo(self, widget):
+    print "deshace cosas"
+  def destroy(self, widget):
+    gtk.main_quit()
+
+
+  def __init__(self):
+    #
+    #        CÓDIGO DE CONSTRUCCIÓN DE GUI
+    #-----------------------------------------------
+    self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+    self.window.show()
+    self.vbox1 = gtk.VBox(False, 25)
+    self.window.add(self.vbox1)
+    open_button = gtk.Button(label="Abre cosas")
+    open_button.set_use_stock(True)
+    self.vbox1.pack_start(open_button, False, False, 0)
+    open_button.show()
+    save_button = gtk.Button(label="Guarda Cosas")
+    self.vbox1.pack_start(save_button, False, False, 0)
+    save_button.show()
+    undo_button = gtk.Button(label="Deshacer")
+    self.vbox1.pack_start(undo_button, False, False, 0)
+    undo_button.show()
+    self.vbox1.show()
+    #
+    #        MANEJADORES DE SEÑAL
+    #------------------------------------------------
+    open_button.connect("clicked", self.open)
+    save_button.connect("clicked", self.save)
+    undo_button.connect("clicked", self.undo)
+    self.window.connect("destroy", self.destroy)
+
+  def main(self):
+   gtk.main()
+
+if __name__ == "__main__":
+ gui_instance = gui()       # crea un objeto gui
+ gui_instance.main()        # llama al método principal
+    </programlisting>
+
+    <para>
+        Si se ejecuta el programa se comprueba que se trata de una única
+        ventana con algunos botones. Tal como está organizado ahora el
+        programa, todo el código está en un único archivo. Pero en un
+        momento se verá cómo dividir el programa en múltiples archivos. La
+        idea es retirar esos cuatro métodos de retrollamada de la clase gui
+        y ponerlos en sus propias clases, en archivos independientes. En el
+        caso de que se tuviesen cientos de métodos de retrollamada se
+        procuraría agruparlos de alguna forma lógica como, por ejemplo,
+        situando todos los métodos que se dedican a entrada/salida en la
+        misma clase, y de esa manera se harían otras clases para grupos de
+        métodos.
+    </para>
+
+    <para>
+        Lo primero que tenemos que hacer es construir algunas clases para los
+        métodos del archivo gui.py. Creamos tres nuevos archivos de texto,
+        llamados io.py, undo.py y destroy.py, y sitúa esos archivos en
+        el mismo subdirectorio que el archivo gui.py. Copia el código
+        siguiente en el archivo io.py:
+    </para>
+
+    <programlisting>
+class io:
+  def open(self, widget):
+    print "abre cosas"
+
+  def save(self, widget):
+    print "guarda cosas"
+    </programlisting>
+
+    <para>
+        Estos son los dos métodos de retrollamada, open y save, del programa
+        gui.py. Copia el siguiente bloque de código en el archivo undo.py:
+    </para>
+
+    <programlisting>
+class undo:
+  def undo(self, widget):
+    print "deshace cosas"
+    </programlisting>
+
+    <para>
+        Este es el método undo de gui.py. Y, finalmente, copia el siguiente
+        código en destroy.py:
+    </para>
+
+    <programlisting>
+import gtk
+
+class destroy:
+  def destroy(self, widget):
+    gtk.main_quit()
+    </programlisting>
+
+    <para>
+      Ahora todos los métodos están separados en clases independientes.
+    </para>
+
+    <graphic fileref="images/important.gif"></graphic>
+    <important>
+      <para>
+        En tus futuras aplicaciones querrás importar módulos como gtk, pango,
+        os ect...  en tu clase derivada (la que contiene todo el código de
+        inicialización de GUI), pero recuerda que necesitarás importar también
+        algunos de esos módulos en las clases base. Podrías tener que crear una
+        instancia de un control de gtk en el método de una clase base, y en ese
+        caso necesitarías importar gtk.
+      </para>
+
+      <para>
+        Este es solamente un ejemplo de una clase base en la que sería
+        necesario importar gtk.
+      </para>
+
+      <programlisting>
+  import gtk
+
+  class Font_io
+    def Font_Chooser(self,widget):
+      self.fontchooser = gtk.FontSelectionDialog("Elige Fuente")
+      self.fontchooser.show()
+      </programlisting>
+
+      <para>
+          Hay que observar que define un control gtk: un diálogo de selección
+          de fuente. Normalmente se importaría gtk en la clase principal (la
+          clase derivada) y todo funcionaría correctamente. Pero desde el
+          momento que se extrae este Fon_Chooser de la clase principal y se
+          pone en su propia clase y luego se intenta heredar de ella, nos
+          encontraríamos con un error.
+          En este aso, ni siquiera se detectaría el error hasta el momento
+          de ejecutar la aplicación. Pero cuando se intente usar el
+          Font_Chooser se encontraría que gtk no está definido, aunque se haya
+          importado en la clase derivada. Así que se ha de recordar que, cuando
+          se crean clases base, es necesario añadir sus propios import.
+      </para>
+    </important>
+
+    <para>
+        Con esas tres clases en sus tres archivos py, es necesario cambiar el
+        código en gui.py de tres modos:
+    </para>
+
+    <orderedlist numberation="arabic">
+      <listitem><para>Importar las clases que se han creado.</para></listitem>
+      <listitem><para>Modificar la definición de la clase.</para></listitem>
+      <listitem><para>Eliminar los métodos de retrollamada.</para></listitem>
+    </orderedlist>
+
+    <para>
+      El siguiente código actualizado muestra cómo hacerlo:
+    </para>
+
+
+    <programlisting>
+#Un archivo llamado:  gui.py
+#(versión actualizada)
+#(con herencia múltiple)
+
+import pygtk
+import gtk
+
+from io import file_io                       #
+from undo import undo                        # 1. Importa tus clases
+from destroy import destroy                  #
+
+# Crea una definición de clase llamada gui
+class gui(io, undo, destroy):                # 2. Definición de clase modificada
+                                             # 3. Retrollamadas eliminadas
+  def __init__(self):
+    #
+    #        CÓDIGO DE CONSTRUCCIÓN DE GUI
+    #-----------------------------------------------
+    self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+    self.window.show()
+    self.vbox1 = gtk.VBox(False, 25)
+    self.window.add(self.vbox1)
+    open_button = gtk.Button(label="Open Stuff")
+    open_button.set_use_stock(True)
+    self.vbox1.pack_start(open_button, False, False, 0)
+    open_button.show()
+    save_button = gtk.Button(label="Save Stuff")
+    self.vbox1.pack_start(save_button, False, False, 0)
+    save_button.show()
+    undo_button = gtk.Button(label="Undo")
+    self.vbox1.pack_start(undo_button, False, False, 0)
+    undo_button.show()
+    self.vbox1.show()
+    #
+    #        MANEJADORES DE SEÑAL
+    #------------------------------------------------
+    open_button.connect("clicked", self.open_method)
+    save_button.connect("clicked", self.save_method)
+    undo_button.connect("clicked", self.undo_method)
+    self.window.connect("destroy", self.destroy)
+
+  def main(self):
+   gtk.main()
+
+if __name__ == "__main__":
+ gui_instance = gui()       # crea un objeto gui
+ gui_instance.main()        # llamada al método principal
+    </programlisting>
+
+    <para>
+      Estas tres líneas son nuevas:
+    </para>
+
+    <programlisting>
+       from io import io
+       from undo import undo
+       from destroy import destroy
+    </programlisting>
+
+    <para>
+      Las instrucciones import tienen la forma:
+    </para>
+
+    <programlisting>
+       from [nombre de archivo de la clase] import [nombre de la clase]
+    </programlisting>
+
+    <para>
+      Este es el cambio de la definición de la clase:
+    </para>
+
+    <programlisting>
+       class gui(io, undo, destroy):
+    </programlisting>
+
+    <para>
+        Los nombres de las clases base van entre paréntesis en la definición
+        de la clase. Ahora la clase gui es una clase derivada y es capaz de
+        usar todos los atributos y métodos definidos en sus clases base.
+        También, la case gui hereda de múltiples clases (dos o más); es lo
+        que se conoce como heréncia múltiple.
+    </para>
+
+    <para>
+        Ahora cambia el archivo gui.py a la versión actualizada y ejecuta la
+        aplicación de nuevo. Verás que funciona exactamente del mismo modo,
+        salvo que ahora todos los métodos de retrollamada están en clases
+        independients, y son heredadas por la clase gui.
+    </para>
+
+    <para>
+        Hay otro tema de interés que comentar. Mientras que tu aplicación
+        gui.py y tus archivos de clases base estén en el mismo directorio
+        todo funcionará correctamente. Pero si quieres crear otro directorio
+        en el que situar los archivos con las clases base, entonces es
+        necesario añadir dos líneas más de código junto al resto de
+        intrucciones import en gui.py. Así:
+    </para>
+
+    <programlisting>
+        import sys
+        sys.path.append("classes")
+    </programlisting>
+
+    <para>
+        en donde "classes" es el nombre del directiro en el que se guardan las
+        clases base. Esto permite que Python sepa dónde localizarlas.
+        Pruébalo. Simplemente crea un directorio llamado classes en el
+        directorio en el que está el programa gui.py. Luego añade los archivos
+        de las tres clases base al directorio classes. Añade las dos líneas de
+        código anteriores a la parte superior del archivo gui.py. Y, ¡listo!
+    </para>
+
+    <para>
+        Una nota final para quienes usan py2exe para compilar aplicaciones
+        Python.  Si se ponen las cases base en el directorio de Python,
+        entonces py2exe los incluirá en la versión compilada de la aplicación
+        como con cualquier otro módulo Python.
+    </para>
+
+  </sect2>
+
+</sect1>
   </chapter>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]