C# – El extraño caso de la ventana sin borde que no se deja cambiar de tamaño
Esta es una copia del artículo original publicado en mi blog,
el artículo original con código y texto completemante formateado se puede ver en:
C# - El extraño caso de la ventana sin borde que no se deja cambiar de tamaño
------------------------------------------------------------------------------------------------------------------
Cómo hacer una ventana sin borde que se deje redimensionar
Hola,
tal vez este titulo les parezca repetido, pero no es así. Quiero traer a colación uno de mis artículos más populares en la web:
C# – El extraño caso de la ventana sin borde que no se deja maximizar ni minimizar
Bien, en el continuo devenir de mi hobbie, que es programar, tuve la oportunidad de ayudarle a un amigo, más conocido como
VIRUTERO_5 quien en dado momento estaba trabajando con una ventana sin borde, con tan mala suerte que necesitaba que esta ventana se dejara redimensionar por el usuario, pero como ustedes podrán adivinar… no es posible hacer esto por si solo.
Así que estuve revisando el tema por un rato y llegue a dos soluciones, una de ellas rápida con resultados ‘modestos’ y otra un poco más demorada pero con resultados mucho más profesionales.
A continuación expondré las dos soluciones, y como siempre, tratando que la funcionalidad sea muy entendible para todos aunque es claro que ya en sus labores podrán organizarla mucho mejor.
Para hacer este ejercicio lo primero es crear un proyecto de Windows Forms, utilizaremos la forma creada por defecto para hacer lo demás.
Método 1, rápido y resultados modestos
Dejamos el Form tal y como queda creado por defecto.
Una vez más debemos sobrescribir la propiedad CreateParams, allí cambiaremos el estilo inicial de la forma dejándolo tal como esta pero quitándole el atributo WS_CAPTION, que básicamente es la barra de título.
PHP:
const int WS_CAPTION = 0xC00000;
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
p.Style &= ~WS_CAPTION;
return p;
}
}
Eso es todo, el resultado es una ventana a la que se le puede cambiar el tamaño, aunque no es del todo una ventana sin borde.
La solución más fácil y obvia es “quitemos el borde” esto lo podemos hacer quitando además de WS_CAPTION a WS_THICKFRAME tal y como lo mostré en el artículo C# – El extraño caso de la ventana sin borde que no se deja maximizar ni minimizar, pero el problema es que precisamente WS_THICKFRAME es el que le da al Form la funcionalidad de cambiar el tamaño. Así que hasta aquí llega el método 1.
Método 2, demorado pero con resultados más profesionales
Esta vez, desde el diseñador, dejamos el Form sin borde.
Hacer que el Form luzca como un objeto que se deja cambiar de tamaño
Lo primero que debemos hacer es que el Form luzca como un objeto que se deja cambiar de tamaño, puesto que sino tiene borde hay que buscar una forma de que el usuario se de por enterado de que SI puede cambiarle el tamaño.
Para poder dibujar el SizeGrip debemos determinar su tamaño, para mi gusto 15px es perfecto, y debemos dibujarlo en la ubicación tradicional que es en la parte inferior derecha del Form.
Es importante tener en cuenta que si el usuario cambia el tamaño del Form la ubicación relativa del SizeGrip cambiará también ya que debe ajustarse a las nuevas dimensiones así que creamos un método capaz de establecer el Rectangle donde se dibujara el SizeGrip de acuerdo al tamaño del Form.
PHP:
Rectangle sizeGripRectangle;
const int GRIP_SIZE = 15;
private void AdaptGripRectangle()
{
sizeGripRectangle.X = this.Width - GRIP_SIZE;
sizeGripRectangle.Y = this.Height - GRIP_SIZE;
}
public Form1()
{
InitializeComponent();
sizeGripRectangle.Width = sizeGripRectangle.Height = GRIP_SIZE;
AdaptGripRectangle();
}
Como ya tenemos definido del tamaño y la ubicación del SizeGrip modificaremos el evento Paint para dibujarlo. Utilizaré la notación lambda por que me gusta más, no se confundan, es lo mismo que utilizar un delegado o los eventhandler tradicionales.
PHP:
public Form1()
{
InitializeComponent();
sizeGripRectangle.Width = sizeGripRectangle.Height = GRIP_SIZE;
AdaptGripRectangle();
this.Paint += (o, ea) => { ControlPaint.DrawSizeGrip(ea.Graphics,
this.BackColor,
sizeGripRectangle); };
}
La clase ControlPaint incorpora varios métodos útiles, uno de ellos es precisamente DrawSizeGrip que hace el dibujo que necesitamos. Para ello le pasamos como Color el BackColor de la forma actual, para que se vea más natural, y desde luego el Rectangle que define el SizeGrip
Ejecutamos nuestra Form y se ve así:
Hacer que el SizeGrip sirva para algo
Todo va muy bonito, muy simpático pero completamente inútil. El SizeGrip hasta el momento no es nada más que un adorno pero no sirve para nada. Hay que hacer que funcione.
Antes que nada necesitamos un método que nos diga si un punto dado, por ejemplo la ubicación del mouse, esta encima del SizeGrip esto es fácil de hacer:
PHP:
private bool IsInSizeGrip(Point tmp)
{
if (tmp.X >= sizeGripRectangle.X
&& tmp.X <= this.Width
&& tmp.Y >= sizeGripRectangle.Y
&& tmp.Y <= this.Height
)
return true;
else
return false;
}
Una vez hecho esto, hay que detectar cuando el mouse hace clic sobre el SizeGrip. Para ello creamos una variable boolean llamada inSizeDrag y la modificaremos con los eventos MouseDown y MouseUp, de tal forma que si el usuario deja presionado el botón del mouse justo sobre el SizeGrip ponemos la variable en true, y una vez levante el botón del mouse ponemos la variable en false.
PHP:
//declaramos esta variable en la clase
bool inSizeDrag = false;
//...
//...
//Adicionamos este codigo en el constructor
//justo despues de donde hicimos lo del evento Paint
this.MouseUp += delegate { inSizeDrag = false; };
this.MouseDown += (o, ea) =>
{
if (IsInSizeGrip(ea.Location))
inSizeDrag = true;
};
Gracias a esto ya podemos detectar cuando el usuario quiere cambiar el el tamaño del Form, así que solo basta con modificar el evento MouseMove, allí detectamos si se pretende cambiar el tamaño del Form y si es así entonces procedemos a cambiarle el tamaño de acuerdo a las coordenadas del mouse.
A las coordenadas del mouse les he adicionado la mitad del tamaño del SizeGrip para producir un efecto más natural.
PHP:
//La mitad del tamaño del SizeGrip
//se declara en al clase
const int GRIP_SIZE_OVER_TWO = GRIP_SIZE / 2;
//...
//..
//esto lo colocamos justo despues de donde
//hemos colocado todo el código anterior
this.MouseMove += (o, ea) =>
{
if (inSizeDrag)
{
this.Width = ea.Location.X + GRIP_SIZE_OVER_TWO;
this.Height = ea.Location.Y + GRIP_SIZE_OVER_TWO;
AdaptGripRectangle();
this.Invalidate();
}
};
Eso es todo, pueden ver la aplicación y el ejemplo completo disponible para descarga al final del artículo en mi blog.
Ventana Sin Borde pero Resizable.
byte!
.