wxFormBuilder, un diseñador para wxPython Antonio Mario Molina Saorín & Ángel Luis García García Taller de wxFormBuilder ● Introducción al Universo de Discurso. – ● wxPython y wxFormBuilder wxFormBuilder. – Diseño y creación de interfaces – Eventos – Herencia y override Universo de Discurso ● ¿Qué es wxFormBuilder? ● Breve repaso de wxPython. ● – Widgets. – Sizers. – Eventos. Requisitos para seguir este taller: – Python 2.6.6 – wxPython 2.8.11 – Stani's Python Editor – wxFormBuilder 3.2 wxFormBuilder, y 1 ● ● ● Desarrollado por José Antonio Hurtado, Juan Antonio Ortega, Ryan Mulder, Ryan Pusztai, Michal Bliznak. Es un entorno WYSISWG para diseño gráfico de interfaces wxWidgets. A partir del diseño gráfico de componentes permite generar código C++, XRC y Python (para el framework wxPython). ● Intuitivo y fácil de utilizar. ● Contiene muchos widgets (NoteBook, Splitter, …) ● Utiliza sizers para posicionamiento de widgets. wxFormBuilder, y 2 ● No es un RAD propiamente dicho, como Microsoft Visual Studio. – Es un diseñador y constructor de interfaces gráficas que utiliza wxPython como framework gráfico para Python. – Por tanto: ● ● En wxFormBuilder diseñamos y creamos la interfaz gráfica. Con una herramienta de edición de código (IDE, editor) llamamos a las clases generadas por wxFormBuilder. wxFormBuilder, y 3 ● Sitio web: http://wxformbuilder.org/. ● ¿Dónde obtener wxFormBuilder? – Para Linux: ● ● ● – En repositorios. LaunchPad. SourceForge. Para Windows: ● SourceForge. wxFormBuilder, y 4 ● Open Source (licencia GPL). ● Alternativas a wxFormBuilder: – wxGlade. – BOA Constructor (un RAD al estilo de Microsoft Visual Studio). – PythonCard. – wxDesigner. – VisualWx. – DialogBlocks. wxPython, y 1 ● wxPython es un framework creado por Robin Dunn, en 1995. ● Es una librería gráfica para Python (al igual que GTK, Qt y Tkinter). ● ● Permite crear programas con una interfaz gráfica robusta y de gran funcionalidad, fácil y simple. Es un wrapper de la plataforma wxWidgets (escrita en C++). – Una adaptación de la biblioteca wxWidgets para ser usada en Python. ● Es Open Source. ● Multiplataforma. (Windows, Unix, Mac). ● Muy documentado. ● Proyecto muy activo – Versión estable: 2.8.12.0 (Abril 2011) – Versión desarrollo: 2.9.1.1 (Octubre 2010) wxPython, y 2 ● Sitio web: http://www.wxpython.org/. ● Además de wxPython se recomienda la instalación de wxPython Demo: – ● contiene la documentación de wxWidgets y multitud de ejemplos. Material bibliográfico recomendado: wxPython, y 3 ● ● wxPython sirve para crear aplicaciones gráficas orientadas a eventos. Un evento es cualquier interacción entre el agente humano y la aplicación, como puede ser un click de ratón. – ● ● ● La generación de un evento provoca una respuesta en el sistema. A cada evento se le puede asociar un código, mediante un proceso llamado binding. El manejador de eventos es el código que se dispara a consecuencia de la generación de un evento. Una aplicación wxPython espera a que se generen eventos, asociando los mismos a un código, llamado manejador de eventos. wxPython, y 4 ● Estructura básica de una aplicación wxPython: # Se importan las wx. import wx # Se instancia una aplicación wxPython. app = wx.PySimpleApp() # Se instancia el contenedor principal. ventana_principal = wx.Frame(None, -1) # Mostramos la ventana. ventana_principal.Show() # Esperamos a los eventos. app.MainLoop() wxPython, y 5 ● Un widget es cualquier componente gráfico con el que interactuar en wxPython (botones, cajas de texto, calendarios, sliders, ...). – ● wx.Frame es un widget contenedor, similar a una ventana de Microsoft Windows. Los widgets pueden disponerse con wx.Point y wx.Size, mediante coordenadas, dentro de un contenedor. Otra forma de hacerlo es mediante el uso de sizers. wxPython, y 6 ● Un sizer es un mecanismo de disposición de widgets en wxPython. – Maneja el tamaño y posición de sus widgets, basado en un conjunto de reglas. – Se asigna a un contenedor (wx.Panel ó wx.Frame). – Es un algoritmo para disponer o enmarcar un grupo de widgets. – Los subwidgets que se crean dentro de un contenedor deben de añadirse por separado al sizer. – El sizer administra la posición de los widgets. wxPython, y 7 ● ● Un sizer en wxPython es un objeto con el único propósito de administrar el posicionamiento de un conjunto de widgets dentro de un contenedor. El sizer es la representación de un algoritmo de posicionamiento de pantalla (no un contenedor ó widget). ● Un sizer es una instancia de la clase wx.Sizer. ● Un sizer puede estar incluido en otro sizer. wxPython, y 8 ● ● Tipos de sizers: – wx.BoxSizer – wx.FlexGridSizer – wx.GridSizer – wx.GridBagSizer – wx.StaticBoxSizer En este taller veremos: – wx.BoxSizer & wx.FlexGridSizer Herramientas a utilizar ● ● ● ● Python 2.6.6. Es la versión, junto a la 2.7, que funciona sin ningún tipo de problemas en wxPython 2.8.X. wxPython 2.8.11.0. Versión estable, junto a la 2.8.12.0. Stani's Python Editor. Es uno de los IDE's gratuitos más potentes y livianos, multiplataforma, con completitud, indentación y coloreado de código, además de otras muchas cualidades. wxFormBuilder 3.2 Beta. Es la última versión. Creación de un proyecto, y 1 Creación de un proyecto, y 2 Guardamos el proyecto con Ctrl+S, ó File/Save, ó haciendo click en botón Guardar. wxFormBuilder: Partes ● wxFormBuilder está compuesto de 4 partes: – Object Tree: Tree El árbol de objetos que compone la interfaz diseñada. – Component Pallete: Pallete Conjunto de widgets y sizers disponibles para diseñar la interfaz. – Editor. Editor Se compone de 4 hojas: ● Designer: Diseño gráfico de la interfaz. ● C++: Código C++ generado a partir del diseño en el Designer. ● ● – Python: Código Python generado a partir del diseño en el Designer. XRC: Código XML generado a partir del diseño en el Designer. Object Properties: Properties Propiedades y eventos de los componentes del Designer. Interfaz 1 Creamos un contenedor wx.Frame. Interfaz 1 Incluimos dentro del contenedor un wx.BoxSizer. Interfaz 1 Incluimos un wx.StaticText; cambiamos la propiedad label, y configuramos el sizeritembase, es decir, cómo queremos que se comporte el widget dentro del sizer base (que lo contiene). Para ello activamos bandera wxALIGN_CENTER y aumentamos el borde a 25. Interfaz 1 Incluimos 3 wx.TextCtrl. Interfaz 1 ¿Cómo redimensionar las 3 cajas de texto? Configurando su posición dentro del sizer base. Para ello hay que activar el flag wx.EXPAND. Interfaz 1 – Código Python generado Conforme se va diseñando la interfaz gráfica se va generando el código Python (Editor, pestaña Python). Para crear el fichero Python pulsar F8, o File/Generate Code o click en icono de generar código. Importando la Interfaz 1 ● ● Una vez creada la interfaz y generado el código Python, creamos el módulo que llamará a dichas clases. En dicho módulo hay que crear una aplicación wxPython, pues wxFormBuilder no lo genera (en contraposición con otros diseñadores, como wxGlade). Abrimos Stani's Python Editor. – Creamos un módulo: datos.py Importando la Interfaz 1 ● Creamos el módulo con el siguiente código y ejecutamos: Ejecutando la Interfaz 1 ● ● Se ha creado una aplicación wxPython, y toma como contenedor principal una instanciación de la clase generada en wxFormBuilder. Cosas a tener en cuenta: – Si se redimensiona el widget contenedor, se redimensionan sus widgets contenidos, automáticamente. – No se puede pasar de un widget wx.TextCtrl a otro mediante la tecla tabulador (TAB), como cabría esperar. ● ¿Solución? Usar paneles. Modificando la Interfaz 1 Incluimos un widget wx.Panel dentro del wx.BoxSizer principal. Modificando la Interfaz 1 Si se incluyen widgets dentro de un contenedor wx.Panel aparece la propiedad de navegación entre widgets a través del tabulador. Todo posicionamiento de widgets se realiza con sizers, por lo que será necesario crear uno dentro del wx.Panel. Modificando la Interfaz 1 Se pueden mover los widgets wx.TextCtrl y wx.StaticText mediante la técnica de Drag & Drop, capturando y soltando los widgets de un sizer al interior de otro. Ejecutando de nuevo la Interfaz 1 ● ● Guardamos el proyecto y volvemos a generar el código Python. Volvemos a Stani's, y sin cambiar nada (en realidad no es necesario), ejecutamos. Ahora aparece la funcionalidad de navegación entre widgets con la tecla TAB. – UTILIZAR SIEMPRE PANELES. Eventos en wxFormBuilder ● ● ● Se ha creado la primera interfaz en wxFormBuilder, completamente funcional. A partir de este diseño se creará un frame con dos botones (en sentido horizontal) de ACEPTAR y CANCELAR. Se crearán los eventos de click en los botones anteriores. Eventos en wxFormBuilder Sobre MyFrame1 botón derecho/Paste y creamos una copia de Frame1 Eventos en wxFormBuilder Eventos en wxFormBuilder ● Renombramos nuevo widget contenedor a MyFrame2, y modificamos algunos atributos. Eventos en wxFormBuilder Creamos un sizer horizontal, dentro del sizer principal del contenedor MyFrame2. Fijarse en la propiedad orient, que la hemos cambiado a wxHORIZONTAL. Eventos en wxFormBuilder Creamos 2 wx.Button dentro del nuevo sizer. Eventos en wxFormBuilder Vamos a cambiar la posición de los botones ACEPTAR y CANCELAR. Los vamos a justificar a la derecha. Para ello hay que desactivar la bandera wxEXPAND del sizer contenedor de los botones y activar la bandera wxALIGN_RIGHT. Eventos en wxFormBuilder Cambiamos los nombres a los botones y creamos los eventos de click en botones ACEPTAR y CANCELAR. En realidad es añadir los nombres de los manejadores de eventos que se lanzarán cuando se den los eventos pertinentes. Hay 2 maneras de crear el nombre del manejador de eventos: 1) Haciendo doble click sobre el evento, y genera de manera automática el nombre del manejador de eventos. 2) Insertando el nombre directamente junto al evento que queremos tratar. Eventos en wxFormBuilder Podemos ver el código Python que wxFormBuilder genera automáticamente: Eventos en wxFormBuilder Guardamos proyecto y generamos código Python en wxFormBuilder. Volvemos a Stani. Tal como se ha visto hay que hacer override de los manejadores de eventos para darle funcionalidad. Habrá que crear una clase Frame que herede de MyFrame2, y hacer override de los manejadores de eventos. Conclusiones... ● Conceptos vistos: – Proyecto wxFB. – Widgets contenedores Frame y Panel. – Posicionamiento con sizer wx.BoxSizer. – Eventos. – Herencia de widgets y override de manejadores de eventos. Interfaz 2 ● ● ● Vamos a crear un segundo proyecto, denominado gestion_datos, que generará el fichero Python gestion_datos_vista.py. Crearemos paneles como widgets contenedores, para ver la reusabilidad de los mismos. Veremos el uso del flag Proportion en un sizer. Interfaz 2 Se va a diseñar el frontend de una posible aplicación de gestión, con widgets avanzados, tales como NoteBook, Splitters ó Choices. Se verá el potencial de los sizers como algoritmos de posicionamiento de widgets. La aplicación consta de un único Frame y 3 paneles. Cada Frame contenedor de la aplicación será la instanciación del Frame generado por wxFB. Se practicará como pasar estructuras de datos a los componentes gráficos para que muestren información. Interfaz 2 Los conceptos de esta segunda interfaz son idénticos a la primera, a excepción que se verán nuevos widgets más complejos a la vez que útiles y sofisticados. El proyecto wxFB, wxFB así como el código Python para llamar a las clases de wxPython están en los ficheros adjuntos a este material. Menús en wxFormBuilder ● ● ● Como se puede observar en el Forms del Component Pallete, existen 5 componentes que se pueden instanciar sin necesidad de un contenedor padre, a saber, Panel, Frame, Dialog y los widgets de menús MenuBar y ToolBar. ToolBar Además en el Component Pallete está la pestaña Menu/Toolbar, Menu/Toolbar que contiene toda una colección de widgets para utilizar en menús. Un menú se puede crear: – Dentro de un Frame. – Como un contenedor, al estilo de Paneles ó Frames (es decir, se crea una clase en el código Python generado). Menús en wxFormBuilder Creamos un nuevo proyecto, llamado menus_wx, y el fichero Python a generar será menus_wx_vista.py. Menús en wxFormBuilder Diseño de un Frame con un sistema de menú integrado. Menús en wxFormBuilder Menús en wxFormBuilder Menús en wxFormBuilder Menús en wxFormBuilder La herramienta del Editor de menú da como resultado el Object Tree de widgets de menú. Menús en wxFormBuilder Podemos comprobar las opciones de elementos de menú tipo Radio (excluyentes). Menús en wxFormBuilder Y para las opciones de menú de tipo check. Eventos en menús Crear eventos de elementos de menú es trivial, tal como se ha visto anteriormente. Únicamente hay que seleccionar el item de menú deseado, e ir a Events (Objects Properties), para ingresar el nombre del manejador de eventos asociado al evento en cuestión, en este caso, OnMenuSelection. NOTA: Crear eventos OnMenuSelection para elementos de menú de Nuevo y Abrir (Archivo). Menús en wxFormBuilder En el código generado por wxFormBuilder encontramos los identificadores de los elementos de menú. Al crear un Tool dentro de un ToolBar hay que especificar el ID del elemento del menú creado, para enlazar el manejador de eventos. Menús en wxFormBuilder Creamos un ToolBar, y dentro de él, un widget Tool (todo esto seleccionado de la pestaña Menu/Toolbar del Component Pallete). Fijarse en el atributo id del widget Tool, que se ha cambiado por ID_ABRIR, de modo que cuando se haga click en él se lanzará el manejador de eventos asociado al elemento de menú Abrir. Además se ha creado un StatusBar, enlazando el atributo statusbar del widget Tool al mismo (automáticamente), con el texto “Abrir un documento”. Cuando se pase el ratón por encima del widget Tool aparecerá dicho texto en el widget StatusBar. Menús en wxFormBuilder Volvemos a Stani, y creamos el módulo menus_wx.py, con el siguiente contenido: Ejecutamos y vemos la solución esperada... Conclusiones... ● Hemos visto como crear menús en contenedores de tipo wx.Frame. – Menús. – Elementos de menús (normal, checked, radio). – Submenús. – Eventos en menús. – Barra de herramientas (ToolBar). – Elementos de la barra de herramientas (Tool). ● – Asociar eventos de Tool a elementos de menús. Llamar a las clases generadas por wxFormBuilder desde un editor, en este caso, Stani's Python Editor, y hacer override en algunos manejadores de eventos. Componente Custom Control en wxFB ● ● De lo que se trata es de generar código Python para un widget que todavía no está soportado en wxFormBuilder. Vamos a crear un nuevo proyecto, llamado cc_proyecto, que generará cc_proyecto_vista.py. Componente Custom Control en wxFB Para ver cómo funciona este widget vamos a crear un proyecto en wxFormBuilder, en donde insertaremos un widget LEDNumberCtrl, LEDNumberCtrl el cual no está soportado actualmente (en la versión 3.2) por wxFormBuilder. Componente Custom Control en wxFB Diseñamos un Frame que contendrá un Panel, Panel que a su vez contendrá un CustomControl. CustomControl NOTA: Darse cuenta que hemos renombrado todos los widgets, en especial el Custom Control, ahora LedControl. Componente Custom Control en wxFB Modificamos las propiedades del CustomControl LedControl: Para generar código Python de estas propiedades solamente nos interesan 2, a saber: name (el nombre del widget, que se utiliza para añadirlo al sizer) y construction (la llamada para instanciar la clase y crear el objeto cuyo nombre ha sido declarado en name, y que tiene que ser atributo de la clase). Por tanto vamos a darle a nuestro nuevo widget como name LedControl. Y el construction será: self.LedControl = wx.gizmo.LedNumberCtrl(self, -1). Darse cuenta que el LedControl tiene que ser atributo de la clase generada (es por ello lo del self). Componente Custom Control en wxFB Configuración final de las propiedades del LedControl: Custom Control en Stani Creamos el módulo cc_proyecto.py en Stani, con el siguiente código: Custom Control en Stani ¡CONSEGUIDO! Conclusiones sobre el taller de wxFB ● ● ● Se ha introducido a la herramienta de diseño de interfaces gráficas wxFormBuilder, en especial, para la generación de código Python a partir del framework wxPython. Se han visto los conceptos de widget, evento y sizer. Se ha probado la herencia de las clases generadas por wxFB y el override de métodos (manejadores de eventos). ● Se han diseñado menús de Frames. ● Se ha comprobado el widget Custom Control. Taller de wxFB – Caldum 2011 Universidad de Murcia Muchas gracias a todos. Antonio Mario Molina Saorín Ángel Luis García García