visual studio redimensionar net formulario form change c# winforms winapi window-resize

c# - studio - vb net change form height



Mango de cambio de tamaƱo personalizado en forma sin bordes C# (4)

Estoy intentando hacer formas sin bordes que salgan de una barra de herramientas. Quiero que el usuario pueda tomar en la esquina inferior derecha (un "controlador de cambio de tamaño") y poder cambiar el tamaño del formulario, pero no podrá cambiar el tamaño o cambiar la posición del formulario de ninguna otra manera.

He oído que puedo interceptar el mensaje WM_NCHITTEST enviado al formulario y establecer su resultado en HTBOTTOMRIGHT que permitirá que el sistema operativo maneje el redimensionamiento del formulario, como si tuviera un marco considerable. La idea que tenía era detectar si el puntero del mouse había ingresado en un cuadro que HTBOTTOMRIGHT en la esquina y, si lo hacía, devolver el resultado HTBOTTOMRIGHT .

Esto no funciona del todo como esperaba. Puedo interceptar el mensaje, pero parece que el mensaje solo se envía cuando el usuario coloca el cursor del mouse en el borde grueso de 1px del formulario. Eso significa que funciona como quiero, si coloca el cursor con mucha precisión en los bordes inferior derecho.

Aquí está mi anulación de WndProc :

protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 HTBOTTOMRIGHT = 17; const int RESIZE_HANDLE_SIZE = 40; bool handled = false; if (m.Msg == WM_NCHITTEST) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Rectangle hitBox = new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE); if (hitBox.Contains(clientPoint)) { m.Result = (IntPtr)HTBOTTOMRIGHT; handled = true; } } if (!handled) base.WndProc(ref m); }

¿Estoy haciendo algo mal o hay una mejor manera de hacer lo que estoy tratando de hacer?

Muchas gracias.


Basado en la solución de Charles P. hizo algunas modificaciones, espero que ayude a otros también :) Pequeñas comprobaciones y mejoras para no declarar variables adicionales cada vez que se invoca el mensaje de Windows. También verifica que no se pinta el ancla de agarre cuando el estado de las ventanas está maximizado. Quería crear un control personalizado, pero terminé rellenando el formulario con este código, lamentablemente.

Constructor o en el archivo de diseñador:

this.DoubleBuffered = true; this.ResizeRedraw = true;

Anulación de las funciones de Windows:

const uint WM_NCHITTEST = 0x0084, WM_MOUSEMOVE = 0x0200, HTLEFT = 10, HTRIGHT = 11, HTBOTTOMRIGHT = 17, HTBOTTOM = 15, HTBOTTOMLEFT = 16, HTTOP = 12, HTTOPLEFT = 13, HTTOPRIGHT = 14; Size formSize; Point screenPoint; Point clientPoint; Dictionary<uint, Rectangle> boxes; const int RHS = 10; // RESIZE_HANDLE_SIZE bool handled; protected override void WndProc(ref Message m) { if (this.WindowState == FormWindowState.Maximized) { base.WndProc(ref m); return; } handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE) { formSize = this.Size; screenPoint = new Point(m.LParam.ToInt32()); clientPoint = this.PointToClient(screenPoint); boxes = new Dictionary<uint, Rectangle>() { {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RHS, RHS, RHS)}, {HTBOTTOM, new Rectangle(RHS, formSize.Height - RHS, formSize.Width - 2*RHS, RHS)}, {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RHS, formSize.Height - RHS, RHS, RHS)}, {HTRIGHT, new Rectangle(formSize.Width - RHS, RHS, RHS, formSize.Height - 2*RHS)}, {HTTOPRIGHT, new Rectangle(formSize.Width - RHS, 0, RHS, RHS) }, {HTTOP, new Rectangle(RHS, 0, formSize.Width - 2*RHS, RHS) }, {HTTOPLEFT, new Rectangle(0, 0, RHS, RHS) }, {HTLEFT, new Rectangle(0, RHS, RHS, formSize.Height - 2*RHS) } }; foreach (var hitBox in boxes) { if (hitBox.Value.Contains(clientPoint)) { m.Result = (IntPtr)hitBox.Key; handled = true; break; } } } if (!handled) base.WndProc(ref m); } protected override void OnPaint(PaintEventArgs e) { if (this.WindowState != FormWindowState.Maximized) { ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, this.ClientSize.Width - 16, this.ClientSize.Height - 16, 16, 16); } base.OnPaint(e); }


Estaba buscando algo similar y el código de Anton era una gran base. Esto es lo que terminé para cambiar el tamaño del trabajo desde todos los lados. No estoy seguro de que un Dictionary forma óptima de almacenar los hitboxes, pero supongo que no importa demasiado.

Y como mi formulario está lleno de controles utilizando los parámetros de Rellenar como Muelle, solo tuve que agregar un relleno de 5px al Form para que funcione bien.

protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 WM_MOUSEMOVE = 0x0200; const UInt32 HTLEFT = 10; const UInt32 HTRIGHT = 11; const UInt32 HTBOTTOMRIGHT = 17; const UInt32 HTBOTTOM = 15; const UInt32 HTBOTTOMLEFT = 16; const UInt32 HTTOP = 12; const UInt32 HTTOPLEFT = 13; const UInt32 HTTOPRIGHT = 14; const int RESIZE_HANDLE_SIZE = 10; bool handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Dictionary<UInt32, Rectangle> boxes = new Dictionary<UInt32, Rectangle>() { {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOM, new Rectangle(RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE)}, {HTTOPRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOP, new Rectangle(RESIZE_HANDLE_SIZE, 0, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOPLEFT, new Rectangle(0, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTLEFT, new Rectangle(0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE) } }; foreach (KeyValuePair<UInt32, Rectangle> hitBox in boxes) { if (hitBox.Value.Contains(clientPoint)) { m.Result = (IntPtr) hitBox.Key; handled = true; break; } } } if (!handled) base.WndProc(ref m); }


solo pequeñas modificaciones a tu código. WM_MOUSEMOVE manejo de mensajes WM_MOUSEMOVE :

protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 WM_MOUSEMOVE = 0x0200; const UInt32 HTBOTTOMRIGHT = 17; const int RESIZE_HANDLE_SIZE = 10; bool handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE ) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Rectangle hitBox = new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE); if (hitBox.Contains(clientPoint)) { m.Result = (IntPtr)HTBOTTOMRIGHT; handled = true; } } if (!handled) base.WndProc(ref m); }

por cierto, puede dibujar un agarre de tamaño de ventana específico del sistema con ControlPaint.DrawSizeGrip Method http://msdn.microsoft.com/en-us/library/2e1yx2sa.aspx


Anton Semenov , no entendí tu código.

De todos modos, tuve un problema con el primer código de Charles P ,
cuando maximizo la ventana y luego trato de cambiar su tamaño, está cambiando de tamaño.
después de eso no pude arreglarlo de nuevo a su tamaño normal, ni maximizarlo de nuevo con el botón max normal.

Lo que hice para solucionar este problema fue agregar una condición dentro del bucle ''foreach'' en la parte inferior:

protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 WM_MOUSEMOVE = 0x0200; const UInt32 HTLEFT = 10; const UInt32 HTRIGHT = 11; const UInt32 HTBOTTOMRIGHT = 17; const UInt32 HTBOTTOM = 15; const UInt32 HTBOTTOMLEFT = 16; const UInt32 HTTOP = 12; const UInt32 HTTOPLEFT = 13; const UInt32 HTTOPRIGHT = 14; const int RESIZE_HANDLE_SIZE = 10; bool handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Dictionary<UInt32, Rectangle> boxes = new Dictionary<UInt32, Rectangle>() { {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOM, new Rectangle(RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE)}, {HTTOPRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOP, new Rectangle(RESIZE_HANDLE_SIZE, 0, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOPLEFT, new Rectangle(0, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTLEFT, new Rectangle(0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE) } }; foreach (KeyValuePair<UInt32, Rectangle> hitBox in boxes) { if (this.WindowState != FormWindowState.Maximized && hitBox.Value.Contains(clientPoint)) { m.Result = (IntPtr)hitBox.Key; handled = true; break; } } } if (!handled) base.WndProc(ref m); }