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< Назад | Оглавление | Далее >

Сайт управляется системой uCoz