Posición y tamaño de los controles



IronPython - Diseño WinForms: Propiedades Location y Size


Vamos a crear una aplicación winforms con ironpython para ver como posicionar y dar tamaño a los controles. Empecemos creando el esqueleto de la aplicación:

# -*- coding: utf-8 -*-

import sys, clr

clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Drawing')

from System.Windows.Forms import *
from System.Drawing import *

class MainForm(Form):
    def __init__(self):
    	Form.__init__(self)
    	self.Text = 'Mi App'
    	self.Icon = Icon.ExtractAssociatedIcon(sys.executable)
    	self.ClientSize = Size(300, 100)
    	self.add_controls()

    def add_controls(self):
    	pass


if __name__ == '__main__':

    Application.EnableVisualStyles()
    Application.Run(MainForm())

En el método MainForm.add_controls añadiremos los controles.


Añadir un control al formulario


Vamos a añadir un Button al formulario MainForm:

def add_controls(self):
    button = Button()
    button.Text = 'Un botón'
    self.Controls.Add(button)

El resultado es el siguiente:

Botón con posición y tamaño por defecto

El botón se encuentra en la esquina superior izquierda, ya que es la posición por defecto. Su tamaño también es asignado por defecto debido a que no lo hemos indicado explícitamente.

Para que el control sea visible hay que añadirlo a la colección Controls del formulario: self.Controls.Add(button).

Si quieres eliminar un control en tiempo de ejecución puede utilizar el método Remove de la colección Controls del formulario: self.Controls.Remove(button).


Posición y tamaño del control


Continuando con el botón que hemos añadido anteriormente al formulario, ahora vamos a asignarle una posición y tamaño explícitamente:

def add_controls(self):
    button = Button()
    button.Text = 'Un botón'
    button.Location = Point(50, 30)
    button.Size = Size(100, 50)
    self.Controls.Add(button)

Este código da el siguiente resultado:

Botón con posición y tamaño personalizados

La propiedad Location define la posición del control en el eje de coordenadas de su contenedor (en este caso el formulario). Su valor debe ser una instancia de System.Drawing.Point. El primer parámetro es la posición en el eje X y el segundo la posición en el eje Y.

La propiedad Size define el tamaño del control. Su valor debe se una instancia de System.Drawing.Size. El primer parámetro es el ancho y el segundo el alto.


Centrar un control


Vamos a intentar centrar nuestro botón. Fíjate que en el método __init__ hemos asignado un tamaño al formulario: self.ClientSize = Size(300, 100).

La propiedad ClientSize del formulario define el tamaño del área en la que se dibujan los controles, es decir, es el tamaño del formulario sin incluir la caja de control (donde están los botones de minimizar, maximizar y cerrar el formulario).

Podemos utilizar self.ClientSize para asignar a nuestros controles posiciones y tamaños relativos al tamaño del formulario. Por ejemplo:

def add_controls(self):
    button = Button()
    button.Text = 'Un botón'
    button.Location = Point(self.ClientSize.Width/2, self.ClientSize.Height/2)
    button.Size = Size(100, 50)
    self.Controls.Add(button)

El resultado es el siguiente:

Botón casi centrado

El ancho del formulario está almacenado en self.ClientSize.Width, y su altura en self.ClientSize.Height. Al asignar button.Location = Point(self.ClientSize.Width/2, self.ClientSize.Height/2) el botón ¿está centrado? no lo está.

Lo que está centrado es la esquina superior izquierda del botón. Si queremos centrar el botón tenemos que tener en cuenta su propio tamaño:

def add_controls(self):
    button = Button()
    button.Text = 'Un botón'

    button.Size = Size(100, 50)

    x = int((self.ClientSize.Width - button.Size.Width) / 2)
    y = int((self.ClientSize.Height - button.Size.Height) / 2)

    button.Location = Point(x, y) # # x e y pueden ser <float> o <int> en ironpython, pero en pythonnet tienen que ser <int>

    self.Controls.Add(button)

Ahora el botón si está centrado, ya que a su posición en X le restamos la mitad se su propio ancho, y a su posición en Y le restamos la mitad de su propia altura.

Botón centrado

Fíjate en que para centrar el botón ha sido necesario definir su Size antes que su Location.

El único problema es que si el usuario cambia el tamaño del formulario el botón no se adapta:

Formulario redimensionado - botón no adaptable

De momento, la solución que vamos a dar va a ser impedir que se pueda cambiar el tamaño del formulario asignando self.FormBorderStyle = FormBorderStyle.FixedSingle. Ya de paso, deshabilitaremos el botón de maximizar el formulario: self.MaximizeBox = False.


Código final


El código completo de nuestra increible aplicación con un botón que no hace nada, pero perfectamente centrado, es el siguiente:

# -*- coding: utf-8 -*-

import sys, clr

clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Drawing')

from System.Windows.Forms import *
from System.Drawing import *

class MainForm(Form):
    def __init__(self):
        Form.__init__(self)
        self.Text = 'Mi App'
        self.Icon = Icon.ExtractAssociatedIcon(sys.executable)
        self.ClientSize = Size(300, 100)
        self.MaximizeBox = False
        self.FormBorderStyle = FormBorderStyle.FixedSingle
        self.add_controls()

    def add_controls(self):
        button = Button()
        button.Text = 'Un botón'

        button.Size = Size(100, 50)

        x = int((self.ClientSize.Width - button.Size.Width) / 2)
        y = int((self.ClientSize.Height - button.Size.Height) / 2)

        button.Location = Point(x, y) # x e y pueden ser <float> o <int> en ironpython, pero en pythonnet tienen que ser <int>

        self.Controls.Add(button)


if __name__ == '__main__':

    Application.EnableVisualStyles()
    Application.Run(MainForm())

En la siguiente sección aprenderás a adaptar la posición y tamaño de los controles cuando cambia el tamaño del formulario.

Un saludo!