Formulario redondeado, romboidal y poligonal en C# y VB

Aplicar regiones a un formulario usando objetos GraphicsPath.AddLine y GraphicsPath.AddEllipse para recortar el área del formulario y cambiar la forma de la ventana, en Visual Studio 2017 con C# y VB

Utilizando objetos de la clase GraphicsPath y aplicando regiones de recorte es sencillo modificar la forma de la ventana de un formulario. Podemos darle prácticamente cualquier aspecto pero, por sencillez del código, en este ejercicio nos restringiremos a 3 formas, círculo, rombo y polígono, usando regiones de recorte con el aspecto deseado.

GraphicsPath del espacio de nombres System.Drawing.Drawing2D representa una serie de líneas y curvas conectadas. La base del ejercicio es:

  • ventana redondeada: en el evento Paint de un PictureBox o del formulario se dibuja sobre GraphicsPath una región de recorte de forma circular con el método AddEllipse y se convierte en la región visible del formulario
  • ventana romboidal y poligonal: en el evento Load del formulario se van añadiendo líneas definidas por su punto x.y de inicio y de final con coordenadas absolutas calculadas respecto a la ventana visible del formulario. Cada segmento de línea se añade con GraphicsPath.AddLine(Int32, Int32, Int32, Int32) a la figura actual.

Los 4 parámetros Int32 de AddLine son: coordenada x del punto inicial de la línea, coordenada y del punto inicial de la línea, coordenada x del punto final de la línea, coordenada y del punto final de la línea.

Imagen del formulario romboidal

Código en C#

Nota: La presentación de este tipo de formularios queda mejor si en el diseñador de VS configuramos su propiedad FormBorderStyle en none.

Para conseguir el aspecto de un formulario redondeado:

// ACTUAMOS EN EL EVENTO PAINT DEL CONTROL PICTUREBOX
private void PBox1_Paint(object sender, PaintEventArgs e)
	{
		// Rectángulo para hacer el recorte
		// El rectángulo está colocado en la esquina superior izquierda del formulario (0,0) y sus medidas
		// han de coincidir con las del formulario (w = this.Width y h = this.Height) (391 px en este caso)
		// Los parámetros (0, 0, w, h) equivalen a (Left, Top, Width, Height) del formulario 
		int w = this.Width;
		int h = this.Height;
		Rectangle rect = new Rectangle(0,0,w,h);
		// Se crea un objeto de la clase GraphicsPath
		GraphicsPath gp = new GraphicsPath();
		// Método que superpone una figura (círculo en este caso) al objeto GraphicsPath
		gp.AddEllipse(rect);
		// Región que se crea a partir del objeto GraphicsPath recortado
		Region reg = new Region(gp);            
		// Esta es la región visible del formulario
		this.Region = reg;
		// Mejorar el aspecto del borde redondeado aplicando antialias
		e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
	}

Para conseguir el aspecto de un formulario romboidal:

//ACTUAMOS EN EL EVENTO LOAD  DEL FORMULARIO
private void F2_Load(System.Object sender, System.EventArgs e)
	{
	// Se crea un objeto de la clase GraphicsPath
	// Para determinar cómo se rellena su interior se usa como parámetro un objeto de la emumeración FillMode que tiene 2 miembros:
	// Alternate (por defecto) y Winding. El modo determina cómo se rellena y recorta el interior de una figura cerrada
	GraphicsPath GP = new GraphicsPath(FillMode.Alternate);
	// anchura y altura del área visible del formulario
	int w = this.Width;
	int h = this.Height;
	// Se van añadiendo líneas definidas por su punto x.y de inicio y de final con coordenadas absolutas 
	// calculadas respecto a la ventana visible del formulario.
	// GraphicsPath.AddLine(Int32, Int32, Int32, Int32) agreda un segmento de línea a la figura actual. Parámetros:
	// x1 Int32 coordenada x del punto inicial de la línea, y1 Int32 coordenada y del punto inicial de la línea
	// x2 Int32 coordenada x del extremo de la línea, y2 Int32 coordenada y del extremo de la línea
	// El ancho y alto del formulario es 391px y se utiliza esa medida junto con 1/2 
	// para elegir los puntos de origen y final de las líneas de recorte.
	// Estas medidas además del valor cero se utilizan para dibujar el rombo
	GP.AddLine(0, h/2, w/2, 0);
	GP.AddLine(w/2, 0, w, h/2);
	GP.AddLine(w, h/2, w/2, h);
	GP.AddLine(w/2, h, 0, h/2);
	// Recortar el objeto GraphicsPath con la forma generada por las líneas
	this.Region = new Region(GP);
	}

Para conseguir el aspecto de un formulario poligonal:

//ACTUAMOS EN EL EVENTO LOAD  DEL FORMULARIO
private void F3_Load(System.Object sender, System.EventArgs e)
	{
	// Se crea un objeto de la clase GraphicsPath
	// Para determinar cómo se rellena su interior se usa como parámetro un objeto de la emumeración FillMode que tiene 2 miembros:
	// Alternate (por defecto) y Winding. El modo determina cómo se rellena y recorta el interior de una figura cerrada
	GraphicsPath GP = new GraphicsPath(FillMode.Alternate);
	// anchura y altura del área visible del formulario
	int w = this.Width;
	int h = this.Height;
	// Se van añadiendo líneas, definidas por su punto x.y de inicio y de final con coordenadas absolutas calculadas respecto a la ventana visible del formulario
	// GraphicsPath.AddLine(Int32, Int32, Int32, Int32) añade un segmento de línea a la figura actual. Parámetros
	// x1 Int32 coordenada x del punto inicial de la línea, y1 Int32 coordenada y del punto inicial de la línea
	// x2 Int32 coordenada x del extremo de la línea, y2 Int32 coordenada y del extremo de la línea
	// El ancho y alto del formulario es 391px y se utiliza esa medida junto con 1/5 y 4/5 
	// para elegir los puntos de origen y final de las líneas de recorte.
	// Estas medidas además del valor cero se utilizan para dibujar el rombo
	GP.AddLine(w / 5, 0, (w / 5) * 4, 0);
	GP.AddLine((w / 5) * 4, 0, w, h);
	GP.AddLine(w, h, 0, h);
	GP.AddLine(0, h, w / 5, 0);
	// Recortar el objeto GraphicsPath con la forma generada por las líneas
	this.Region = new Region(GP);
	}

Control Button transparente

En algunas ocasiones puede ser conveniente que las botones aplicados sobre la imagen de un PictureBox (o cualquier otro control) tengan su fondo transparente. Para que Button sea transparente hay que establecer su propiedad BackColor en Color.Transparent.
La propiedad BackColor es una propiedad de ambiente. Una propiedad de ambiente es una propiedad del control que, si no se establece, se recupera del control principal. Por ejemplo, de forma predeterminada el control Button tendrá la misma propiedad BackColor que su control Form principal.
Si hay otro control entre el control actual (Button) y el primario correspondiente (Form), Button no mostrará el color del control situado entre ambos sino el del control primario (Form). Por ejemplo, los botones transparentes situados sobre un PictureBox cogen el color de fondo del formulario y no el del PictureBox (que es el control intermedio).
Podríamos hacer que el botón se configurase con el color de fondo de la imagen del PictureBox añadiéndolo al grupo de controles del PictureBox con el método Controls.Add, de esta manera PictureBox se convierte en el control primario de Button (en lugar de Form) y es con él con el que simula la transparencia.

this.PictureBox1.Controls.Add(this.Button1);

En este ejercicio esto se aplica a los botones colocados sobre la imagen de fondo de los formularios con forma que, al ser pulsados, cierran la ventana. En los recortes de tipo romboidal y poligonal la imagen está colocada directamente como fondo del formulario que de esta forma es el control padre del botón y, sin necesidad de código adicional, el botón obtiene por transparencia el color de la imagen que tiene debajo con la condición de tener estas 2 propiedades:

this.BtCerrar.BackColor = System.Drawing.Color.Transparent
this.BtCerrar.UseVisualStyleBackColor = true

En el recorte de tipo circular se ha interpuesto un PictureBox que es el que se rellena con la imagen. Si en las propiedades del botón colocamos el código anterior sin más, el resultado es que el botón no se ve porque coge el color del Formulario y no el de la imagen. Hay que añadir el botón al grupo de controles del PictureBox y de esta forma el botón coge el color de la imagen y se muestra correctamente.

private void FormCircular_Load(object sender, EventArgs e)
	{
	//agregar el botón al grupo de controles del PictureBox
	this.PBox1.Controls.Add(this.BtCerrar);
	}

Puedes descargar un archivo ZIP con las aplicaciones C# y VB.