Hi there, I am writing some code to resize a borderless form but the results are wrong. I can't find where the problem is

65 views Asked by At

When I try to run this code the behavior of the output is unexpected and I think the code is correct. If anyone got some insight please help me to resolve this problem.

I've tried to adjust the code to solve the problem in different ways without luck. The main problem should be in the MouseMove event but I cannot see the fault.

namespace Personal.Forms
{
    public partial class NewMainForm : Form
    {
        private const int BorderWidth = 5;
        private bool isResizing = false;
        private Point lastMousePosition;
        private Size originalSize;

        public NewMainForm()
        {
            InitializeComponent();
            InitializeFormEvents();
        }

        private void InitializeFormEvents()
        {
            this.MouseDown += MainForm_MouseDown;
            this.MouseMove += MainForm_MouseMove;
            this.MouseUp += MainForm_MouseUp;
        }

        private void MainForm_MouseDown(object? sender, MouseEventArgs e)
        {
            if (IsOnBorder(e.Location))
            {
                isResizing = true;
                lastMousePosition = e.Location;
                originalSize = this.Size;
            }
        }

        private void MainForm_MouseMove(object? sender, MouseEventArgs e)
        {
            if (isResizing)
            {
                int deltaX = e.X - lastMousePosition.X;
                int deltaY = e.Y - lastMousePosition.Y;

                if (lastMousePosition.X < BorderWidth)
                {
                    // Adjust left side
                    this.Width = Math.Max(originalSize.Width - deltaX, this.MinimumSize.Width);
                    this.Left += originalSize.Width - this.Width;
                }
                else if (lastMousePosition.X > this.Width - BorderWidth)
                {
                    // Adjust right side
                    this.Width = Math.Max(originalSize.Width + deltaX, this.MinimumSize.Width);
                }

                if (lastMousePosition.Y < BorderWidth)
                {
                    // Adjust top side
                    this.Height = Math.Max(originalSize.Height - deltaY, this.MinimumSize.Height);
                    this.Top += originalSize.Height - this.Height;
                }
                else if (lastMousePosition.Y > this.Height - BorderWidth)
                {
                    // Adjust bottom side
                    this.Height = Math.Max(originalSize.Height + deltaY, this.MinimumSize.Height);
                }

                lastMousePosition = e.Location;
            }
            else if (IsOnBorder(e.Location))
            {
                this.Cursor = Cursors.SizeAll;
            }
            else
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void MainForm_MouseUp(object? sender, MouseEventArgs e)
        {
            isResizing = false;
        }

        private bool IsOnBorder(Point point)
        {
            return point.X < BorderWidth || point.X > this.Width - BorderWidth ||
                   point.Y < BorderWidth || point.Y > this.Height - BorderWidth;
        }
    }
}
1

There are 1 answers

0
Olivier Jacot-Descombes On

I suggest a slightly different approach. Let's add the following declaration to the form:

private const int BorderWidth = 5;

private enum Border
{
    None,
    Near, // left or top
    Far   // right or bottom
}

private bool _isResizing;
private Border _borderX, _borderY;
private Point _distanceToBorder;

The Border enum indicates which border is affected. We determine it in the MouseDown event:

private void FormBorderlessResize_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Location.X < BorderWidth) {
        _borderX = Border.Near;
        _distanceToBorder.X = MousePosition.X - Left;
    } else if (e.Location.X > Width - BorderWidth) {
        _borderX = Border.Far;
        _distanceToBorder.X = Right - MousePosition.X;
    } else {
        _borderX = Border.None;
    }
    if (e.Location.Y < BorderWidth) {
        _borderY = Border.Near;
        _distanceToBorder.Y = MousePosition.Y - Top;
    } else if (e.Location.Y > Height - BorderWidth) {
        _borderY = Border.Far;
        _distanceToBorder.Y = Bottom - MousePosition.Y;
    } else {
        _borderY = Border.None;
    }
    _isResizing = _borderX != Border.None || _borderY != Border.None;
}

private void FormBorderlessResize_MouseUp(object sender, MouseEventArgs e)
{
    _isResizing = false;
}

Note that I am storing the distance of the mouse cursor to the non-moving border. I use the screen coordinates given by MousePosition for this. It yields more stable positions than the local mouse coordinates which are affected by movements of our form. The distance we get is by itself an absurd number, but this doesn't matter, as we only need the relative measurements.

Moving the mouse becomes:

private void FormBorderlessResize_MouseMove(object sender, MouseEventArgs e)
{
    if (_isResizing) {
        switch (_borderX) {
            case Border.Near:
                int right = Right;
                Width = Math.Max(MinimumSize.Width, Right - MousePosition.X + _distanceToBorder.X);
                Left = right - Width;
                break;
            case Border.Far:
                Width = MousePosition.X + _distanceToBorder.X - Left;
                break;
        }
        switch (_borderY) {
            case Border.Near:
                int bottom = Bottom;
                Height = Math.Max(MinimumSize.Height, Bottom - MousePosition.Y + _distanceToBorder.Y);
                Top = bottom - Height;
                break;
            case Border.Far:
                Height = MousePosition.Y + _distanceToBorder.Y - Top;
                break;
        }
    }
}