Приложение для рисования на GDI с высокой загрузкой процессора

#c# #.net #winforms

#c# #.net #winforms

Вопрос:

У меня есть приложение, в котором пользователь рисует некоторые фигуры. Когда я нажимаю на фигуру и перетаскиваю ее, процессор загружается на 100% из-за Invalidate() внутри MouseMove. Если я использую таймер и вызываю Invalidate() из события tick, перемещение происходит не так гладко. Есть ли какой-либо другой подход для минимизации процессора и обеспечения плавного перемещения?

   ` Point startDragMousePoint;
    Point startShapeLocation;
    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if(isMouseDown)
        {
            Point deltaPoint = Point.Subtract(e.Location, new Size(startDragMousePoint));
            shape.Location = Point.Add(startShapeLocation, new Size(deltaPoint));
            Invalidate();
        }
    }

    private void Canvas_Paint(object sender, PaintEventArgs e)
    {
       shape.Render(e.Graphics);
    }`
  

Комментарии:

1. Что находится в методе «Invalidate»? не можете ли вы перенести логику в фоновый поток, используя класс Dispatcher, и установить для Dispatcherproperty некоторое меньшее значение?

2. в GDI Invalidate() заставляет окно перерисовываться. Это функция библиотеки Microsoft.

Ответ №1:

Есть три общих решения.

1) Не рисуйте во время перемещения, это долгое время было решением в Windows, когда вы перетаскивали окно, оно просто исчезало, и вы видели контур окна.

2) Создайте растровый объект и перемещайте только его. Обратите внимание, что вам придется перерисовать область под ним.

3) Не делайте недействительным окно отверстия, только область, которую вы изменяете. Рисование в буфере (растровое изображение) может помочь вам повторно использовать области.

Кроме того, если GDI не является самой быстрой функцией рисования в мире. Если ваша фигура очень сложная, вы можете рассмотреть возможность использования OpenGL, DirectX или SDL.

Ответ №2:

Вместо того, чтобы делать недействительной всю область, вы могли бы сделать недействительной часть элемента управления, которая была изменена, используя:

 Rectangle changedArea = new Rectangle(cX, cY, cW, cH);
this.Invalidate(changedArea);
  

Также убедитесь, что ваш элемент управления настроен на использование двойной буферизации

  this.DoubleBuffered = true;
  

Ответ №3:

Из ограниченного кода, который вы разместили, я думаю, что аннулирование не вызовет никаких проблем. Скорее всего, проблема может заключаться в реальном коде рендеринга вашей формы.Визуализация(). В прошлом я писал подобное приложение, в котором я вызывал Invalidate при перемещении мыши, и приложения работали нормально. Только было некоторое мерцание, которое исчезло при включении двойной буферизации.