Hola, en este tutorial realizaremos un Formulario de Menú Principal Plano, Moderno y Multi Forms (Abrir Varios Formularios en un panel, tal como lo harías en un MDI Parent), con todas las funcionalidades de un formulario normal, totalmente personalizado, con Windows Form, C# o Visual Basic (VB.Net).
Bien, empecemos con el tutorial:
Paso 1: Crear Proyecto y Formulario de Menú Principal
- Creamos un proyecto nuevo de aplicación de Windows Form en C# o Visual Vasic (VB.Net).
- Removemos el borde del formulario: Propiedad-> FormBorderStyle=None
- Cambiamos el tamaño al formulario: Propiedad-> Size= 1100; 600
- Asignamos el tamaño mínimo del formulario: Propiedad-> MinimumSize= 680; 500
Paso 2: Crear Función de Redimensionar (Cambiar de Tamaño – Resize) el Formulario
Al establecer la propiedad FormBorderStyle=None del formulario, este pierde la funcionalidad de poder cambiar de tamaño, para solucionar el problema, realizamos lo siguiente.
- Agregamos un Panel como Contenedor Principal para otros paneles y formularios.
- Establecemos la propiedad BackColor = ActiveCaption (OPCIONAL)
- Establecemos la propiedad Dock = Fill
- Asignamos un nombre al panel: Name = “PanelContenedor”
- El diseño de debió haber quedado de la siguiente manera:
- Ahora es momento de codificar la funcionalidad de redimensionar el formulario a través de Panel Contenedor Principal.
FormMenuPrincipal.cs /.vb
//Constructor public FormMenuPrincipal() { InitializeComponent(); //Estas lineas eliminan los parpadeos del formulario o controles en la interfaz grafica (Pero no en un 100%) this.SetStyle(ControlStyles.ResizeRedraw, true); this.DoubleBuffered = true; } //RESIZE METODO PARA REDIMENCIONAR/CAMBIAR TAMAÑO A FORMULARIO EN TIEMPO DE EJECUCION ---------------------------------------------------------- private int tolerance = 12; private const int WM_NCHITTEST = 132; private const int HTBOTTOMRIGHT = 17; private Rectangle sizeGripRectangle; protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_NCHITTEST: base.WndProc(ref m); var hitPoint = this.PointToClient(new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16)); if (sizeGripRectangle.Contains(hitPoint)) m.Result = new IntPtr(HTBOTTOMRIGHT); break; default: base.WndProc(ref m); break; } } //----------------DIBUJAR RECTANGULO / EXCLUIR ESQUINA PANEL protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); var region = new Region(new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height)); sizeGripRectangle = new Rectangle(this.ClientRectangle.Width - tolerance, this.ClientRectangle.Height - tolerance, tolerance, tolerance); region.Exclude(sizeGripRectangle); this.panelContenedor.Region = region; this.Invalidate(); } //----------------COLOR Y GRIP DE RECTANGULO INFERIOR protected override void OnPaint(PaintEventArgs e) { SolidBrush blueBrush = new SolidBrush(Color.FromArgb(244, 244, 244)); e.Graphics.FillRectangle(blueBrush, sizeGripRectangle); base.OnPaint(e); ControlPaint.DrawSizeGrip(e.Graphics, Color.Transparent, sizeGripRectangle); }
'RESIZE DEL FORMULARIO- CAMBIAR TAMAÑO' Dim cGrip As Integer = 10 Protected Overrides Sub WndProc(ByRef m As Message) If (m.Msg = 132) Then Dim pos As Point = New Point((m.LParam.ToInt32 And 65535), (m.LParam.ToInt32 + 16)) pos = Me.PointToClient(pos) If ((pos.X _ >= (Me.ClientSize.Width - cGrip)) _ AndAlso (pos.Y _ >= (Me.ClientSize.Height - cGrip))) Then m.Result = CType(17, IntPtr) Return End If End If MyBase.WndProc(m) End Sub '----------------DIBUJAR RECTANGULO / EXCLUIR ESQUINA PANEL' Dim sizeGripRectangle As Rectangle Dim tolerance As Integer = 15 Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs) MyBase.OnSizeChanged(e) Dim region = New Region(New Rectangle(0, 0, Me.ClientRectangle.Width, Me.ClientRectangle.Height)) sizeGripRectangle = New Rectangle((Me.ClientRectangle.Width - tolerance), (Me.ClientRectangle.Height - tolerance), tolerance, tolerance) region.Exclude(sizeGripRectangle) Me.PanelContenedor.Region = region Me.Invalidate() End Sub '----------------COLOR Y GRIP DE RECTANGULO INFERIOR' Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) Dim blueBrush As SolidBrush = New SolidBrush(Color.FromArgb(244, 244, 244)) e.Graphics.FillRectangle(blueBrush, sizeGripRectangle) MyBase.OnPaint(e) ControlPaint.DrawSizeGrip(e.Graphics, Color.Transparent, sizeGripRectangle) End Sub
Paso 3: Diseñar la Interfaz Gráfica de Menú Principal
- Diseñe la interfaz gráfica de menú principal sobre el Panel Contenedor. La configuración de las propiedades se describen abajo.
- Establezca las siguientes propiedades en los controles de usuario.
Panel Barra Titulo
BackColor = 0; 100; 182
Dock = Top
Name = «panelBarraTitulo»
Size = 1200; 40
Panel Menú
Name = «panelMenu»
Dock = Left
Size = 240; 560
BackColor = 37; 54; 75
Panel Formularios
BackColor = Control
Dock = Fill
Name = «panelFormularios»
Picture Box Cerrar, Maximizar, Minimizar, Restaurar
Size = 16;16
Cursor = Hand
Anchor = Top | Right (Responsive)
Botones
FlatStyle = Flat
FlatAppearance.BorderSize = 0
Size = 230, 45
Paso 4: Crear Función de Cerrar, Maximizar/Restaurar y Minimizar el formulario
- Creamos los eventos Clic de cada botón, y codificamos de la siguiente manera:
private void btnCerrar_Click(object sender, EventArgs e) { Application.Exit(); } //Capturar posicion y tamaño antes de maximizar para restaurar int lx, ly; int sw, sh; private void btnMaximizar_Click(object sender, EventArgs e) { lx = this.Location.X; ly = this.Location.Y; sw = this.Size.Width; sh = this.Size.Height; btnMaximizar.Visible = false; btnRestaurar. Visible = true; this.Size = Screen.PrimaryScreen.WorkingArea.Size; this.Location = Screen.PrimaryScreen.WorkingArea.Location; } private void btnRestaurar_Click(object sender, EventArgs e) { btnMaximizar.Visible = true ; btnRestaurar.Visible = false; this.Size = new Size(sw,sh); this.Location = new Point(lx,ly); } private void btnMinimizar_Click(object sender, EventArgs e) { this.WindowState = FormWindowState.Minimized; }
Private Sub btnCerrar_Click(sender As Object, e As EventArgs) Handles btnCerrar.Click Application.Exit() End Sub Dim lx, ly As Integer Dim sw, sh As Integer Private Sub btnMaximizar_Click(sender As Object, e As EventArgs) Handles btnMaximizar.Click lx = Me.Location.X ly = Me.Location.Y sw = Me.Size.Width sh = Me.Size.Height btnMaximizar.Visible = False btnRestaurar.Visible = True Me.Size = Screen.PrimaryScreen.WorkingArea.Size Me.Location = Screen.PrimaryScreen.WorkingArea.Location End Sub Private Sub btnRestaurar_Click(sender As Object, e As EventArgs) Handles btnRestaurar.Click Me.Size = New Size(sw, sh) Me.Location = New Point(lx, ly) btnMaximizar.Visible = True btnRestaurar.Visible = False End Sub Private Sub btnMinimizar_Click(sender As Object, e As EventArgs) Handles btnMinimizar.Click Me.WindowState = FormWindowState.Minimized End Sub
Paso 5: Crear Función de Arrastrar el formulario (Drag Form)
- Importamos la librería System.Runtime.InteropServices, y agregamos los siguientes fragmentos de código.
[DllImport("user32.DLL", EntryPoint = "ReleaseCapture")] private extern static void ReleaseCapture(); [DllImport("user32.DLL", EntryPoint = "SendMessage")] private extern static void SendMessage(System.IntPtr hWnd, int wMsg, int wParam, int lParam);
<DllImport("user32.DLL", EntryPoint:="ReleaseCapture")> Private Shared Sub ReleaseCapture() End Sub <DllImport("user32.DLL", EntryPoint:="SendMessage")> Private Shared Sub SendMessage(ByVal hWnd As System.IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) End Sub
- Creamos el evento MouseDown del Panel Barra de Titulo, e invocamos los métodos anteriores creados.
private void panelBarraTitulo_MouseMove(object sender, MouseEventArgs e) { ReleaseCapture(); SendMessage(this.Handle, 0x112, 0xf012, 0); }
Private Sub PanelBarraTitulo_MouseMove(sender As Object, e As MouseEventArgs) Handles PanelBarraTitulo.MouseMove ReleaseCapture() SendMessage(Me.Handle, &H112&, &HF012&, 0) End Sub
Paso 6: Crear Método para Abrir formularios en el panel Contenedor.
- Creamos el siguiente método que nos permitirá abrir varios formularios dentro del panel contenedor de formularios.
private void AbrirFormulario<MiForm>() where MiForm : Form, new() { Form formulario; formulario = panelformularios.Controls.OfType<MiForm>().FirstOrDefault();//Busca en la colecion el formulario //si el formulario/instancia no existe if (formulario == null) { formulario = new MiForm(); formulario.TopLevel = false; formulario.FormBorderStyle = FormBorderStyle.None; formulario.Dock = DockStyle.Fill; panelformularios.Controls.Add(formulario); panelformularios.Tag = formulario; formulario.Show(); formulario.BringToFront(); } //si el formulario/instancia existe else { formulario.BringToFront(); } }
Private Sub AbrirFormEnPanel(Of Miform As {Form, New})() Dim Formulario As Form Formulario = PanelFormularios.Controls.OfType(Of Miform)().FirstOrDefault() 'Busca el formulario en la coleccion' 'Si form no fue econtrado/ no existe' If Formulario Is Nothing Then Formulario = New Miform() Formulario.TopLevel = False Formulario.FormBorderStyle = FormBorderStyle.None Formulario.Dock = DockStyle.Fill PanelFormularios.Controls.Add(Formulario) PanelFormularios.Tag = Formulario Formulario.Show() Formulario.BringToFront() Else Formulario.BringToFront() End If End Sub
- Invocamos el método anterior de la siguiente manera:
private void button1_Click(object sender, EventArgs e) { AbrirFormulario<Form1>(); } private void button2_Click(object sender, EventArgs e) { AbrirFormulario<Form2>(); }
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click AbrirFormEnPanel(Of Form1)() End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click AbrirFormEnPanel(Of Form2)() End Sub
Recomendaciones Finales
Crea los formularios hijos que se abrirán en el panel contenedor de Formulario al mismo tamaño de este, adicionando las dimensiones del borde. para este ejemplo, el tamaño ideal es: 886 de ancho; 496 de alto (El tamaño del panel contenedor de Formulario es 870; 457, a este le sumamos el tamaño de los bordes del form: 16 de ancho, 39 de alto ), de esa manera evitamos que le formulario parpadee al abrir formularios o redimensionar en tiempo de ejecución.
Eso es todo 🙂