2009-10-15 7 views
0

Я написал собственный элемент управления, который отображает некоторую графику. Сама графика довольно дорогая, но после ее рендеринга она редко меняется. У меня есть проблема в том, что если вы перемещаете мышь очень быстро над графикой поверхности он продолжает называть перекрытый метод Paint элемента управления, который затем берет на себя высокий штраф CPU:C# OnPaint mousemove high cpu

частных недействительного UserControl1_Paint (объект отправитель, PaintEventArgs е)

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

+0

спасибо за ответы. Я должен был добавить, что я использую control.Invalidate, когда я знаю, что что-то изменилось. Метод Paint вызывается .NET (not me!), Когда мышь перемещается. –

+2

OnPaint не вызывается, когда мышь перемещается над элементом управления, что-то происходит. –

+1

Я просто протестировал с простым проектом, чтобы убедиться, и Paint не вызывается движением мыши, если я не вызову Invalidate в OnMouseMove (как упоминают другие здесь). Вы уверены, что в коде нет какого-либо другого условия, которое делает вызовы недействительными, когда их не следует вызывать? Попытайтесь добавить некоторый код регистрации, чтобы регистрировать вызовы для отмены и перемещения мыши и посмотреть, вызваны ли они так, как вы намереваетесь. – rslite

ответ

3

EDIT: После просмотра вашего редактирования я могу заверить вас, что OnPaint не вызывается по умолчанию, когда мышь перемещается над элементом управления. Что-то в вашем коде определенно вызывает повторную краску, вы просто этого не видите. Возможно, размещение некоторых из вашего кода поможет нам найти проблему.

Вы признаете недействительным свой контроль над MouseMove? Вероятно, это плохая идея, и если вам действительно нужно это сделать (т. Е. Вы создаете графический редактор или что-то еще), вам нужно быть умным в том, насколько большой регион был перерисован. Итак, решение; не красите свой контроль в MouseMove.

В противном случае я не ожидал, что OnPaint будет гореть, когда мышь перемещается над элементом управления. Вы также можете просто сгенерировать изображение один раз, а затем добавить его в объект Graphics, пока он не будет повторно создан.

+0

спасибо. Вы должны быть верны. Я фактически переопределяю поведение другого Control, поэтому он может делать что-то непослушное под листами, из-за чего mousemove повышает недействительность –

2

Вы можете использовать буферное изображение, на которое нужно рисовать, когда что-то изменилось, и в методе Paint просто скопируйте изображение на экран. Должно быть довольно быстро. Также вы можете использовать область клипа для копирования только той части, которая нуждается в обновлении. Это должно уменьшить использование ЦП.

Вы также можете использовать флаг IsDirty, чтобы узнать, когда необходимо обновить буферное изображение (т. Е. Полностью перерисовать его), если это необходимо.

+0

Это в настоящее время то, что я делаю. Однако мне было интересно, есть ли способ остановить среду, вызывающую Paint, когда движется мышь. –

+0

OnPaint не вызывается, когда курсор перемещается по элементу управления. –

-1

Вы можете использовать этот код для подавления и возобновления перерисовки элемента управления:] Удачи.

using System; 
    using System.Windows.Forms; 
    using System.Collections.Generic; 
    using System.Text; 
    using System.Runtime.InteropServices; 

namespace pl.emag.audiopc.gui { 
    // ************************************************************************ 
//`enter code here` 
    // ************************************************************************ 
    public class PaintingHelper { 
     // ******************************************************************** 
// 
     // ******************************************************************** 
     public static void SuspendDrawing(Control parent) { 
      SendMessage(parent.Handle, WM_SETREDRAW, false, 0); 
     } 
     // ******************************************************************** 
// 
     // ******************************************************************** 
     public static void ResumeDrawing(Control parent) { 
      SendMessage(parent.Handle, WM_SETREDRAW, true, 0); 
      parent.Refresh(); 
     } 
     // ******************************************************************** 
// 
     // ******************************************************************** 
     [DllImport("user32.dll")] 
     private static extern int SendMessage(IntPtr hWnd, Int32 wMsg, 
      bool wParam, Int32 lParam); 
     // ******************************************************************** 
     // 
     // ******************************************************************** 
     private const int WM_SETREDRAW = 11; 
    } 
} 
2

Не следует звонить непосредственно по телефону Paint.

Вместо этого позвоните по телефону Invalidate (Control.Invalidate). Это ставит очередь на необходимость перекраски, и Windows позаботится о самом вызове. Таким образом, многие быстрые недействительности (запросы на перерисовку) могут обслуживаться одним вызовом до Paint.

0

Также проверьте Clip Rectange in the PaintArgs event argument, чтобы вы только перекрасили область, которая нуждается в обновлении, вместо повторного рисования всего изображения.

1

Одной из вещей, которые могут вызвать высокую загрузку процессора в методе Paint, является ненадлежащий (неуправляемый) выпуск ресурсов. Убедитесь, что у вас есть утилита() всех ручек, кистей и т. Д. (Вероятно, все экземпляры классов System.Drawing имеют некоторый неуправляемый ресурс, привязанный к ним). В основном вы должны удалить() объекта, как только закончите работать с ним. Не кэшируйте или что-либо еще - ресурсы GDI + являются системными ресурсами и должны быть возвращены в систему как можно скорее. Приобретение их (например, создание нового экземпляра класса Brush) должно быть довольно быстрым, но на данный момент мне нечего скрывать.

Смежные вопросы