Índice de la sección dedicada a .NET (en el Guille) Cómo... en .NET

Mover y cambiar el tamaño de los controles en tiempo de ejecución
(para que los usuarios de nuestra aplicación puedan hacerlo)

Código para Visual Basic.NET (VB.NET)

Código para C Sharp (C#)


Publicado el 26/Oct/2002
Actualizado el 26/Oct/2002

 

El código que te voy a mostrar, (tanto para Visual Basic .NET como para C#), está basado en un ejemplo que hice hace tiempo para Visual Basic clásico, (cuyo código está en la entrega 25 del Curso Básic y que puedes ver si sigues este link).

Lo de cambiar el tamaño de los controles se hace mediante llamadas al API de Windows y, casi con total seguridad, se podría hacer de otra forma mejor, pero...
De todas formas, decirte que para cambiar el tamaño de un control, tendrás que pulsar con el botón secundario del ratón sobre dicho control y verás que se cambia el borde del mismo, permitiendo que se cambie el tamaño, para volver a dejarlo "normal", pulsa de nuevo con el botón secundario del ratón.

En fin... no es gran cosa... pero creo que puede ser interesante, sobre todo es más facil que en VB clásico, ya que la posibilidad de poder asignar dinámicamente los eventos a los controles es algo que en la versión anterior de Visual Basic no se podía hacer (o casi)

Entre otras cosillas, tienes un ejemplo de saber cómo agregar eventos a los controles en tiempo de ejecución...

Una aclaración, en las cajas de texto y los combos, no se puede seleccionar el texto con el ratón... ya que cuando se pulsa el botón del ratón, se entra en modo "mover", pero este inconveniente se podría solucionar en una aplicación usando un "indicador" (o flag) que idicara si se está en modo "diseño" o en ejecución normal...

¡Que lo disfrutes!

Nos vemos.
Guillermo

Nota del 07/ene/05:
Si quieres ver sólo el código necesario para mover un formulario al pulsar en cualquier parte del mismo o sobre cualquier control, sigue este link.


Una captura del formulario en tiempo de ejecución
y los links al código completo, tanto para VB .NET como para C#


El ejemplo de VB .NET en ejecución

El código del proyecto para Visual Basic .NET (movercontrolesVB.zip 24.4 KB)
El código del proyecto para C# (movercontrolesCS.zip 25.4 KB)


Código para Visual Basic.NET (VB.NET)Mover y redimensionar controles en tiempo de ejecución (código para VB .NET)


'------------------------------------------------------------------------------
' Redimensionar y mover controles
'
' Revisado para Visual Basic.NET                                    (20/Ene/02)
' Revisado para ejemplo en http://www.elguille.info/                (26/Oct/02)
'
' ©Guillermo 'guille' Som, 1996-2002 <mensaje@elguille.info>
'------------------------------------------------------------------------------
Option Strict On

Friend Class MoverControles
    Inherits System.Windows.Forms.Form
    '
    Private DX, DY As Integer
    '
    ' Declaraciones del API para 32 bits
    Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
        (ByVal hwnd As Integer, ByVal nIndex As Integer) As Integer
    Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
        (ByVal hwnd As Integer, ByVal nIndex As Integer, _
         ByVal dwNewLong As Integer) As Integer
    Private Declare Function SetWindowPos Lib "user32" _
        (ByVal hwnd As Integer, ByVal hWndInsertAfter As Integer, _
         ByVal X As Integer, ByVal Y As Integer, _
         ByVal cX As Integer, ByVal cY As Integer, _
         ByVal wFlags As Integer) As Integer
    '
    ' Constantes para usar con el API
    Const GWL_STYLE As Integer = (-16)
    Const WS_THICKFRAME As Integer = &H40000 ' Con borde redimensionable
    '
    Const SWP_DRAWFRAME As Integer = &H20
    Const SWP_NOMOVE As Integer = &H2
    Const SWP_NOSIZE As Integer = &H1
    Const SWP_NOZORDER As Integer = &H4
    '
    '' Este procedimiento no es necesario en Visual Basic .NET,
    '' pero está por si se quiere añadir código
    '' para detectar si ya está en ejecución,
    'Shared Sub Main()
    '    ' Starts the application.
    '    Application.Run(New MoverControles())
    'End Sub
    '
#Region "Windows Form Designer generated code "
    '...
#End Region
    '
    Private Sub CmdSalir_Click( _
            ByVal eventSender As Object, _
            ByVal eventArgs As System.EventArgs) _
            Handles cmdSalir.Click
        Me.Close()
        Application.Exit()
    End Sub
    '
    Private Sub Text3_Move( _
            ByVal sender As Object, _
            ByVal e As System.EventArgs) _
            Handles Text3.Move
        Text3.Text = "Left= " & Text3.Left.ToString & ", Top= " & Text3.Top.ToString
    End Sub
    '
    Private Sub Form_Load( _
            ByVal sender As Object, _
            ByVal e As System.EventArgs) _
            Handles MyBase.Load
        ' Asignar a todos los controles los eventos para poder moverlos...
        ' Usar un procedimiento recursivo                         (17/May/02)
        AsignarEventos(Me)
        '
        Text2.Text = "X= 0, Y= 0"
        Text3.Text = "Left= " & Text3.Left.ToString & ", Top= " & Text3.Top.ToString
    End Sub
    '
    Private Sub Form_MouseMove( _
            ByVal sender As Object, _
            ByVal e As System.Windows.Forms.MouseEventArgs) _
            Handles MyBase.MouseMove
        Text2.Text = "X= " & e.X.ToString & ", Y= " & e.Y.ToString
    End Sub
    '
    Private Sub Control_MouseDown( _
            ByVal sender As Object, _
            ByVal e As System.Windows.Forms.MouseEventArgs)
        ' Cuando se pulsa con el ratón
        DX = e.X
        DY = e.Y
        ' Al pulsar con el botón derecho, 
        ' cambiar el estilo entre redimensionable y normal
        'lblStatus.Text = "Control: " & CType(sender, Control).Name
        If e.Button = MouseButtons.Right Then
            CambiarEstilo(CType(sender, Control))
        Else
            ' Cuando se pulsa en un control, posicionarlo encima del resto
            CType(sender, Control).BringToFront()
        End If
    End Sub
    '
    Private Sub Control_MouseMove( _
            ByVal sender As Object, _
            ByVal e As System.Windows.Forms.MouseEventArgs)
        ' Cuando se mueve el ratón y se pulsa el botón izquierdo... mover el control
        If e.Button = MouseButtons.Left Then
            CType(sender, Control).Left = e.X + CType(sender, Control).Left - DX
            CType(sender, Control).Top = e.Y + CType(sender, Control).Top - DY
        End If
    End Sub
    '
    Private Sub Control_MouseEnter( _
            ByVal sender As Object, _
            ByVal e As System.EventArgs)
        lblStatus.Text = "Control: " & CType(sender, Control).Name
    End Sub
    '
    Private Sub AsignarEventos(ByVal elControl As Control)
        Dim ctrl As Control
        ' 
        For Each ctrl In elControl.Controls
            ' No asignar estos evento al botón salir
            If ctrl.Name <> "cmdSalir" Then
                ' Curiosamente un control GroupBox en apariencia
                ' no tiene estos eventos, pero... se le asigna y...
                ' ¡funciona!
                AddHandler ctrl.MouseDown, AddressOf Me.Control_MouseDown
                AddHandler ctrl.MouseMove, AddressOf Me.Control_MouseMove
                AddHandler ctrl.MouseEnter, AddressOf Me.Control_MouseEnter
                AsignarEventos(ctrl)
            End If
        Next
    End Sub
    '
    Private Sub CambiarEstilo(ByVal aControl As Control)
        ' Hacer este control redimensionable, usando el API
        ' Pone o quita el estilo dimensionable
        Dim Style As Integer
        '
        ' Si se produce un error, no hacer nada...
        Try
            Style = GetWindowLong(aControl.Handle.ToInt32, GWL_STYLE)
            If (Style And WS_THICKFRAME) = WS_THICKFRAME Then
                ' Si ya lo tiene, lo quita
                Style = Style Xor WS_THICKFRAME
            Else
                ' Si no lo tiene, lo pone
                Style = Style Or WS_THICKFRAME
            End If
            SetWindowLong(aControl.Handle.ToInt32, GWL_STYLE, Style)
            SetWindowPos(aControl.Handle.ToInt32, Me.Handle.ToInt32, 0, 0, 0, 0, SWP_NOZORDER Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_DRAWFRAME)
        Catch 'e As Exception
            'MsgBox("El control " & queControl.Name & " no permite que se redimensione", MsgBoxStyle.Information)
            'Exit Sub
        End Try
    End Sub
    '
End Class

Código para C Sharp (C#)Mover y redimensionar controles en tiempo de ejecución (código para C#)


//-----------------------------------------------------------------------------
// Redimensionar y mover controles
//
// Revisado para Visual C#                                          (20/Ene/02)
// Corregidas las declaraciones del API y las constantes            (17/May/02)
// Así como en la forma de acceder al objeto sender convertirdo en control
//
// Revisado para ejemplo en http://www.elguille.info/               (26/Oct/02)
//
// ©Guillermo 'guille' Som, 1996-2002 
//----------------------------------------------------------------------------

using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MoverControlesCS
{
    public class MoverControles : System.Windows.Forms.Form
    {
        int DY, DX;
        //
        //' Declaraciones del API para 32 bits
        [DllImport("user32.DLL", EntryPoint="GetWindowLong")]
        static extern int GetWindowLong(
            int hWnd,   // handle to window
            int nIndex  // offset of value to retrieve
        );
        [DllImport("user32.DLL", EntryPoint="SetWindowLong")]
        static extern int SetWindowLong(
            int hWnd,       // handle to window
            int nIndex,     // offset of value to set
            int dwNewLong   // new value
        );
        [DllImport("user32.DLL", EntryPoint="SetWindowPos")]
        static extern bool SetWindowPos(
            int hWnd,               // handle to window
            int hWndInsertAfter,    // placement-order handle
            int X,                  // horizontal position
            int Y,                  // vertical position
            int cx,                 // width
            int cy,                 // height
            uint uFlags             // window-positioning options
        );
        //'
        //' Constantes para usar con el API
        const int GWL_STYLE = (-16);
        const int WS_THICKFRAME = 0x40000; //' Con borde redimensionable
        //'
        const int SWP_DRAWFRAME = 0x20;
        const int SWP_NOMOVE = 0x2;
        const int SWP_NOSIZE = 0x1;
        const int SWP_NOZORDER = 0x4;
        //'
        //
    #region  Declaración de los controles del formulario
        //...
    #endregion

        #region Windows Form Designer generated code
        //
        #endregion

        private void cmdSalir_Click(
                object sender,
                System.EventArgs e)
        {
            // Finalizar el programa
            this.Close();
            Application.Exit();
        }

        void CambiarEstilo(Control aControl)
        {
            //' Hacer este control redimensionable, usando el API
            //' Pone o quita el estilo dimensionable
            int Style;
            //'
            //' Si se produce un error, no hacer nada...
            try
            {
                Style = GetWindowLong(aControl.Handle.ToInt32(), GWL_STYLE);
                if( (Style & WS_THICKFRAME) == WS_THICKFRAME ) // & = And
                {
                    //' Si ya lo tiene, lo quita
                    Style = Style ^ WS_THICKFRAME; // ^ = Xor
                }
                else
                {
                    //' Si no lo tiene, lo pone
                    Style = Style | WS_THICKFRAME; // | = Or
                }
                SetWindowLong(aControl.Handle.ToInt32(), GWL_STYLE, Style);
                SetWindowPos(aControl.Handle.ToInt32(), this.Handle.ToInt32(), 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_DRAWFRAME);
            }
            catch //(Exception e)
            {
                //MessageBox.Show(e.Message ); 
                //MessageBox.Show("El control " + aControl.Name + " no permite que se redimensione","",MessageBoxButtons.OK ,MessageBoxIcon.Warning  );
            }
        }

        private void Form_Load(
                object sender,
                System.EventArgs e)
        {
            // Al cargar el formulario, asignar los eventos, etc.
            //' Asignar a todos los controles los eventos para poder moverlos...
            //' 
            // Usar un procedimiento recursivo                      (17/May/02)
            AsignarEventos(this);
            //'
            Text2.Text = "X= 0, Y= 0";
            Text3.Text = "Left= " + Text3.Left.ToString() + ", Top= " + Text3.Top.ToString();
        }

        private void AsignarEventos(Control elControl)
        {
            foreach(Control ctrl in elControl.Controls )
            {
                //' No asignar estos evento al botón salir
                if( ctrl.Name != "cmdSalir")
                {
                    ctrl.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Control_MouseDown);
                    ctrl.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Control_MouseMove);
                    ctrl.MouseEnter += new System.EventHandler(this.Control_MouseEnter);
                    // Comprobar si el control contiene otros controles
                    AsignarEventos(ctrl);
                }
            }
        }

        private void Form_MouseMove(
                object sender,
                System.Windows.Forms.MouseEventArgs e)
        {
            Text2.Text = "X= " + e.X.ToString() + ", Y= " + e.Y.ToString();
        }

        private void Text3_Move(
                object sender,
                System.EventArgs e)
        {
            Text3.Text = "Left= " + Text3.Left.ToString() + ", Top= " + Text3.Top.ToString();
        }

        private void Control_MouseDown(
                object sender,
                System.Windows.Forms.MouseEventArgs e)
        {
            //' Cuando se pulsa con el ratón
            DX = e.X;
            DY = e.Y;
            //' Al pulsar con el botón derecho, 
            //' cambiar el estilo entre redimensionable y normal
            Control elControl = (Control)sender;
            //lblStatus.Text = "Control: " + elControl.Name ;
            if( e.Button == MouseButtons.Right )
                CambiarEstilo(elControl);
            else
                //' Cuando se pulsa en un control, posicionarlo encima del resto
                elControl.BringToFront();
        }

        private void Control_MouseMove(
                object sender,
                System.Windows.Forms.MouseEventArgs e)
        {
            //' Cuando se mueve el ratón... mover el control
            if( e.Button == MouseButtons.Left )
            {
                Control elControl = (Control)sender;
                elControl.Left = e.X + elControl.Left - DX;
                elControl.Top = e.Y + elControl.Top - DY;
            }
        }

        private void Control_MouseEnter(
                object sender,
                System.EventArgs e)
        {
            Control elControl = (Control)sender;
            lblStatus.Text = "Control: " + elControl.Name;
        }

        private void CheckBox1_Click(
                object sender,
                System.EventArgs e)
        {
            CheckBox1.Checked = false;
        }
        private void RadioButton1_CheckedChanged(
                object sender,
                System.EventArgs e)
        {
            RadioButton1.Checked = false;
        }
    }
}

la Luna del Guille o... el Guille que está en la Luna... tanto monta...