Publicado por Pablo Tilli a las la s23:58 . Etiquetas: Etiquetas:Python Introducción A la hora de crear una aplicación que posea una interface gráfica basada en wxPython, disponemos de los denominados widgets. Los widgets son un conjunto de controles, que tenemos a disposición nuestra para crear la interface de usuario. Ejemplos de widgets son las cajas de texto t exto y los botones, por citar solo dos. Obviamente, vamos a necesitar distribuir estos widgets de distintas formas, según las necesidades que tengamos en cada aplicación que desarrollemos. La organización de los widgets, la podemos hacer de forma estática o dinámica. Organización estática En la organización estática, la idea es especificar para cada uno de los widgets, una posición y un tamaño fijo. Teniendo en cuenta que una de las ventajas de utilizar wxPython, es que es multiplaforma, esta forma de organizar los widgets no nos resulta muy útil ... ¿Por que? ... simple ... veamos un ejemplo: imaginemos que creamos un botón con el texto “Aceptar” utilizando la fuente “Ms Sans Serif” de 10px, con un ancho de 70px y 35px d e alto, y estamos sobre una
plataforma Windows. Si ahora tomamos esta aplicación y la corremos sobre Ubuntu (por ejemplo), como podrán imaginar, ahora nuestro texto ya no se mues tra con la fuente “Ms Sans Serif” ya que
seguramente no estará disponible, por lo tanto sera reemplazada por algu na fuente parecida, por lo tanto es probable que ya nuestro texto “Ac eptar” no se vea como cuando lo veíamos en
Windows, y tal vez el texto no quepa en los 700px de ancho del botón, o en los 35px de alto y se vea incompleto. Otro inconveniente, es que cuando fijamos el tamaño y la posición de los widgets, lo hacemos para un tamaño de ventana concreto, y si la redimensionamos, la disposición de los controles seguirá estática, o sea: los controles no se adaptan al cambiar el tamaño de la ventana. Para salvar estos problemas, es que existe otra forma d e organizar los widgets, que es mucho mas flexible, y se denomina: organización dinámica. Organización dinámica A diferencia de lo que ocurre en la organización estática, aquí los widgets se organizan en base a proporciones. Con este método, no le diremos a los widgets su posición y tamaño en forma absoluta, sino que estas propiedades estarán determinadas por un algoritmo. Podríamos definir, por ejemplo, que una caja de texto s ea tan ancha como el ancho de la ventana, independientemente de si la ventana tiene tan solo 50px de ancho, o s i esta maximizada, y tampoco importa si corre sobre Ubuntu o Windows, o cualquier otra plataforma, ya que s e adaptara en forma automática. Para lograr este dinamismo, los widgets son organizados dentro de widgets especiales denominados Sizers. ¿Que son los Sizers?
Los sizers son un tipo especial de widget, que permiten contener a otros widgets en su interior. inte rior. Los sizers permiten a su vez contener a otros sizers, con lo cual nos permite crear interfaces muy elaboradas y donde el limite es nuestra imaginación. Existen 5 clases de sizers (y algunas variantes):
wx.GridSizer
wx.BoxSizer (Vertical y Horizontal)
wx.StaticBoxSizer (Vertical y Horizontal)
wx.FlexGridSizer
wx.GridBagSizer
Cada uno de estos Sizers, implementa un algoritmo de organización dinámica distinto, de modo tal, que según en cual de ellos ubiquemos nuestros widgets, sera como estos aparecerán dentro de nuestra interface. En el resto de este articulo, describiremos las características de c ada unos de ellos, y veremos algunos ejemplos de como combinarlos entre si. Antes de adentrarnos en las particularidades de cada uno de los Sizers, veremos como se muestra (por defecto) un mismo conjunto de widgets en cada uno de los distintos sizers. Un mismo conjunto de widgets ... una interface distinta A continuación podrán ver una serie de capturas de pantalla, con el fin de tener una idea inicial de como funciona cada uno de los sizers. En todos los sizers se encuentran los mismos widgets, y el orden en que se agregaron los widgets a cada sizer fue el siguiente:
stNombre (wxStaticText)
tcNombre (wxTextCtrl)
stApellido (wxStaticText)
tcApellido (wxTextCtrl)
Los widgets en un GridSize:
Los sizers son un tipo especial de widget, que permiten contener a otros widgets en su interior. inte rior. Los sizers permiten a su vez contener a otros sizers, con lo cual nos permite crear interfaces muy elaboradas y donde el limite es nuestra imaginación. Existen 5 clases de sizers (y algunas variantes):
wx.GridSizer
wx.BoxSizer (Vertical y Horizontal)
wx.StaticBoxSizer (Vertical y Horizontal)
wx.FlexGridSizer
wx.GridBagSizer
Cada uno de estos Sizers, implementa un algoritmo de organización dinámica distinto, de modo tal, que según en cual de ellos ubiquemos nuestros widgets, sera como estos aparecerán dentro de nuestra interface. En el resto de este articulo, describiremos las características de c ada unos de ellos, y veremos algunos ejemplos de como combinarlos entre si. Antes de adentrarnos en las particularidades de cada uno de los Sizers, veremos como se muestra (por defecto) un mismo conjunto de widgets en cada uno de los distintos sizers. Un mismo conjunto de widgets ... una interface distinta A continuación podrán ver una serie de capturas de pantalla, con el fin de tener una idea inicial de como funciona cada uno de los sizers. En todos los sizers se encuentran los mismos widgets, y el orden en que se agregaron los widgets a cada sizer fue el siguiente:
stNombre (wxStaticText)
tcNombre (wxTextCtrl)
stApellido (wxStaticText)
tcApellido (wxTextCtrl)
Los widgets en un GridSize:
Los widgets en un BoxSizer (Vertical):
Los widgets en un BoxSizer (Horizontal):
Los widgets en un StaticBoxSizer (Vertical):
Los widgets en un StaticBoxSizer (Horizontal):
Los widgets en un FlexGridSizer:
Los widgets en un GridBagSizer:
Como podemos apreciar en las capturas anteriores, se gún en que sizer agreguemos nuestros widgets, será la organización que obtendremos. Algunos pueden parecer muy parecidos (Por ejemplo: BoxSizer Vertical y StaticBoxSizer Vertical), otros parecen iguales (GridSizer y FlexGridSizer) e incluso podemos decir, que a simple vis ta, pareciera que el GridBagSizer (la ultima imagen) no tiene sentido!. En realidad todos tienen sus particularidades que lo hacen mas o menos adecuados dependiendo del tipo de interface que busquemos. Hasta aquí llegamos con esta primera parte. En otros posts, i remos viendo cuales son las características en común y cuales las particularidades de cada uno de los sizers, para así después comenzar a combinarlos y crear finalmente algunas interfaces de prueba con distinto grado de complejidad. Hasta la proxima! _______------------------------------------------------------____________________________________ Parte II
Etiquetas:Python Si has llegado aquí mediante un buscador o por simp le casualidad, te cuento que estas en la segunda parte de un tutorial que empieza AQUI.
Trabajando con los Sizers Todos los sizers tienen algunas características en común; y otras, que hacen que cada uno de ellos sea único. Podríamos ver una a una cuales son las similitudes y cuales las diferencias para luego pasar a la practica con cosas concretas, pero no quiero que tengas que leer un montón de teoría antes de poder ver algo de practica, es por esto
que iré intercalando la teoría y la practica de manera que el tutorial no se te haga muy tedioso. Creo que va a ser mas fácil partir de un sizer en particular (el GridSizer en este caso), y luego ir explicando en que se parecen y en que se diferencian a medida que vayamos avanzando con cada uno de los otros sizers. Hay distintos enfoques a la hora de trabajar con interfaces gráficas con Wxpython: 1- Escribir todo el código necesario para ir generando la interface gráfica; llamando a las funciones de wxPython que permiten crear los distintos widgets (botones, listas, etc.) desde la propia aplicación que estemos desarrollando. 2- Generar un archivo XML que describe la interface gráfica, y que luego podemos cargar desde la aplicación. 3- Utilizar un IDE para diseñar la interface gráfica. En este método, trabajamos de la misma manera que en método 2, excepto que es el propio IDE el que genera el archivo XML para que después lo carguemos desde nuestra aplicación. De los tres métodos, vamos a empezar por el tercero. El IDE que vamos a usar seráwxFormBuilder, pero existen otros como XRCed y wxGlade por nombrar sólo algunos mas. Este método es el mas práctico porque (al igual que en el segundo) logramos independizar la parte gráfica de la aplicación, del resto del código de la aplicación en sí. A diferencia del segundo método, es mucho mas fácil delegar la tarea de escribir el archivo XML en el IDE. Mas adelante veremos el primero y segundo metodo tambien. En mi caso trabajo sobre Ubuntu Intrepid Ibex (8.10), pero wxFormBuilder es un IDE multiplataforma. Por lo menos en el caso de l a mayoría de las distribuciones populares de Linux, ya viene en l os repositorios. Los usuarios de Windows y Mac los pueden descargar desde el sitio del proyecto. wxFormBuilder es libre y gratuito. A continuación te muestro una captura de pantalla para que te vayas familiarizando con el programa:
Una vez que tenemos wxFormBuilder instalado en nuestro sistema, ya estamos listos para empezar a trabajar. Antes de poder crear un Sizer, debemos generar algún tipo de formulario que lo contenga. Para este ejemplo crearemos un Frame como contenedor, el cual visualmente no es mas que una clásica ventana (con su borde, botones de cerrar, minimizar y maximizar, etc). Para esto vamos a la solapa “Forms” de la paleta de componentes de wxFormBuilder y pulsamos el botón "Frame". Veamos una imágen para que se entienda mejor:
Luego de pulsar el botón “Frame”, el resultado será el siguiente:
Ahora que tenemos creado
el Frame, ya podemos agregar nuestro Sizer, que como dije antes, será un GridSizer. Para logra esto, lo hacemos del mismo modo que agregamos el Frame, sólo que ahora vamos a la solapa “Layout” y pulsamos el botón “wxGridSizer”:
El resultado lo vemos en la siguiente captura:
En la imágen se muestran resalatadas 3 cosas importantes: 1- El panel izquierdo de wxFormBuilder ("Object Tree" ), nos muestra toda la interface en forma de árbol. En la imagen podemos apreciar que la raíz es el proyecto en si (Proyect1 en este caso), inmediatamente después se encuentra el Frame (llamado MyFrame2), y por último, dentro del Frame esta el GridSizer que acabamos de agregar (cuyo nombre es gSizer1). 2- Si miramos bien dentro del Frame que creamos, veremos que el GridSizer esta representado por un rectángulo rojo que ocupa todo el interior del Frame. 3- El panel derecho de wxFormBuilder ("Object Properties" ), nos muestra las propiedades del objeto que esta seleccionado actualmente en el Editor. Para ver como se comporta el GridSizer, iremos agregando algunos widgets dentro de éste. A modo de ejemplo, agregaremos cuatro botones. Esto realmente no tiene ninguna complejidad, ya que el modo de trabajo es el mismo que usamos hasta aquí. Ante todo, verificamos que esté seleccionado "gSizer1" en el "Object Tree" de wxFormBuilder; de modo que el IDE "sepa" que los botones irán dentro del GridSizer, luego vamos a la solapa “Common” y pulsamos el botón “wxButton”. Esto agregará el primer botón al GridSizer.
Tras pulsar el botón “wxButton” , el Editor quedará como se ve a continuación:
Como podemos apreciar el botón se creo en la esquina superior izquierda del GridSizer, ahora crearemos el segundo botón. Para esto sólo pulsamos nuevamente el botón “wxButton”, con lo cual el Editor ahora quedara así:
El segundo botón fue creado a la derecha del otro (pero con bastante espacio de por medio). Sólo nos falta crear los dos botones restantes. Si has llegado hasta acá, seguramente te imaginaras como hacerlo … claro, pulsas dos veces mas el
botón“wxbutton” (recuerda que debe estar seleccionado "gSizer1" en el "Object Tree"). El resultado final que debes ver en el Editor es el siguiente:
Como te habrás dado cuenta, los últimos dos botones se encuentran en una segunda fila (pero siempre alineados verticalmente con la primera). Tal vez todavía no te hayas dado cuenta (o tal vez si), pero la distribución que conseguimos tiene una lógica. Con la siguiente imagen tal vez lo veas mas claro:
Como muestra la imágen, y como el nombre del Sizer lo indica, un GridSizer no es mas que una grilla, donde en cada celda podemos ir agregando el widget que necesitemos. Hasta aquí hemos visto como agregar un Frame, un GridSizer y cuatro botones dentro de éste. Es importante que le vayas prestando atención al "Object Tree" de wxFormBuilder.
Este "árbol" nos da una clara visión de como se relacionan los distintos elementos de nuestra interface. Entender este “árbol” también te servirá mucho si en algún momento decides trabajar con el IDE XRCed (en otro tutorial l o veremos). Veamos un poco mas en detalle el GridSizer.
Grid Sizer (wx.Grid Sizer) Como ya hemos dicho, el GridSizer consiste en una grilla bidimensional, en la cual se organizan los distintos widgets que necesitemos. Gráficamente un GridSizer no es mas que una grilla, donde en cada celda podemos posicionar un widget. El primer widget que se agrega a un GridSizer se ubica en la esquina superior izquierda de la grilla; el resto se ubican de izquierda a derecha, y al llegar a la ultima columna de una fila, se continua en la primera columna de la fila inmediatamente inferior hasta llegar a la ultima celda de la grilla, que corresponde a la esquina inferior derecha de l a misma. Este comportamiento, lo habrás visto bien claro si fuiste haciendo el ejemplo de agregar cuatro botones dentro del GridSizer con wxFormBuilder; cada vez que pulsas el botón que agrega un wxButton, puedes observar donde se posiciona el botón dentro de la grilla. Si no hiciste el ejemplo, te invito a que lo hagas!. Al redimensionar un GridSizer, cada celda de este, agranda o disminuye su tamaño proporcionalmente, pero por defecto, los widgets contenidos en cada una de las celdas, mantienen su tamaño original, y quedan “anclados” a la esquina superior izquierda de la celda en la que se encuentran. Veamos una captura, donde vemos 2 veces una misma ventana, pero antes y después de ser redimensionada. La ventana contiene un GridSizer que tiene cuatro botones en su interior (el ejemplo que hicimos antes).
En la imagen, se puede apreciar como las cuatro celdas, crecen de manera idéntica, siendo en todo momento todas las celdas del mismo alto y ancho, pero como vemos los widgets no cambiaron su tamaño. Si bien todas las celdas tienen el mismo tamaño, no necesariamente el alto de las filas es igual al ancho de las columnas. Como hemos visto; al crear un GridSizer con wxFormBuilder, nuestra grilla es de 2 X 2 en forma predeterminada, pero obviamente tenemos una forma de cambiar esto. Entre las propiedades particulares del GridSizer se encuentran Rows y Cols, las cuales nos
permiten establecer la cantidad de filas y columnas respectivamente. Si lo deseamos, también podemos especificar que haya un espacio entre las distintas celdas; para esto contamos con la propiedad hgap para crear un espacio entre las filas, y vgap para lograr el espaciado entre las columnas. El v alor de vgap y hgap, es un numero entero que representa el espaciado en pixeles. En la imagen siguiente, vemos una una grilla de 3 X 2, con un espacio horizontal entre las celdas de 2px y un espaciado vertical entre celdas de 3px:
Para lograrlo, simplemente seleccionamos el GridSizer ("gSizer1") desde el “Object Tree” y luego establecemos los valores en el panel de propiedades (rows=2, cols=3, vgap=3 y hgap=2). Si bien dijimos que todas las celdas tienen el mismo tamaño, esto no quiere decir que todos los elementos que estén en cada una de ellas, también deban tener las mismas dimensiones ni tampoco la misma posición dentro la celda. Como dijimos antes, al agregar un elemento en un GridSizer, por defecto éste queda posicionado en la esquina superior izquierda de l a celda que le corresponda, y su tamaño NO se ve afectado al cambiar el tamaño del sizer. Este comportamiento puede ser modificado a través de los Flags. Los Flags entran dentro de las características comunes a todos los widgets que se encuentren contenidos en un Sizer. Para entender mejor de que hablamos, veremos cuales son los Flags y para que sirve cada uno de ellos.
Flags para establecer la alineación de los widgets Las opciones disponibles para alinear los widgets que agregamos a los Sizers s on las siguientes: wx.ALIGN_TOP: El widget es alineado en la parte superior de la celda en l a que se encuentre, si se omite, esta es la opcion por defecto. wx.ALIGN_BOTTOM: El widget se alinea en la parte inferior de la celda en la que es
insertado. wx.ALIGN_LEFT: El widget es alineado a la izquierda dentro la celda en la que se encuentre, si se omite, esta es la opcion por defecto. wx.ALIGN_RIGHT: El widget es alineado a la derecha dentro la celda en la que se encuentre. wx.ALIGN_CENTER_HORIZONTAL: El widget es centrado en forma horizontal. Se omite el valor de wx.ALIGN_LEFT y wx.ALIGN_RIGHT. wx.ALIGN_CENTER_VERTICAL: El widget es centrado en forma vertical. Se omite el valor de wx.ALIGN_TOP y wx.ALIGN_BOTTOM. wx.ALIGN_CENTER: El widget se alinea en la centro de la celda en la que es insertado. En este caso se omiten todas las opciones anteriores. wx.EXPAND: El widget toma el mismo tamaño que la celda en la que se encuentra. wx.FIXED_MINSIZE: El widget mantiene siempre su tamaño mínimo (Luego volveremos sobre este punto). wx.SHAPED: El widget cambiara su tamaño de forma proporcional, manteniendo su relación de aspecto (luego lo veremos con un ejemplo, para que se entienda mejor). wx.GROW: Funciona igual que wx.EXPAND.
Flags para establecer un borde (espacio) entre los widgets Además de poder cambiar la alineación de los widgets, tenemos la posibilidad de dejar un borde (espacio) entre el widget y la celda que lo contiene. Para establecer este valor, podemos combinar las siguientes opciones junto con las de alineación que vimos anteriormente: wx.TOP: Establece que el espacio especificado en la propiedad “border”, sea aplicado en la parte superior del widget. wx.LEFT: Establece que el espacio especificado en la propiedad “border”, sea aplicado a la izquierda del widget. wx.RIGHT: Establece que el espacio especificado en la propiedad “border”, sea aplicado a la derecha del widget.
wx.BOTTOM: Establece que el espacio especificado en la propiedad “border”, sea aplicado en la parte inferior del widget. wx.ALL: El espacio se establece a todos los lados del widget (Arriba, Izquierda, Derecha y Abajo). Es la suma de las cuatro opciones anteriores juntas. Luego veremos algunas imágenes donde se puedan apreciar los resultados de combinar estos valores de di stintas formas. Para que esta segunda parte no se haga mas larga, vamos a dejar aquí. En esta parte, hemos avanzado bastante, y cada vez estamos mas cerca de poder crear una i nterface mas “real” (léase útil). Repasando un poco, hasta aquí dijimos que existen tres métodos para trabajar con interfaces gráficas con wxPython, y que por ahora usaremos la alternativa del IDE. Estuvimos viendo como se trabaja con wxFormBuilder, hablamos de los Flags, y tenemos una idea mas clara de como funciona el GridSizer. Para dominar de forma fluida el diseño de interfaces gráficas con wxPython, se requiere mucha práctica. Al principio puede ser un poco desalentador, ya que cuesta mucho lograr lo que uno tiene en mente; y sobre todo si eres un desarrollador que viene de otros lenguajes (como Visual Basic, por ejemplo) donde la forma de trabajo es bastante distinta, pero con el tiempo te darás cuenta de las ventajas que tiene esta manera de hacer las cosas, y podras ir logrando lo que t e propones. Cualquier duda o sugerencia, puedes comentar. feliz 0212-8141893 Parete III
Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que estas en la segunda parte de un tutorial que empieza AQUI.
Trabajando con los Sizers Todos los sizers tienen algunas características en común; y otras, que hacen que cada uno de ellos sea único. Podríamos ver una a una cuales son las similitudes y cuales las diferencias para luego pasar a la practica con cosas concretas, pero no quiero que tengas que leer un montón de teoría antes de poder ver algo de practica, es por esto que iré intercalando la teoría y la practica de manera que el tutorial no se te haga muy
tedioso. Creo que va a ser mas fácil partir de un sizer en particular (el GridSizer en este caso), y luego ir explicando en que se parecen y en que se diferencian a medida que vayamos avanzando con cada uno de los otros sizers. Hay distintos enfoques a la hora de trabajar con interfaces g ráficas con Wxpython: 1- Escribir todo el código necesario para ir generando la interface gráfica; llamando a las funciones de wxPython que permiten crear los distintos widgets (botones, listas, etc.) desde la propia aplicación que estemos desarrollando. 2- Generar un archivo XML que describe la interface gráfica, y que luego podemos cargar desde la aplicación. 3- Utilizar un IDE para diseñar la interface gráfica. En este método, trabajamos de la misma manera que en método 2, excepto que es el propio IDE el que genera el archivo XML para que después lo carguemos desde nuestra aplicación. De los tres métodos, vamos a empezar por el tercero. El IDE que vamos a usar seráwxFormBuilder, pero existen otros como XRCed y wxGlade por nombrar sólo algunos mas. Este método es el mas práctico porque (al igual que en el segundo) logramos independizar la parte gráfica de la aplicación, del resto del código de la aplicación en sí. A diferencia del segundo método, es mucho mas fácil delegar la tarea de escribir el archivo XML en el IDE. Mas adelante veremos el primero y segundo metodo tambien. En mi caso trabajo sobre Ubuntu Intrepid Ibe x (8.10), pero wxFormBuilder es un IDE multiplataforma. Por lo menos en el caso de l a mayoría de las distribuciones populares de Linux, ya viene en l os repositorios. Los usuarios de Windows y Mac los pueden descargar desde el sitio del proyecto. wxFormBuilder es libre y gratuito. A continuación te muestro una captura de pantalla para que te vayas familiarizando con el programa:
Una vez que tenemos wxFormBuilder instalado en nuestro sistema, ya estamos listos para empezar a trabajar. Antes de poder crear un Sizer, debemos generar algún tipo de formulario que lo contenga. Para este ejemplo crearemos un Frame como contenedor, el cual visualmente no es mas que una clásica ventana (con su borde, botones de cerrar, minimizar y maximizar, etc). Para esto vamos a la solapa “Forms” de la paleta de componentes de wxFormBuilder y pulsamos el botón "Frame". Veamos una imágen para que se entienda mejor:
Luego de pulsar el botón “Frame”, el resultado será el siguiente:
Ahora que tenemos creado el Frame, ya podemos agregar nuestro Sizer, que como dije antes, será un GridSizer. Para logra esto, lo hacemos del mismo modo que agregamos el Frame, sólo que ahora vamos a la solapa “Layout” y pulsamos el botón “wxGridSizer”:
El resultado lo vemos en la siguiente captura:
En la imágen se muestran resalatadas 3 cosas importantes: 1- El panel izquierdo de wxFormBuilder ("Object Tree" ), nos muestra toda la interface en forma de árbol. En la imagen podemos apreciar que la raíz es el proyecto en si (Proyect1 en este caso), inmediatamente después se encuentra el Frame (llamado MyFrame2), y por último, dentro del Frame esta el GridSizer que acabamos de agregar (cuyo nombre es gSizer1). 2- Si miramos bien dentro del Frame que creamos, veremos que el GridSizer esta representado por un rectángulo rojo que ocupa todo el interior del Frame. 3- El panel derecho de wxFormBuilder ("Object Properties" ), nos muestra las propiedades del objeto que esta seleccionado actualmente en el Editor. Para ver como se comporta el GridSizer, iremos agregando algunos widgets dentro de éste. A modo de ejemplo, agregaremos cuatro botones. Esto realmente no tiene ninguna complejidad, ya que el modo de trabajo es el mismo que usamos hasta aquí. Ante todo, verificamos que esté seleccionado "gSizer1" en el "Object Tree" de wxFormBuilder; de modo que el IDE "sepa" que l os botones irán dentro del GridSizer, luego vamos a la solapa “Common” y pulsamos el botón “wxButton”. Esto agregará el primer botón al GridSizer.
Tras pulsar el botón “wxButton” , el Editor quedará como se ve a continuación:
Como podemos apreciar el botón se creo en la esquina superior izquierda del GridSizer, ahora crearemos el segundo botón. Para esto sólo pulsamos nuevamente el botón “wxButton”, con lo cual el Editor ahora quedara así:
El segundo botón fue creado a la derecha del otro (pero con bastante espacio de por medio). Sólo nos falta crear los dos botones restantes. Si has llegado hasta acá, seguramente te imaginaras como hacerlo … claro, pulsas dos veces mas el botón“wxbutton” (recuerda que debe estar seleccionado "gSizer1" en el "Object Tree"). El resultado final que debes ver en el Editor es el siguiente:
Como te habrás dado cuenta, los últimos dos botones se encuentran en una segunda fila (pero siempre alineados verticalmente con la primera). Tal vez todavía no te hayas dado cuenta (o tal vez si), pero la distribución que conseguimos tiene una lógica. Con la siguiente imagen tal vez lo veas mas claro:
Como muestra la imágen, y como el nombre del Sizer lo indica, un GridSizer no es mas que una grilla, donde en cada celda podemos ir agregando el widget que necesitemos. Hasta aquí hemos visto como agregar un Frame, un GridSizer y cuatro botones dentro de éste. Es importante que le vayas prestando atención al "Object Tree" de wxFormBuilder. Este "árbol" nos da una clara visión de como se relacionan los distintos elementos de nuestra interface. Entender este “árbol” también te servirá mucho si en algún momento decides trabajar con el IDE XRCed (en otro tutorial lo veremos).
Veamos un poco mas en detalle el GridSizer.
Grid Sizer (wx.Grid Sizer) Como ya hemos dicho, el GridSizer consiste en una grilla bidimensional, en la cual se organizan los distintos widgets que necesitemos. Gráficamente un GridSizer no es mas que una grilla, donde en cada celda podemos posicionar un widget. El primer widget que se agrega a un GridSizer se ubica en la esquina superior izquierda de la grilla; el resto se ubican de izquierda a derecha, y al llegar a la ultima columna de una fila, se continua en la primera columna de la fila inmediatamente inferior hasta llegar a la ultima celda de la grilla, que corresponde a la esquina inferior derecha de l a misma. Este comportamiento, lo habrás visto bien claro si fui ste haciendo el ejemplo de agregar cuatro botones dentro del GridSizer con wxFormBuilder; cada vez que pulsas el botón que agrega un wxButton, puedes observar donde se posiciona el botón dentro de la grilla. Si no hiciste el ejemplo, te invito a que lo hagas!. Al redimensionar un GridSizer, cada celda de este, agranda o disminuye su tamaño proporcionalmente, pero por defecto, los widgets contenidos en cada una de las celdas, mantienen su tamaño original, y quedan “anclados” a la esquina superior izquie rda de la celda en la que se encuentran. Veamos una captura, donde vemos 2 veces una misma ventana, pero antes y después de ser redimensionada. La ventana contiene un GridSizer que tiene cuatro botones en su interior (el ejemplo que hicimos antes).
En la imagen, se puede apreciar como las cuatro celdas, crecen de manera idéntica, siendo en todo momento todas las celdas del mismo alto y ancho, pero como vemos los widgets no cambiaron su tamaño. Si bien todas las celdas tienen el mismo tamaño, no necesariamente el alto de las filas es igual al ancho de las columnas. Como hemos visto; al crear un GridSizer con wxFormBuilder, nuestra grilla es de 2 X 2 en forma predeterminada, pero obviamente tenemos una forma de cambiar esto. Entre las propiedades particulares del GridSizer se encuentran Rows y Cols, las cuales nos permiten establecer la cantidad de filas y columnas respectivamente. Si lo deseamos, también podemos especificar que haya un espacio entre las distintas celdas; para esto contamos con la propiedad hgap para crear un espacio entre las filas, y vgap para lograr el espaciado entre las columnas. El valor de vgap y hgap, es un numero entero que representa el espaciado en pixeles. En la imagen siguiente, vemos una una grilla
de 3 X 2, con un espacio horizontal entre las celdas de 2px y un espaciado vertical entre celdas de 3px:
Para lograrlo, simplemente seleccionamos el GridSizer ("gSizer1") desde el “Object Tree” y luego establecemos los valores en el panel de propiedades (rows=2, cols=3, vgap=3 y hgap=2). Si bien dijimos que todas las celdas tienen el mismo tamaño, esto no quiere decir que todos los elementos que estén en cada una de ellas, también deban tener las mismas dimensiones ni tampoco la misma posición dentro la celda. Como dijimos antes, al agregar un elemento en un GridSizer, por defecto éste queda posicionado en la esquina superior izquierda de la celda que le corresponda, y su tamaño NO se ve afectado al cambiar el tamaño del sizer. Este comportamiento puede ser modificado a través de los Flags. Los Flags entran dentro de las características comunes a todos los widgets que se encuentren contenidos en un Sizer. Para entender mejor de que hablamos, veremos cuales son los Flags y para que sirve cada uno de ellos.
Flags para establecer la alineación de los widgets Las opciones disponibles para alinear los widgets que agregamos a los Sizers son las siguientes: wx.ALIGN_TOP: El widget es alineado en la parte superior de la celda en l a que se encuentre, si se omite, esta es la opcion por defecto. wx.ALIGN_BOTTOM: El widget se alinea en la parte inferior de la celda en la que es insertado. wx.ALIGN_LEFT: El widget es alineado a la izquierda dentro la celda en la que se
encuentre, si se omite, esta es la opcion por defecto. wx.ALIGN_RIGHT: El widget es alineado a la derecha dentro la celda en la que se encuentre. wx.ALIGN_CENTER_HORIZONTAL: El widget es centrado en forma horizontal. Se omite el valor de wx.ALIGN_LEFT y wx.ALIGN_RIGHT. wx.ALIGN_CENTER_VERTICAL: El widget es centrado en forma vertical. Se omite el valor de wx.ALIGN_TOP y wx.ALIGN_BOTTOM. wx.ALIGN_CENTER: El widget se alinea en la centro de la celda en la que es insertado. En este caso se omiten todas las opciones anteriores. wx.EXPAND: El widget toma el mismo tamaño que la celda en la que se encuentra. wx.FIXED_MINSIZE: El widget mantiene siempre su tamaño mínimo (Luego volveremos sobre este punto). wx.SHAPED: El widget cambiara su tamaño de forma proporcional, manteniendo su relación de aspecto (luego lo veremos con un ejempl o, para que se entienda mejor). wx.GROW: Funciona igual que wx.EXPAND.
Flags para establecer un borde (espacio) entre los widgets Además de poder cambiar la alineación de los widgets, tenemos la posibilidad de dejar un borde (espacio) entre el widget y la celda que lo contiene. Para establecer este valor, podemos combinar las siguientes opciones junto con las de alineación que vimos anteriormente: wx.TOP: Establece que el espacio especificado en la propiedad “border”, sea aplicado en la parte superior del widget. wx.LEFT: Establece que el espacio especificado en la propiedad “border”, sea aplicado a la izquierda del widget. wx.RIGHT: Establece que el espacio especificado en la propiedad “border”, sea aplicado a la derecha del widget. wx.BOTTOM: Establece que el espacio especificado en la propiedad “border”, sea aplicado en la parte inferior del widget.
wx.ALL: El espacio se establece a todos los lados del widget (Arriba, Izquierda, Derecha y Abajo). Es la suma de las cuatro opciones anteriores juntas. Luego veremos algunas imágenes donde se puedan apreciar los resultados de combinar estos valores de distintas formas. Para que esta segunda parte no se haga mas larga, vamos a dejar aquí. En esta parte, hemos avanzado bastante, y cada vez estamos mas cerca de poder crear una interface mas “real” (léase útil). Repasando un poco, hasta aquí dijimos que existen tres métodos para trabajar con interfaces gráficas con wxPython, y que por ahora usaremos la alternativa del IDE. Estuvimos viendo como se trabaja con wxFormBuilder, hablamos de los Flags, y tenemos una idea mas clara de como funciona el GridSizer. Para dominar de forma fluida el diseño de interfaces gráficas con wxPython, se requiere mucha práctica. Al principio puede ser un poco desalentador, ya que cuesta mucho lograr lo que uno tiene en mente; y sobre todo si eres un desarrollador que viene de otros lenguajes (como Visual Basic, por ejemplo) donde la forma de trabajo es bastante distinta, pero con el tiempo te darás cuenta de las ventajas que tiene esta manera de hacer las cosas, y podras ir logrando lo que t e propones. Parete III
... continuando con los Flags En la segunda parte de este tutorial, les había prometido continuar con el tema de los Flags, y esto es lo que trataremos justamente ahora. El primer caso que veremos, será sobre el Flag de alineación wx.ALIGN_CENTER :
En la imagen podemos apreciar el Editor (Arriba) y el panel de propiedades (Abajo) de wxFormBuilder. En el Editor dibuje una grilla de color rojo, para que tengas de referencia el tamaño de cada celda. Como ya habíamos dicho, en un G ridSizer todas las celdas son iguales, y de echo esto lo puedes apreciar en la imagen, pero como puedes ver, en la primera celda (Fila 0, Col. 0) el widget se encuentra con una alineación distinta a la del resto. Para lograr esto, en el Editor debes seleccionar el widget con el que quieres trabajar, y luego en el panel de propiedades desplegar la sección Flags (lo puedes ver en la parte de abajo de la imagen), y activar la opción wxALIGN_CENTER . En la captura de pantalla, se pueden ver desplegados todos los Flags. Si quisiéramos cambiar alguno de ellos, simplemente la activamos o desactivamos desde el checkbox que tienen a la derecha. En el siguiente ejemplo vamos a combinar algunos de ellos:
En este ejemplo vemos que cada una de los widgets posee una alineación distinta. Las opciones aplicadas en cada caso son las siguientes: 1- wx.ALIGN_CENTER 2- wx.ALIGN_BOTTOM + wx.ALIGN_RIGHT 3- wx.ALIGN_CENTER_VERTICAL 4- wx.ALIGN_CENTER_HORIZONTAL + wx.ALIGN_CENTER_BOTTOM 5- wx.ALIGN_CENTER_VERTICAL + wx.ALIGN_RIGHT 6- wx.ALIGN_BOTTOM Si miras con detenimiento en la imagen, te puedes dar cuenta que los widgets nunca llegan hasta el borde de las “celdas virtuales” (que por claridad, yo las dibuje en rojo). Esto se debe a que el valor de la propiedad “border” esta en 5, y esta aplicado a los cuatro lados de los widgets (wx.ALL). En el ejemplo siguiente, variaremos los bordes (además de la alineación):
Las opciones de cada widget de la imagen son los siguientes:
1- border=0 + wx.ALIGN_RIGHT + wx.ALL 2- border=30 + wx.ALIGN_RIGHT + wx.RIGHT 3- border=40 + wx.LEFT + wx.TOP 4- border=30 + wx.ALIGN_LEFT Ahora veremos un ejemplo donde usaremos los Flags wx.EXPAND, wx.SHAPED ywx.GROW.
Los Flags utilizados en cada widget de l a imagen, son los siguientes: 1- border=0 + wx.ALL + wx.EXPAND 2- border=5 + wx.ALL + wx.SHAPED 3- border=20 + wx.ALL + wx.EXPAND 4- No hay widget en esta celda. Si bien en las celdas 1 y 3 estamos usando el Flag wx.EXPAND, y por lo tanto los widgets deben ocupar la totalidad del espacio de l a celda en la que estén, pareciera que en la celda 3 no se cumple, pero en realidad si. La diferencia entre las dos celdas, es que la primera tiene un borde de 0px en todos sus lados, y la celda 3 tiene un borde de 20px en todos sus lados, por lo que puedes deducir que con el Flag wx.EXPAND, el widget se expande, pero contempla los bordes especificados en la propiedad “border” . En el caso de la celda 2, es difícil entender como funciona el Flag wx.SHAPED, así que te voy a mostrar dos imágenes donde se encuentra la misma ventana, pero en dos tamaños distintos:
En estas ultimas 2 capturas, vemos que la celda 2, al utilizar el Flag wx.SHAPED wx.SHAPED,, hace que al agrandarse o achicarse la ventana, el widget lo haga también en forma proporcional. Para que lo veas aun mejor, aislé el botón de la celda 2, de las dos imágenes y aquí los tienes uno debajo del otro:
En este punto seria bueno que experimentes tu mismo combinando los distintos Flags que hemos visto. El Flag wx.GROW wx.GROW no no se encuentra disponible en wxFormsBu wxFormsBuilder, ilder, y esto es así porque en realidad (como dijimos antes) es lo mismo que wx.EXPAND wx.EXPAND.. Por ahora llegaremos hasta aquí. A partir de la próxima parte del tutorial, seguiremos viendo el resto de los l os Sizers. Si bien esta parte no fue muy extensa, era necesaria para que podamos continuar. Recuerda que puedes dejar tus t us dudas, sugerencias, experiencias o lo que quieras para que todos podamos aprender de ti también. t ambién. Parte IV
Organización de widgets en wxPython (Parte IV) Como ya les había anticipado, en esta oportunidad seguiremos hablando de Sizers. Hasta ahora sólo hemos visto el GridSizer. En esta oportunidad veremos el BoxSizer (Vertical y Horizontal).
BoxSizer (Vertical y Horizontal) El BoxSizer es uno de los l os Sizers más simples (y mas usados). La verdadera potencia de este Sizer, se basa en la l a posibilidad de agregar un BoxSizer dentro de otro BoxSizer.
Este tipo de Sizer, se puede imaginar como una simple fila donde los widgets se ubican uno al lado del otro (en el caso del BoxSizer Horizontal), o como una columna donde los widgets se ubican uno debajo del otro (en el caso del BoxSizer Vertical).
BoxSizer Horizontal
BoxSizer Vertical
En las dos imágenes de arriba, se ven las l as dos variantes de un BoxSizer. En realidad, el BoxSizer Vertical y Horizontal son el mismo Sizer, pero tiene una propiedad que define su orientación. Al igual que en el GridSizer, en cada celda del BoxSizer, solo podemos ubicar un solo Widget. Como ya lo había hecho con el GridSizer, en las imágenes les remarque en color rojo, lo que serían las “celdas virtuales” donde se ubican los Widgets. En este caso, no podemos especificar la cantidad de fil as o columnas como hacíamos en el GridSizer; sino que aquí se van creando en forma automática cada vez que agregamos un Widget al BoxSizer. Si agregamos un Widget, y el BoxSizer es Horizontal, este se agrega a la derecha de los Widgets que ya existan en el Sizer; y si el BoxSizer es Vertical, el Widget se agregará abajo de todos los que se encuentren ya contenidos en el Sizer.
Crear un BoxSizer con wxFormBuilder, es tan simple como crear el GridSizer. Si estas siguiendo las distintas partes de este tutorial, ya casi sabes como hacerlo. De todos modos, lo veremos rápidamente en 3 pasos: 1- Creamos un Frame:
Veremos en el Editor, que el Frame se ha creado :
2- Hacemos click en la solapa "Layout", y luego clickeamos el botón correspondiente para la creación del BoxSizer:
3- Ahora agregamos algunos botones, del mismo modo que lo hicimos antes con el GridSizer. Para esto íbamos a la solapa "Common", y pulsabamos el botón para agregar un "wx.button" al Sizer:
Con estos pasos, ya tenemos el BoxSizer dentro de un Frame, con algunos botones
(wx.button) adentro. Cuando creamos el BoxSizer con wxFormBuilder, la orientación por defecto será “Vertical” (wx.VERTICAL); por lo tanto cada vez que pulses el botón para crear un “wx.button” (o cualquier otro widget), cada uno de estos se ubicará uno debajo de otro:
Si quisieramos que la orientacion sea Horizontal (wx.HORIZONTAL), seleccionamos el BoxSizer en el “Object Tree” (bSizer1), y luego en el panel de propiedades, elegimos la opción wx.HORIZONTAL en la lista desplegable de la propiedad Orient.
El Editor con el BoxSizer (Horizontal) se veria asi:
ACLARACION: Los numeros (1, 2, 3, 4) que vez en las imágenes, fueron agregados por mi, para representar en que orden fueron apareciendo los botones a medida que eran añadidos al Sizer. Al redimensionar un BoxSizer, este toma el tamaño total disponible de su contenedor (del Frame en este caso), pero los widgets contenidos en cada una de las celdas, mantienen su tamaño original, y quedan “anclados” a la esquina superior izquierda de la celda en la que se encuentran, tal como sucedía con el GridSizer. Por suerte, aquí también podemos “jugar” con los Flags, y asi l ograr adaptar la interface a nuestra necesidad. El modo de trabajo es exactamente igual que antes, elegimos el widget en cuestion y editamos sus Flags en el panel de propiedades, veamos un ejemplo de lo que podemos lograr:
Las opciones aplicadas a cada widget que ves en la i magen son las siguientes: 1- border=0 + wx.ALL 2- border=5 + wx.ALL + wx.ALIGN_CENTER_VERTICAL 3- border=5 + wx.ALL + wx.EXPAND 4- border=30 + wx.BOTTOM + wx.ALIGN_BOTTOM 5- border=20 + wx.ALL + wx.EXPAND Este mismo ejemplo, pero en su versión “Vertical”, quedaría así:
Una propiedad muy importante en este tipo de Sizer es la llamada “Proportion”. Esta característica, nos permite determinar que hacer cuando al agregar un Widget al Sizer, nos queda “espacio en blanco” dentro de este. Como base para explicar este concepto (y como ya es costumbre) veamos una imagen:
Como ya hemos dicho antes, al agregar el BoxSizer dentro del Frame, el BoxSizer ocupa la totalidad del espacio del Frame. Como se ve en la imagen, puede ser que al agregar algunos widgets al BoxSizer, estos no ocupen el 100% del espacio disponible. En el ejemplo de la imagen anterior, vemos que al agregar sólo 3 botones, nos queda mucho espacio libre. En algunas circunstancias puede ser que es lo que queramos, pero también podría darse el caso en que deseamos otro comportamiento.
Por dar un ejemplo, podríamos querer que el último botón ocupe el total del espacio libre. Para este tipo de situaciones, tenemos la propiedad “Proportion”. Esta propiedad esta definida mediante un valor entero, que por defecto es “0”. Si la dejamos en "0", los widgets tomarán su tamaño por defecto. Si establecemos la propiedad “Proportion” de un solo widget en “1”, este ocupara el 100% del espacio disponible que quede dentro del sizer. Si establecemos la propiedad “proportion” de dos widget en “1” dentro del mismo BoxSizer, significa que cada uno ocupara el 50% de lugar libre, y asi podemos ir combinando distintos valores, por ej: un widget en “1”, otro en “2”, otro en “3”, etc.. En definitiva, esta propiedad especifica como se distribuye el espacio libre del Sizer. Cuanto mayor sea el valor de la propiedad “proportion” de un widget, mas espacio ocupara este. Veamos el caso en que el ultimo botón ocupe el total del espacio libre:
Para lograr el comportamiento que ves en la imagen, tienes dos maneras. 1- Seleccionar el último botón en el Editor de wxFormBuilder, ir al panel de propiedades, y establecer el valor de Proportion en “1”.
2- Seleccionar el último botón en el Editor de wxFormBuilder y pulsar el botón “Strech” de la barra de herramientas (o pulsar ALT + S):
Al pulsar el boton “Strech”, lo unico que hace el IDE , es poner el valor “1” en l a propiedad Proportion por nosotros. Si sobre este mismo ejemplo, establecemos también la propiedad “Proportion” del segundo botón a “1”, el espacio libre se repartiría dando un 50% a cada widget. El ejemplo se vería así:
Si también establecemos la propiedad“Proportion” del primer botón a "1", el espacio libre quedaría dividido equitativamente, dándole a cada uno de los widgets, la misma cantidad de espacio. En este caso, cada botón tendrá un 1/3 del espacio total del sizer:
Veamos un ejemplo donde el primer botón tenga la propiedad “Proportion” en “0”, el segundo en “1” y el tercero en “2”. Se veria asi:
En esta imagen se puede apreciar que el primer botón (proportion="0") tiene su tamaño por defecto, el segundo botón (proportion="1") ocupa 1/3 del espacio libre que quedaria en el Sizer y el tercer botón
(proportion="3") ocupa 2/3 del espacio libre. Esta propiedad suele ser un tanto difícil de entender al principio, pero realmente no es tan compleja como parece. Sólo es cuestión de hacer unas cuantas pruebas, para ir viendo que resultado se obtienen al variar su valor. En las ultimas imágenes, siempre vimos BoxSizer's verticales, pero lo dicho vale también si la orientación es horizontal:
En esta imagen vemos un BoxSizer con orientación Horizontal. Los dos pri meros botones tienen su propiedad “Proportion” establecida en “0”, y el último en “1”; es por eso que el ultimo botón ocupa todo el espacio que quedaría libre dentro del Sizer. IMPORTANTE: Una diferencia importante, referida al espacio libre en un BoxSizer, es que si este tiene una orientacion Vertical, el espacio libre se encuentra abajo de todo, y si la orientacion es Horizontal, el espacio libre se encuentra a la derecha.
Entendiendo mejor wxEXPAND y Proportion Es muy importante entender como funcionan estas dos caracteristicas dependiendo de si el BoxSizer es Vertical u Horizontal. Si el BoxSizer es VERTICAL: 1- El Flag wx.EXPAND expande el widget para que ocupe el ancho total del Sizer, pero no afecta la altura del widget: En la imagen el primer botón tiene “proportion” en “0” y NO esta activo el Flag wx.EXPAND. El segundo botón también tiene “proportion” en “0”, pero SI tiene activado el Flag wx.EXPAND. Se puede observar claramente que el segundo botón se expandió a lo ancho, pero el alto esta igual que en el primer botón.
2- La propiedad “Proportion” modifica al widget en su altura, pero no afecta la el ancho del widget:
En esta imagen, el primer botón tiene “proportion” en “0” y NO esta activo el Flag wx.EXPAND. El segundo botón tiene “proportion” en “1”, y tampoco tiene activado el Flag wx.EXPAND. Se puede ver que el segundo botón se expandió a lo alto, pero el ancho es el mismo que en el primer botón. 3- Si activamos wx.EXPAND y establecemos el valor de la propiedad Proportion en un valor distinto de “0”, logramos que el widget crezca en ambos sentidos (Alto y ancho):
Podemos ver en la imagen, que al combinar las 2 opciones, el botón ocupa la totalidad del espacio libre. En realidad, lo que esta sucediendo, es que al activar el Flag wx.EXPAND, el widget se expande hasta ocupar todo el ancho, y luego, al establecer la propiedad “Proportion” a “1”, el widget crece hasta ocupar t odo el alto. Si el BoxSizer es HORIZONTAL: Si la orientación del BoxSizer es Horizontal, todo se i nvierte. Veamos los 3 casos anteriores, pero con un BoxSizer Horizontal: 1- El Flag wx.EXPAND expande el widget para que ocupe el alto total del BoxSizer, pero no afecta al ancho del widget:
En la imagen, el primer botón tiene la propiedad “proportion” en “0” y NO esta activado el Flag wx.EXPAND. El segundo botón también tiene “proportion” en “0”, pero SI tiene activado el Flag wx.EXPAND. Se puede observar claramente que el segundo botón se expandió en el alto, pero su ancho esta igual que en el primer botón. 2- La propiedad Proportion modifica al widget en su ancho, pero no afecta el alto del widget:
3- Si activamos el Flag wx.EXPAND, y establecemos el valor de la propiedad Proportion en un valor distinto de “0”, logramos que el widget crezca en ambos sentidos (Alto y ancho):
En la imagen podemos ver que combinando las 2 opciones, el botón ocupa la totalidad del espacio libre del Sizer. En realidad, lo que esta sucediendo, es que al activar el Flag wx.EXPAND, el widget se expande hasta ocupar todo el alto, y luego, al establecer la propiedad “Proportion” a “1”, el widget crece hasta ocupar todo el alto. Por el momento, dejaremos aquí, pero hemos visto bastante acerca del BoxSizer en su version Horizontal y Vertical. Hablamos de sus caracteristicas y como crearlos en wxFormBuilder. Hablamos tambien sobre la propiedad “Proportion” y seguimos utilizando los Flags que habiamos visto antes. Creo que hemos avanzado bastante, asi que te invito nuevamente a practicar de modo que vayas manejando con fluidez los conceptos vistos (Flags, Proportion, GridSizer, BoxSizer, etc.), y te sientas comodo utilizando wxFormBuilder. En la proxima entrega, vamos a ver una variación del BoxSizer: el StaticBoxSizer y hablaremos tambien del FlexGridSizer. Paret V
Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que estas en la quinta parte de un tutorial que empieza AQUI . En esta oportunidad hablaremos de dos Sizers: el StaticBoxSizer y el FlexGridSizer. Si ya entendiste el BoxSizer, el StaticBoxSizer no te traerá ningún problema, ya que son prácticamente iguales; y el FlexGridSizer es como el G ridSizer, pero con algunas novedades que lo hacen mas flexible (de ahí su nombre). El StaticBoxSizer El StaticBoxSizer deriva del BoxSizer que ya hemos visto en la entrega anterior. Todo lo visto para el BoxSizer, vale para el StaticBoxSizer, es decir, tiene una versión Vertical y otra Horizontal, utiliza la propiedad Proportion para determinar que hacer con el espacio libre, etc.. La diferencia radica en que el StaticBoxSizer muestra un borde que delimita el área correspondiente al Sizer, y l e podemos poner una etiqueta para informar de que se trata este área. Creo que en este caso, no hay duda que una imagen vale mas que mil palabras:
En la imágen puedes ver el recuadro del que te hablaba, y la etiqueta en la parte superior izquierda con el texto “Ejemplo de StaticBoxSizer”. Para crear este tipo de Sizer, procedemos del mismo modo que con el BoxSizer, excepto que pulsamos el botón “wxStaticBoxSizer” en la solapa “Layout” del panel de componentes de wxFormBuilder.
Por último, decirles que para cambiar la etiqueta que se muestra en el recuadro del StaticBoxSizer, debemos escribir lo que queremos en la propiedad “label”:
Como ves, este Sizer no presenta ninguna complicación si ya entendiste el BoxSizer. Ahora hablaremos del FlexGridSizer.
El FlexGridsizer El FlexGridSizer es una variación del GridSizer que ya hemos visto. Al igual que el GridSizer, podemos pensar el FlexGridSizer como una grilla, donde en cada celda podemos ubicar un widget. En el caso del GridSizer, vimos que todas las celdas tenían el mismo tamaño, siendo que el ancho de las columnas estaba determinado por el widget mas ancho que existiera en cualquier columna, y el alto de las filas era igual al widget mas alto que hubiera dentro del Sizer. A diferencia del GridSizer, el FlexGridSizer nos permite tener filas y columnas de distinto tamaño, y en esto radica la flexibilidad de la que nos habla el nombre del Sizer. Si bien cada fila y cada columna pueden tener tamaños distintos, todas las celdas de una misma fi la deben tener un mismo alto, y todas las celdas de una misma columna deben tener un mismo ancho. Veamos una imagen de ejemplo con un FlexGridSizer:
En esta imagen se puede apreciar lo que te decía en el párrafo anterior. Si te fijas bien, puedes ver qu e la primera fila tiene un alto distinto al de la segunda, y que la segunda columna tiene un ancho distinto al de la primera y la tercera. Pero como te decía antes, puedes ver que todas las celdas de cada fila son del mismo alto y las celdas de cada columna son del mismo ancho. Esta distribución, no lo hubiéramos podido lograr con el GridSizer “tradicional”. Veamos como crear el ejemplo de la imagen con wxFormBuilder. Esta vez, voy a obviar el paso de crear el Frame y agregar los botones al Sizer, ya que a sumo que si has llegado hasta aquí, y vienes siguiendo el tutorial desde el principio, ya sabes como
hacerlo. Para crear el FlexGridSizer, vamos a la solapa "Layout" y pulsamos el botón “wxFlexGridSizer”:
Con esto ya tenemos el FlexGridSizer creado. Ahora le agregamos 6 botones y el resultado que deberías ver en el Editor de wxFormBuilder es el siguiente:
En la imagen podemos ver que si bien el FlexGridSizer ocupa todo el área del Frame, las filas y las columnas no crecen mas allá del alto y el ancho por defecto de los widgets que tienen en su interior. Recuerda que si esto fuera una GridSizer, las celdas si hubieran crecido hasta ocupar el 100% del espacio del Sizer. Como dije antes, la idea es crear el ejemplo de la imagen que vimos al principio. Para ir aproximándonos un poco mas, debemos cambiar la cantidad de columnas de “2” a “3”, y así lograr dos filas de tres botones cada una. Esto lo hacemos del mismo modo que lo hacíamos con el GridSizer, por lo que sólo editamos los valores de l as propiedades “Rows” y “Cols”:
Para lograr que las filas y las columnas "crezcan", tenemos las propiedades growablesrowsy growablescols respectivamente. Aquí es importante aclarar que los índices de las filas y las columnas comienzan desde cero, es decir que la primera celda se encuentra en la fila 0 de la columna 0. En el ejemplo que estamos creando, la columna que crece es la “1” (la del medio) y la fila que crece es la “0” (la primera). Es por esto, que el valor degrowablesrows será “0” y el de growablescols sera “1”:
En este momento el Editor se vería así:
Una vez mas, les remarque en rojo las celdas “virtuales” para mayor claridad. Aquí pueden ver como realmente la fila 0 ha crecido y la columna 1 también. Lo único que nos queda para terminar el ejemplo es que el botón de la fila 0 de la columna 1, ocupe todo el espacio de esta, y lo mismo para el botón de la fila 0 de la columna 2. Para lograr esto, activamos el Flag wxEXPAND de estos dos widgets, y listo:
En este ejemplo solo hicimos que crezcan la fila 0 y la columna 1, pero podríamos necesitar hacerlo con mas filas y/o columnas al mismo tiempo. Para esto puedes escribir en las propiedades growablesrows y growablescols según corresponda, los índices de las filas o las columnas separados por coma (,). Si quisiéramos que en el ejemplo también crezca la fila 1 y la columna 2, haríamos lo siguiente:
El resultado seria este:
Para terminar con el FlexGridSizer, vamos a ver dos propiedades mas: flexibledirection ynon_flexible_grow_mode.
“flexibledirection” y “non_flexible_grow_mode”
La propiedad flexibledirection flexibledirection tiene tiene tres valores posibles: wxVERTICAL: las filas que especifiquemos en la propiedad growablesrows growablesrows seran seran flexibles. wxHORIZONTAL: las columnas especificadas en la propiedad growablescols growablescols seran seran flexibles. wxBOTH: Tanto las filas que especifiquemos en la propiedad growablesrows growablesrows,, como las columnas especificadas en la propiedad growablescols growablescols serán serán flexibles Si establecemos la propiedad flexibledirection flexibledirection con con el valor wxVERTICAL o wxHORIZONTAL, debemos especificar como se deberá tratar la dirección que no es flexible, utilizando la propiedad non_flexible_grow_mode. non_flexible_grow_mode. Si Si hemos especificado wxHORIZONTAL (columnas flexibles), debemos decir decir que queremos que pase con el crecimiento de las filas, y si especificamos especifi camos wxVERTICAL (filas flexibles), flexibles), debemos decir como tratar el crecimiento de las columnas. Aquí entra en juego la propiedad non_flexible_grow_mode non_flexible_grow_mode.. Dependiendo de que valor pongamos en la l a propiedad flexibledirection flexibledirection,, tenemos tres escenarios posibles: Escenario 1: La propiedad flexibledirection flexibledirection tiene tiene el valor wxHORIZONTAL En este caso debemos especificar en la propiedad growablecols growablecols las las columnas que crecerán. Veamos que pasaría con las filas dependiendo de que valor pongamos en la propiedad non_flexible_grow_mode non_flexible_grow_mode:: wxFLEX_GROWMODE_NONE: ninguna de las filas crecería. Se ignora el valor de la propiedad growablerows growablerows..
En la imagen puedes ver que especifique que crezcan las columnas 0 y 2, y que no crezca ninguna de las filas. wxFLEX_GROWMODE_ALL: todas las filas crecerían. Se ignora el valor de la propiedadgrowablerows propiedad growablerows..
En este ejemplo especifique que crezcan las columnas 0 y 2, y todas las filas.
wxFLEX_GROWMODE_SPECIFIED: crecerían las filas que especifiquemos en la wxFLEX_GROWMODE_SPECIFIED: propiedadgrowablerows propiedad growablerows..
Aquí especifique que crezcan las columnas 0 y 2, y la l a fila 0.
Escenario 2: La propiedad flexibledirection flexibledirection tiene tiene el valor wxVERTICAL En este caso debemos especificar las filas que crecerán, en la propiedad growablerows growablerows.. Veamos que pasaría con las columnas dependiendo de que valor pongamos en la propiedad non_flexible_grow_mode non_flexible_grow_mode:: wxFLEX_GROWMODE_NONE: ninguna de las columnas crecería. crecería. Se ignora el valor de la propiedad growablecols growablecols..
Aquí especifique que crezcan las filas 0 y 2, y que no crezca ninguna de las columnas.
wxFLEX_GROWMODE_ALL: todas las columnas crecerían. Se ignora el valor de la propiedad growablecols.
En este ejemplo crecen las filas 0 y 2, y todas las columnas.
wxFLEX_GROWMODE_SPECIFIED: crecerían las columnas que especifiquemos en la propiedad growablecols.
Aquí crecen las filas 0 y 2, y la columna 1.
Escenario 3: La propiedad flexibledirection tiene el valor wxBOTH Aquí deberemos especificar tanto las filas como las columnas que crecerán, haciendo uso de las propiedades growablerows y growablecols. En este escenario, el único valor válido para non_flexible_grow_mode es "wxFLEX_GROWMODE_SPECIFIED”, ya que no hay una dirección que no crezca; por este motivo debemos informar las filas y l as columnas flexibles de forma explicita. Vale aclarar que este e s el escenario por defecto. wxFLEX_GROWMODE_SPECIFIED: crecerían las filas y las columnas que especifiquemos en la propiedad growablerows y growablecols.
Aquí crecen las filas 0 y 2, y la columna 1.
Y así llegamos al final de esta parte. Te invito a que comentes si algo no quedo del todo claro, si encuentras algún error, o quieres hacer alguna sugerencia. Ya esta disponible la parte VI Organización de widgets en wxPython (Parte VI)
El GridBagSizer Un GridBagSizer es una versión mejorada del FlexGridSizer. Lo primero que l o hace diferente, es que el GridBagSizer nos da la posibilidad de agregar un widget en una celda especifica a través de sus coordenadas de fila y columna. La segunda característica que lo diferencia, es la posibilidad de combinar varias celdas de modo que formen una sola. Haciendo uso de un GridBagSizer, podemos lograr distribuciones de widgets como la de la siguiente imagen:
En esta imagen, quiero que noten la posibilidad que nos da el GridBagSizer de combinar las celdas. El widget de l a celda (0,1) ocupa dos filas de alto; el widget de la celda (2,1) ocupa dos columnas de ancho y el widget de la celda (0,3) ocupa tres filas de alto. A continuación, veremos como hacer el ejemplo que está en l a imagen utilizando wxFormBuilder. Antes de empezar a crear el ejemplo, les voy a comentar un problema que tiene wxFormBuilder con el GridBagSizer. En todos los Sizers anteriores creábamos primero un Frame y luego el Sizer en cuestión. Si bien aquí debiera ser igual, wxFormBuilder tiene un bug que hace que si intentamos agregar un GridBagSizer directamente dentro de un Frame, simplemente no funcione. La versión de wxFormBuilder que estoy usando es la 3.0.57 (Unicode), depende de en que momento estés leyendo esto, tal ves sea una anécdota, pero por ahora tenemos que usar un pequeño truco: primero creamos el Frame,luego un BoxSizer y por ultimo el GridBagSizer; es decir que debemos agregar el GridBagSizer dentro de un BoxSizer, y de este modo ya podemos trabajar. Dicho esto, veamos como crear el ejemplo paso a paso: Crear el frame:
Crear el BoxSizer (por el bug de wxFormBuilder que te comenté):
Crear el GridBagSizer:
Agregar 8 botones (wxButton), del mismo modo que lo venimos haciendo
hasta acá. El Editor de wxFormBuilder se verá así:
Para poder cambiar la ubicación de un widget dentro de un GridBagSizer, usamos las propiedades row y column, para establecer la fila y la columna donde queremos ubicar realmente el widget. Esto lo hacemos seleccionando el widget que queremos reubicar, y cambiamos los valores de estas propiedades en el panel “Object Properties”. Por ejemplo, para mover el botón de l a celda (0,1) a la celda (1,0) utilizando wxFormBuilder; seleccionamos el botón contenido en la celda (0,1), escribimos un “1” en la propiedad row y establecemos la propiedad column en “0”. Después de hacer esto, el Editor quedaria así:
A continuación, te muestro los movimientos que deberías seguir haciendo para obtener la distribución de los botones del ejemplo: Mover el botón de la celda (0,2) a la celda (2,0):
Mover el botón de la celda (0,3) a la celda (0,1):
Mover el botón de la celda (0,4) a la celda (2,1):
Mover el botón de la celda (0,5) a la celda (0,2):
Mover el botón de la celda (0,6) a la celda (1,2):
Mover el botón de la celda (0,7) a la celda (0,3):
En este punto ya tenemos todos los botones en la ubicación correcta. Ahora debemos combinar las celdas necesarias. Para combinar las celdas, disponemos de las propiedades rowspan y colspan. Con la propiedad rowspan logramos que una celda se combine con cierta cantidad de filas, y con la propiedad colspan combinamos una celda con una cantidad de columnas determinada. Si rowspan y colspan valen “1” (este es el valor por defecto), quiere decir que el widget ocupa solo una fila de alto y una columna de ancho. Para que se entienda mejor, iremos haciendo las combinaciones necesarias para ir terminando el ejemplo. Lo primero será hacer que la celda (0,1) se extienda hacia la fila de abajo (rowspan=2):
Como puedes ver en la imagen, si bien rowspan vale “2” para la celda (0,1), esta no parece estar ocupando dos filas, ya que el botón que esta contenido en ella, no ocupa dos filas, sino una. En realidad si ocupa dos filas, pero por defecto l os widgets dentro del GridBagSizer no crecen en forma automática, es por eso que una ves mas debemos recurrir a l os Flags, y activar el Flag wxEXPAND:
Ahora el botón (wxButton) de la celda (0,1) oc upa las dos filas. Para terminar el ejemplo, debemos combinar y expandir las siguientes celdas: La celda (2,1) debe ocupar dos columnas (colspan=2):
y por último, la celda (0,3) debe ocupar tres filas (rowspan=3):
En la imagen vemos el ejemplo terminado.
Como tal ves notaste, el GridBagSizer es el Sizer mas "complejo" que hemos visto. Si bien, también es cierto que lo podemos definir como el "mas completo y flexi ble", muchas veces no es la mejor opción a la hora de trabajar, debido a su "complejidad" que hace que las interfaces sean mas difíciles de realizar y mantener, es por esto que en general se suelen usar una combinación de los otros Sizers mas simples, para lograr el mismo comportamiento.
... y ahora: ¿Que sigue? Finalmente, después de 6 entregas, estamos en condiciones de comenzar a combinar todo lo visto; así que a partir de la próxima parte del tutorial, nos met eremos de lleno en la creación de interfaces “reales”.
Organización de widgets en wxPython (Parte VII) Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que estas en la quinta parte de un tutorial que empieza AQUI . Como les había prometido en l a ultima entrega, empezaremos a combinar todo lo visto hasta el momento. La idea será tomar como referencia ventanas de “programas reales” y copiar su apariencia. Obviamente, comenzaremos con interfaces simples, y luego iremos viendo algunas con un mayor grado de compleji dad. Como primer proyecto, elegí la ventana “Acerca de” del programa gedit.
La ventana “Acerca de” de gedit
Una de las cosas más difíciles al comenzar a diseñar una interface gráfica que utilice organización dinámica, es determinar que Sizers usar para lograr la distribución deseada. Incluso en este caso, que queremos copiar una interface ya creada, debemos pensar un poco antes de poder darnos cuenta. Una cosa que debes tener en cuenta, es que una misma interface puede estar creada con distintos Sizers, con lo cual quiero decir, que tal ves se te puede ocurrir otra forma de lograr el mismo diseño de manera distinta a la que yo vaya presentando, por lo que seria interesante que si esto sucede, compartas con todos tu idea a través de los comentarios. Por si todavía no imaginas que Sizers podemos utilizar para crear la ventana, voy a mostrarte la misma captura de pantalla de antes, pero con algunas pistas:
Como ves, en la imagen remarque algunas celdas en color rojo. Prestando atención a estas pistas, podemos deducir que esta ventana la podemos lograr utilizando dos Sizers: BoxSizer (Vertical) y un GridSizer. Si todavía “no lo ves”, no te preocupes, y sigue leyendo. Empecemos a trabajar con wxFormBuilder.
Paso 1 Hasta ahora, cuando empezábamos cualquier ejemplo, creábamos un Frame, pero en este caso crearemos un "Dialog" para obtener directamente el aspecto de un cuadro de dialogo en vez del de una ventana estándar.
Paso 2: Creamos un BoxSizer (Vertical), para luego agregar uno a uno los widget que necesitamos en cada fila de éste.
Paso 3: Cuando les hable del BoxSixer (Vertical), vimos que cada widget que agregábamos, se ubicaba debajo del ultimo widget que ya existiera en el Sizer. Teniendo en mente esto, iremos agregando los widgets “de arriba hacia abajo”; empezando por la imagen con el logo de gedit. Para esto, debemos agregar dentro del BoxSizer que creamos, un widget de la clase wxStaticBitmap. El StaticBitmap lo encontramos en la solapa “Common” de la paleta de componentes de wxFormBuilder:
Al crear el StaticBitmap, vemos que en el Editor existe un recuadro rojo con un signo de pregunta en su interior; esto nos indica que si bien el widget se creó, aún no especificamos que imagen se debe mostrar. Para especificar la imagen que queremos mostrar en el StaticBitmap; desplegamos la propiedad bitmap en el panel de propiedades, y luego definimos la ruta a la imagen en file_path:
Paso 4: Debajo del logo, se encuentra el texto con la versión del programa (gedit 2.24.2). Para mostrar un texto simple (como en este caso) disponemos del StaticText. Para crearlo simplemente pulsamos sobre el botón "wxStaticText" en la solapa “Common” de la paleta de componentes de wxFormBuilder:
Ahora que ya creamos el StaticText debajo del logo, cambiaremos el texto “MyLabel” por el de la versión de gedit. El texto que se muestra en un StaticSizer, esta definido en la propiedad label , por lo que sólo debemos escribir el texto “gedit 2.24.2” en esta propiedad:
Con esto ya tenemos el texto debajo del logo, pero nos falta que aparezca centrado como en la ventana original; así que activamos el Flag wxALIGN_CENTER, para centrar el StaticText. Para activar este Flag, tenemos un botón en la barra de herramientas que nos agiliza el trabajo:
Para terminar este paso, cambiaremos la propiedad font del StaticText para que la fuente se parezca mas a la original. Sobre mi plataforma (Ubuntu 8.10 – Intrepid Ibex) para que el tamaño de l a fuente se aproxime al de la ventana original, debe tener 16px y estar en negrita, así que debo poner “16” en "Point Size" y seleccionar “Bold” en “Weight” .
Paso 5: En este paso, debemos agregar un nuevo StaticText para que contenga el texto de l a descripción del programa (“gedit es un editor de t exto pequeño y ...”). Lo creamos de la misma forma que en el paso anterior, y luego establecemos el texto en la propiedad label :
Como se ve en la imagen, el StaticText crece para adaptarse al texto que muestra, pero en la ventana original que estamos “copiando”, el text o ocupa dos lineas y no
una:
Para que un StaticText no se ensanche mas de lo que queremos, debemos especificar el ancho en la propiedad width. En nuestro ejemplo, haremos que tenga un ancho de 235px.
Como ves, ahora el texto ocupa dos lineas, así que ya podemos activar el Flag wxALIGN_CENTER, de modo que el StaticText quede centrado:
Si bien ya tenemos el StaticText centrado (fíjate el recuadro rojo), lo que aún no esta centrado, es el texto en si. Para cambiar la alineación del texto dentro del StaticText usamos la propiedad Style con el valor wxALIGN_CENTRE:
Paso 6: Agregamos otro StaticText, para poner las tres lineas de Copyright.
En este StaticText debemos escribir 3 lineas de texto, pero a diferencia del caso anterior, cada linea debe comenzar con un Copyright distinto, independientemente del ancho del StaticText, por lo que no podemos usar simplemente la propiedad width (como en el caso anterior) ya que si por ejemplo cambiamos el tamaño del texto, seguramente no quedaría un Copyright abajo del otro, sino que probablemente alguno aparecería al lado del otro. En este caso, para lograr el corte de las lineas, utilizamos la secuencia de escape “\n” (sin comillas). Sólo debemos escribir “\n” donde queremos que se corte la línea. Para el ejemplo, el texto seria el siguiente: Copyright © 1998-2000 Evan Lawrence, Alex Robert\nCopyright © 2000-2002 Chema Celorio, Paolo Maggi\nCopyright © 2003-2006 Paolo Maggi Si no quieres escribir los “\n”, puedes hacer que wxFormBuilder lo haga por ti, para esto debes pulsar el botón que se encuentra al final de la caja de texto de la propiedad label y te aparecerá un cuadro de dialogo donde puedes escribir directamente el texto y pulsar Enter donde sea necesario, luego, al cerrar el cuadro de dialogo, wxFormBuilder hará el reemplazo por ti.
Aquí también debemos centrar el texto estableciendo el valor wxALIGN_CENTRE en l a propiedad Style. Luego de centrar el texto, el Editor se vera así :
Si miras con atención, puedes ver que los dos primeros Copyright's hicieron que el Dialog se haga mas ancho de lo que era, y ahora podemos notar que no hemos centrado el logo de gedit. Recuerda que para centrarlo, solo debemos seleccionar el StaticBitmap que lo contiene, y activar el Flag wx.ALIGN_CENTER:
Paso 7: Aqui agregaremos el enlace hacia el sitio del programa. Para crear el enlace usamos el widget de la clase wxHyperlinkCtrl. Agregarlo es tan simple como ir a la solapa “Additional” de la paleta de componentes, y pulsar el botón correspondiente:
Una vez creado, lo centramos y quedaría como se ve a continuación:
Al igual que en el StaticText, para cambiar el texto de un HyperlinkCtrl, usamos la propiedad label . En este caso, el valor de la propiedad label será “http://www.gedit.com”, y también pondremos este mismo valor en la propiedad url para que apunte a esta dirección:
Paso 8: Por último, debemos agregar los botones de “Créditos” y “Cerrar”. Al principio yo les dije que íbamos a usar dos Sizers: BoxSizer (Vertical) y GridSizer. Hasta este momento sólo hemos usado un BoxSizer (Vertical), pero voy a cumplir con lo que te dije, y usaremos el GridSizer. Si en este punto simplemente agregáramos dos botones al BoxSizer (Vertical), estos quedarían uno debajo del otro (por la naturaleza misma del Sizer). Para salvar esto, lo que haremos sera agregar un GridSizer con una fila y dos columnas, y le agregamos un botón a cada una de las celdas:
Aquí vemos como podemos ir combinando los Sizers para obtener la organización que necesitamos. En este caso, el widget de l a ultima fila del BoxSizer (Vertical), es un GridSizer con dos botones. Ahora editamos los textos que aparecen en los botones mediante la propiedad label y por último alineamos el botón “Cerrar” a la derecha de su celda.
Por último les dejo una captura de como les debería quedar el panel "Object Tree", donde vemos claramente la jerarquía de los distintos widgets.
Conclusión: En esta parte del tutorial, creo que se habrán aclarado muchas de las dudas que tal ves tenías (y seguramente te surgieron otras tantas).
La idea de este tutorial se enfoca mas en la organización de los widgets que en la apariencia de los mismos, es por esto que no he hablado demasiado sobre las particularidades de cada widget que usamos (wxStaticText, wxHyperlinkCtrl, etc.). Si les interesa, luego puedo escribir otro tutorial sobre l os distintos widgets que podemos usar con wxPython, y así ver mas en detalle a cada uno de ellos. En la próxima parte, continuaremos con otras interfaces mas elaboradas. Nos vemos!
Organización de widgets en wxPython (Parte VIII) Siguiendo con la idea de hacer “ventanas reales”, hoy será el turno de crear el cuadro de diálogo de “Ajustar balance de color” del programa Gimp (v. 2.6.1). Esta ventana tiene una organización de widgets mas compleja que la que vimos en el post anterior. Empecemos!
La ventana “Ajustar balance de color” de
Gimp
Al igual que hicimos con l a ventana de gedit, lo primera será identificar cuales son los Sizers que debemos usar. Una “técnica” que puede servir para “ver” que Sizers existen en la ventana, es redimensionarla y observar el comportamiento de la misma, así que veamos ahora la ventana redimensionada:
Al redimensionar la ventana, se puede ver básicamente lo siguiente:
1- El ComboBox y los Sliders crecen a lo ancho. 2- La imagen que está en el margen superior derecho, siempre queda anclada en esa esquina. 3- Los botones “Reiniciar”, “Cancelar” y “Aceptar”, quedan “anclados” en la esquina inferior derecha; pero el botón “Ayuda” que esta en la mi sma fila, no cambia su posición. 4- Los dos CheckBox que están arriba del botón “Ayuda”, quedan siempre a la misma distancia de este botón. 5- Del botón “Reiniciar el rango” (inclusive) hacia arriba, la posición de los widgets no varía en forma vertical. Para ayudarte un poco mas, y al igual que antes, te voy a mostrar la ventana original, pero con algunas pistas:
Con este análisis inicial, vamos a empezar a crear la ventana con wxFormBuilder. Para no alargar esta parte mas de lo necesario, y ya que hemos visto como hacer muchas de las cosas que necesitaremos para realizar esta ventana (crear un Frame, un Button, un StaticText, usar Flags de alineación, etc.), voy a obviar algunas capturas y simplemente te diré el paso concreto y te mostrare la imagen con el resultado final; por ejemplo tal vez te diga: “crea dos botones, luego centralos y cambia sus textos a
'Aceptar' y 'Cancelar' respectivamente”. Para que te sirva de ayuda, también iré mostrándote el “Object Tree” en cada paso, para que puedes compararlo con lo que tu vayas haciendo. Dicho esto, veamos el desarrollo paso a paso:
Paso 1: Para empezar crearemos un Frame, y luego como contenedor general usaremos un BoxSizer (Vertical), donde en cada fila iremos poniendo los widgets necesarios. Luego de crear el BoxSizer (Vertical); en la primera fila de éste, tenemos varias cosas por agregar. Debido a que debemos ubicar mas de un widget en esta fila, esta claro que no podemos simplemente agregarlos, ya que quedarían uno debajo del otro. Para cambiar este comportamiento, y dado que en realidad esta primera fila la podemos ver como una serie celdas una al lado de l a otra, lo que agregaremos, será un BoxSizer (Horizontal) y dentro de éste, los siguientes widgets: 1- En primer lugar agregaremos la imagen del icono de la ventana: . Para esto creamos un StaticBitmap y establecemos la ruta a la imagen en file_path.
2- Al lado del icono de la ventana, tenemos que crear dos filas donde habrá un StaticText en cada una de ellas, así que vamos a usar un BoxSizer (Vertical), y de este modo, al agregar los dos StaticText, estos quedarán uno debajo del otro. El StaticText superior tendrá el texto "Ajustar el balance de colores" con una fuente de 16px y en negrita. El StaticText inferior tendrá el texto "Fondo-6 (Via.png)" con una fuente de 8px. Al agregar el BoxSizer (Vertical) y los dos StaticText con sus respectivos textos y formatos, el Editor quedaría así:
3- Al final de esta fila, debemos agregar un nuevo StaticBitmap, que representa la vista previa de la imagen a la que Gimp le ajustara el balance de colores: . El StaticBitmap se lo debemos agregar al BoxSizer (Horizontal) [bsizer2], ya que la imagen esta fuera de las dos filas de la columna del medio. Al i gual que antes, una vez agregado el StaticBitmap, cambiamos la ruta (file_path) para que apunte a la imagen que queremos. Presta especial atención al “Object Tree” en la siguiente imagen, para que se entienda mejor lo que digo:
En esta imagen te remarque en rojo la relación entre el “Object Tree” y el Editor. Puedes ver que la Fila 0 del BoxSizer contenedor (bsizer1), es un BoxSizer (Horizontal), que dentro tiene 3 columnas, done la primera y l a última son StaticBitmaps y la del medio, es un BoxSizer (Vertical) con dos filas, que tienen un StaticText cada una. Por el momento terminamos con la primera fila, así que vamos al paso 2.
Paso 2: Ya fuera del BoxSizer (Horizontal) [bsizer2], agregaremos una simple linea divisoria. Para agregarla, debes ir a la solapa “Common” y clickear sobre el botón “wxStaticLine” :
En la imagen anterior, pueden ver que en el “Object Tree”, contraje el BoxSizer que representa la fila 0, y de este modo podemos notar que el StaticLine esta por f uera del BoxSizer bSizer2. Esto de ir contrayendo los Sizers en el “Object Tree”, es una buena practica para lograr mayor claridad.
Paso 3: La tercera fila del BoxSizer (Vertical) [bsizer1] debe contener cuatro widgets uno al lado del otro. Una vez mas, para lograr esta distribución, usaremos un BoxSizer (Horizontal) donde agregaremos los widgets que irán en cada columna. Los widgets que debemos agregar son los siguientes: 1- Un StaticText con el texto “Ajustes prefijados:”
2- Un ComboBox Este widget lo encontramos en la solapa “Common”. Como vimos en el pequeño análisis del comportamiento de la ventana, al ser redimensionada, este ComboBox debe crecer a lo ancho, es por esto (y por estar contenido en un BoxSizer [Horizontal]) que debemos establecer la propiedad proportion en “1” .
3- Un BitmapButton Para crear este widget lo hacemos desde la solapa “Common”. Una vez agregado; para establecer cual es la imagen que debe mostrar, lo hacemos i gual que con el StaticBitmap, o sea en file_path. Un detalle que podemos notar, es que al crear el BitmapButton, este posee un borde que lo rodea dando la apariencia de ser un botón, pero en la ventana original, no existen bordes, sino que parecen simples imágenes. Para cambiar este aspecto, tenemos que establecer la propiedad window_style, con el valor wxNO_BORDER activado:
4- Otro BitmapButton con su respectiva imagen establecida en file_path, y sin el borde clásico de los botones:
Paso 4: En este paso agregaremos cinco widgets directamente en el sizer que hace de contenedor principal (bSizer1). Los widgets que agregaremos serán los siguientes:
1- En primer lugar crearemos un StatiText con el texto “Seleccione el rango para ajustar”. Para que se asimile mas a la fuente original, ponemos el texto en negrita.
2- En segundo lugar, agregamos 3 widgets de la clase RadioButton desde la solapa “Common” . Para cambiar el texto que muestra cada uno de ellos, lo hacemos editando el valor de la propiedad label . El primer RadioButton tendrá el texto “Sombras”, el segundo dirá “Tonos medios” y el tercero “Puntos de luz” .
3- Para terminar este paso, agregamos otro StaticText con el texto “Ajustar los niveles de color”, y lo ponemos en negrita.
Paso 5: En este paso usaremos un FlexGridSizer con cuatro columnas y tres filas. El FlexGridSizer lo agregaremos en el contenedor principal (bSizer1). Una vez creado, vamos a agregar los siguientes widgets:
1- Un StaticText con el texto “Cian” .
2- Un Slider (lo encuentras en la solapa “Common”).
3- Un StaticText con el texto “Rojo” .
4- Un SpinControl (lo encuentras en la solapa “Additional”).
5- Agregamos la misma secuencia de widgets anterior (de la 1 a la 4), pero con los textos “Magenta” y “Verde” para los StaticText.
6- Hacemos lo mismo que en el paso 5, pero con los textos “Amarillo” y “Azul” para los StaticText.
Como habrás podido notar, los sliders no crecen en forma horizontal como esperaríamos, así que para que esto suceda, y dado que están dentro de l a columna 1 (la segunda) de un FlexGridSizer, lo que debemos hacer es especificar el valor “1” en
la propiedad growablecols, y luego activar el flag wxEXPAND de los 3 Sliders.
Paso 6: Agregamos un botón (fuera del FlexGridSizer) con el texto “Reiniciar el rango” y lo alineamos a la derecha.
Paso 7: Agregamos dos CheckBox con los textos “Conservar la luminosidad” y “Vista previa” respectivamente (Para cambiar el texto de un checkbox, también lo hacemos desde la propiedad label ).
Paso 8: En este paso, vamos a crear la botonera de l a parte inferior. Lo primero que haremos es crear un BoxSizer (Horizontal), al cual le cambiaremos su propiedad proportion a “0”. A este BoxSizer, le agregamos un botón con el texto “Ayuda” .
Si bien podríamos agregar los otros tres botones restantes (“Reinciar”, “Cancelar” y
“Aceptar”) directamente dentro del BoxSizer (bSizer5), si miras nuevamente la ventana original redimensionada, estos tres botones se deben mover juntos hacia la derecha, dejando sólo al de “Ayuda” a la i zquierda. Para lograr esto, agregaremos un BoxSizer (Vertical), que si bien sólo tendrá una fila, aprovecharemos la posibilidad de que podemos cambiar la alineación horizontal de los widgets que este contenga en su interior. Para mover los tres botones juntos dentro del BoxSizer (Vertical), los ubicaremos en un GridSizer de una sola fila y tres columnas. Para verlo mejor, presta atención al “Object Tree” :
Ahora desactivaremos el flag wxEXPAND del GridSizer que contiene los tres botones, y también alineamos el GridSizer a la derecha:
Paso 9: Ya tenemos todos los widgets en su lugar, así que ahora haremos algunos últimos retoques. 1- Establecemos la propiedad proportion en “0” del StaticBox bSizer2, para que no crezca en su altura.
2- También establecemos la propiedad proportion en “0” del StaticBox bSizer4 y el del StaticBox bSizer5, para que tampoco crezcan en su altura.
Hasta aquí esta casi todo terminado excepto por un detalle: si en este momento ejecutamos la ventana (lo cual lo puedes hacer, pulsando F5 desde wxFormBuilder), y luego la redimensionamos, verás algo como esto:
Prestando atención, si comparas esta ventana con l a original, notaras que hay un error: el botón “Reiniciar el rango” no debe bajar al agrandarse la ventana, sólo debe ubicarse a la derecha, pero no bajar. Como una solución a este problema, ubicaremos el botón dentro de un nuevo BoxSizer (Vertical). La forma mas simple de hacer esto es seleccionar el botón (m_button1) en el “Object Tree”, pulsar el botón derecho del mouse, y elegir la opción “Move into a new wxBoxSizer” :
Por último, establecemos la propiedad proportion en “0” del FlexGridSizer.
Si ahora ejecutamos la ventana y la redimensionamos, vemos que se comporta como la ventana original:
Listo, hemos terminado con esta interface. Al igual que en l a ventana que hicimos en el post anterior, he tratado de concentrarme mas en lo organización de los widgets que en su apariencia, así que puede que la “copia” no sea 100% exacta en lo que se ve. Para aproximarla mas aun a la original, puedes jugar con los “bordes” de l os widgets y así modificar el espaciado entre estos. A continuación les muestro el “Object Tree” completamente expandido: