Mover
y cambiar el tamaño de los controles en tiempo de ejecución (para que los usuarios de nuestra aplicación puedan hacerlo) |
Publicado 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.
GuillermoNota 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ónEl 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)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 <[email protected]> '------------------------------------------------------------------------------ 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 ClassMover 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; } } }