netlib.narod.ru< Назад | Оглавление | Далее >

Работа с колесиком

Давайте сразу разберемся с колесиком, чтобы потом спокойно сосредоточиться на более привычных аспектах работы с мышью. Абзацем выше я упоминал число 120. Это довольно редкий пример числа, которое очень важно для программирования Windows Forms (по крайней мере для обработки событий колесика мыши), но не связано ни с одним статическим свойством или значением перечисления. В заголовочных файлах Win32 идентификатор WHEEL_DELTA определен как 120. В программах Windows Forms, использующих колесико, придется жестко запрограммировать это значение или определить собственную константу.

Получив событие MouseWheel, надо рассчитать число строк для прокрутки, скажем, так:

  mea.Delta * SystemInformation.MouseWheelScrollLines / 120

В данный момент результатом этого вычисления будет 3 или –3, но включение в расчет константы из SystemInformation позволяет программе лучше приспособиться к будущим устройствам с большим числом градаций вращения колесика. Положительные значения свидетельствуют о том, что пользователь вращает колесико вперед, на что программа должна ответить прокруткой текста к началу документа. Отрицательные значения говорят, что пользователь вращает колесико назад и программа должна прокрутить текст в направлении конца документа.

Следующая программа демонстрирует использование колесика мыши, выводя (и прокручивая) текст душещипательного стихотворения Эдгара Алана По «Аннабель Ли».

PoePoem.cs

  //----------------------------------------
  // PoePoem.cs (C) 2001 by Charles Petzold
  //----------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class PoePoem: Form
  {
      const string strAnnabelLee =

          "It was many and many a year ago,\n"                         +
          "   In a kingdom by the sea,\n"                              +
          "That a maiden there lived whom you may know\n"              +
          "   By the name of Annabel Lee;\x2014\n"                     +
          "And this maiden she lived with no other thought\n"          +
          "   Than to love and be loved by me.\n"                      +
          "\n"                                                         +
          "I was a child and she was a child\n"                        +
          "   In this kingdom by the sea,\n"                           +
          "But we loved with a love that was more than love\x2014\n"   +
          "   I and my Annabel Lee\x2014\n"                            +
          "With a love that the wingйd seraphs of Heaven\n"            +
          "   Coveted her and me.\n"                                   +
          "\n"                                                         +
          "And this was the reason that, long ago,\n"                  +
          "   In this kingdom by the sea,\n"                           +
          "A wind blew out of a cloud, chilling\n"                     +
          "   My beautiful Annabel Lee;\n"                             +
          "So that her highborn kinsmen came\n"                        +
          "   And bore her away from me,\n"                            +
          "To shut her up in a sepulchre,\n"                           +
          "   In this kingdom by the sea.\n"                           +
          "\n"                                                         +
          "The angels, not half so happy in Heaven,\n"                 +
          "   Went envying her and me\x2014\n"                         +
          "Yes! that was the reason (as all men know,\n"               +
          "   In this kingdom by the sea)\n"                           +
          "That the wind came out of the cloud by night,\n"            +
          "   Chilling and killing my Annabel Lee.\n"                  +
          "\n"                                                         +
          "But our love it was stronger by far than the love\n"        +
          "   Of those who were older than we\x2014\n"                 +
          "   Of many far wiser than we\x2014\n"                       +
          "And neither the angels in Heaven above\n"                   +
          "   Nor the demons down under the sea\n"                     +
          "Can ever dissever my soul from the soul\n"                  +
          "   Of the beautiful Annabel Lee:\x2014\n"                   +
          "\n"                                                         +
          "For the moon never beams, without bringing me dreams\n"     +
          "   Of the beautiful Annabel Lee;\n"                         +
          "And the stars never rise, but I feel the bright eyes\n"     +
          "   Of the beautiful Annabel Lee:\x2014\n"                   +
          "And so, all the night-tide, I lie down by the side\n"       +
          "Of my darling\x2014my darling\x2014my life and my bride,\n" +
          "   In her sepulchre there by the sea\x2014\n"               +
          "   In her tomb by the sounding sea.\n"                      +
          "\n"                                                         +
          "                                       [May 1849]\n";

      readonly int   iTextLines = 0;
      int            iClientLines, iStartLine = 0;
      float          cyText;

      public static void Main()
      {
          // Смотрим, имеет ли смысл запускать программу

          if (!SystemInformation.MouseWheelPresent)
          {
              MessageBox.Show("Program needs a mouse with a mouse wheel!",
                              "PoePoem", MessageBoxButtons.OK,
                              MessageBoxIcon.Error);
              return;
          }
          // Все идет нормально

          Application.Run(new PoePoem());
      }
      public PoePoem()
      {
          Text = "\"Annabel Lee\" by Edgar Allan Poe";
          BackColor = SystemColors.Window;
          ForeColor = SystemColors.WindowText;
          ResizeRedraw = true;

          // Вычисляем количество строк в тексте

          int iIndex = 0;

          while((iIndex = strAnnabelLee.IndexOf('\n', iIndex)) != -1)
          {
              iTextLines++;
              iIndex++;
          }

          // Получаем величину межстрочного интервала

          Graphics grfx = CreateGraphics();
          cyText = Font.GetHeight(grfx);
          grfx.Dispose();

          OnResize(EventArgs.Empty);
      }
      protected override void OnResize(EventArgs ea)
      {
          base.OnResize(ea);

          iClientLines = (int) (ClientSize.Height / cyText);

          iStartLine = Math.Max(0, 
                       Math.Min(iStartLine, iTextLines - iClientLines));
      }
      protected override void OnMouseWheel(MouseEventArgs mea)
      {
          int iScroll = 
               mea.Delta * SystemInformation.MouseWheelScrollLines / 120;

          iStartLine -= iScroll;
          iStartLine  = Math.Max(0, 
                        Math.Min(iStartLine, iTextLines - iClientLines));
          Invalidate();
      }
      protected override void OnPaint(PaintEventArgs pea)
      {
          Graphics grfx = pea.Graphics;

          grfx.DrawString(strAnnabelLee, Font, new SolidBrush(ForeColor),
                          0, -iStartLine * cyText);
      }
  }

Заметьте: программа проверяет, есть ли колесико мыши, и сообщает пользователю, если не может найти таковое. Я поместил эту проверку в Main, но это не единственный способ проверки условий, в которых программа не должна работать. В качестве альтернативы можно переопределить метод OnLoad класса Form и выполнять такую проверку при загрузке программы. Событие Load происходит после исполнения кода конструктора, но до того, как форма становится видимой на экране. Если программа определила, что не должна запускаться, можно вывести сообщение и вызвать метод Close, чтобы предотвратить появление ее (формы) на экране. Во время исполнения конструктора формы прервать выполнение программы и предотвратить вывод формы на экран нельзя, так как в этот момент не работают ни Close, ни статический метод Application.Exit.

В текст стихотворения, хранящийся в виде строковой переменной, внедрены символы перевода строки. Программа подсчитывает число строк во время исполнения конструктора формы и сохраняет результат в поле iTextLines. Конструктор также получает значение межстрочного интервала, вызывая метод GetHeight свойства формы Font. Возвращаемое методом значение заносится в поле cyText.

Завершающая часть инициализации состоит в исполнении метода OnResize. Первый раз конструктор должен вызвать этот метод явно, потом OnResize будет вызываться каждый раз, когда пользователь изменит размеры формы. OnResize использует значение cyText для расчета значения iClientLines, определяющего число строк, которое может вместить клиентская область.

Переменная iStartLine — это строка текста, которая должна появиться в верхней части клиентской области. При инициализации этой переменной присваивается 0. Метод OnMouseWheel определяет это значение при помощи вычислений, показанных мной выше.

Иногда программы, использующие прокрутку текста, пишут так, что если в ней полностью прокрутить текст вперед, то его последняя строка окажется в верхней части клиентской области. Но нет нужды позволять прокручивать текст так далеко — достаточно остановить последнюю строку у нижнего края клиентской области. Поэтому в методы OnMouseWheel и OnResize из программы PoePoem включены вычисления с использованием методов Math.Min и Math.Max, гарантирующие получение неотрицательного значения iStartLine, а также что при расчете этого значения будет учтено количество текста, вмещаемое клиентской областью. Если растянуть клиентскую область так, чтобы она вместила все стихотворение, то текст вовсе не будет прокручиваться.


netlib.narod.ru< Назад | Оглавление | Далее >

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