Драг прямоугольника

Драгом (drag) называтся возможность захватывать мышкой объекты в графическом интерфейсе (GUI) и перетаскивать их в новое место. Обычно драг осуществляется наведением на требуемый объект нажатием зажатием левой кнопки мыши и затем перемещением объекта на новое место с отпускание левой кнопки мыши в конце.

Данная задача будет использовать технику ховер прямоугольника

Введем переменные для описания прямоугольника 

int posX = 50;
int posY = 50;
int rectWidth = 200;
int rectHeight = 150;

В конструкторе выполним инициализацию окна и сцены

public Form1()
{
    InitializeComponent();
    var timer = new System.Windows.Forms.Timer();
    StartPosition = FormStartPosition.CenterScreen;
    timer.Interval = 5;
    timer.Start();
    timer.Tick += Timer_Tick;
    DoubleBuffered = true;
    Paint += Form1_Paint;
//подпишемся на события мышки
    MouseDown += Form1_MouseDown;
    MouseUp += Form1_MouseUp;

// зададим позицию прямоугольника ровно по центру окна
    posX = ClientSize.Width / 2 - rectWidth / 2;
    posY = ClientSize.Height / 2 - rectHeight / 2;

}

Подпишемся на события нажатия и поднятия кнопки мыши. Введем bool переменную, которая будет указывать зажата ли в данный момент мышка над нашим прямоугольником или нет.

bool isDrag = false;

private void Form1_MouseUp(object? sender, MouseEventArgs e)
{
    isDrag = false;
}

private void Form1_MouseDown(object? sender, MouseEventArgs e)
{
    var cursor = PointToClient(Cursor.Position);
    RectangleF rect = new RectangleF(posX, posY, rectWidth, rectHeight);
    if (rect.Contains(cursor))
    {
//запоминает стартовую позицию прямоугольника (до драга)
        startPosX = posX;
        startPosY = posY;
// запоминаем позицию курсора (при старте драга)
        startCursorX = cursor.X;
        startCursorY = cursor.Y;
        isDrag = true;
    }
}

Напишем функцию отрисовки сцены:

private void Form1_Paint(object? sender, PaintEventArgs e)
{
    var gr = e.Graphics;
    gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    gr.Clear(Color.Black);
    var cursor = PointToClient(Cursor.Position);
    if (isDrag) // если драг в прогрессе
    {
//расчитаем разницу координат курсора (смещение драга)
        var cursorDiffX = cursor.X - startCursorX;
        var cursorDiffY = cursor.Y - startCursorY;
// обновим координаты прямоугольника
        posX = startPosX + cursorDiffX;
        posY = startPosY + cursorDiffY;
    }
    RectangleF rect = new RectangleF(posX, posY, rectWidth, rectHeight);
    if (rect.Contains(cursor)) // проверка и отрисовка ховера
    {
        gr.FillRectangle(Brushes.LimeGreen, posX, posY, rectWidth, rectHeight);
    }
// рисуем обводку прямоугольника
    gr.DrawRectangle(Pens.White, posX, posY, rectWidth, rectHeight);
}

Проверим что получилось:

 

Полный код примера можно посмотреть здесь

Задания:

1. Сделать несколько разных прямоугольников, которые можно двигать

2. Сделать окружность, которую можно двигать