netlib.narod.ru | < Назад | Оглавление | Далее > |
О программе, работающей не так быстро, как хотелось бы, пользователи говорят «тормозит». Характеристика нелицеприятная, но зачастую справедливая.
Я уже немного улучшил эффективность программы, вызывая методы SysInfoStrings только при запуске программы или при изменении любого из свойств SystemInformation. Еще я избавился от трех вызовов SysInfoStrings при каждом вызове OnPaint.
Однако OnPaint продолжает выводить все 60 строк — и вызывает метод DrawString 120 раз — каждый раз, когда часть клиентской области становится недействительной. На большинстве компьютеров все 60 строк даже не будут видны. Более того, вертикальная прокрутка обычно продвигает текст на 1 – 2 строки; в этих случаях методу OnPaint требуется перерисовать лишь одну – две строки.
Windows сама предоставляет некоторую оптимизацию. Объект Graphics, который вы получаете в методе OnPaint, может выводить информацию только в недействительных участках пользовательской области. Это так называемая область отсечения (clipping region), которая включает в себя только недействительные части пользовательской области и не позволяет выводить информацию за их пределами. Пример перерисовки только недействительных частей пользовательской области был приведен в программе RandomClear в главе 3. Однако факт остается фактом: вы все еще делаете 120 вызовов DrawString, и Windows все еще нужно проверять, относится ли каждый конкретный вызов DrawString к области отсечения.
К счастью, нам поможет свойство ClipRectangle класса PaintEventArgs которое определяет наименьший прямоугольник в координатах клиентской области, в который умещается недействительная зона. (Как было показано в программе RandomClear, недействительная зона не обязательно имеет форму прямоугольника.) В качестве эксперимента можете добавить строку:
Console.Writeline(pea.ClipRectangle);
в метод OnPaint и попробовать прокручивать информацию в окне или частично закрывать форму окнами других программ.
Программа SysInfoEfficient наследует SysInfoUpdate и переопределяет метод OnPaint его более эффективной версией. При помощи пары довольно простых вычислений, основанных на свойстве формы AutoScrollPosition и свойстве ClipRectangle класса PaintEventArgs, вычисляются номера строк, заносимые в переменные iFirst и iLast, которые затем используются в цикле for для отображения минимального количества строк, требуемых для перерисовки клиентской области.
SysInfoColumns.cs
//------------------------------------------------- // SysInfoEfficient.cs (C) 2001 by Charles Petzold //------------------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class SysInfoEfficient: SysInfoUpdate { public new static void Main() { Application.Run(new SysInfoEfficient()); } public SysInfoEfficient() { Text = "System Information: Efficient"; } protected override void OnPaint(PaintEventArgs pea) { Graphics grfx = pea.Graphics; Brush brush = new SolidBrush(ForeColor); Point pt = AutoScrollPosition; int iFirst = (int)((pea.ClipRectangle.Top - pt.Y) / cySpace); int iLast = (int)((pea.ClipRectangle.Bottom - pt.Y) / cySpace); iLast = Math.Min(iCount - 1, iLast); for (int i = iFirst; i <= iLast; i++) { grfx.DrawString(astrLabels[i], Font, brush, pt.X, pt.Y + i * cySpace); grfx.DrawString(astrValues[i], Font, brush, pt.X + cxCol, pt.Y + i * cySpace); } } }
Перед циклом for стоит выражение, которое с помощью метода MathMin предотвращает выход значения iLast за пределы общего количества отображаемых строк. Предел может быть превышен, если окно программы выше, чем требуется для отображения всех строк.
netlib.narod.ru | < Назад | Оглавление | Далее > |