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

Пропавшая каретка

Элементы управления или формы, получающие вводимую с клавиатуры информацию, обычно как-то показывают, что они находятся в фокусе. Например, текст кнопки, находящейся в фокусе, обводится точечной линией. Элементы управления и формы, позволяющие вводить текст, обычно отмечают место появления следующего символа на экране короткой горизонтальной (вертикальной) линией или квадратиком. Этот индикатор, может быть, знаком вам под названием курсор, но в Windows правильнее называть его кареткой. Слово курсор зарезервировано для растровой картинки, отражающей положение указателя мыши на экране.

Если вы создадите элемент управления TextBox или RichTextBox (как это делается, я покажу в главе 18), то за формирование и вывод каретки будет отвечать он. Во многих случаях функциональности этих элементов управления вполне хватает программе. В частности, RichTextBox построен на основе того же элемента управления Windows, что и Microsoft WordPad, и обладает достаточно широкими возможностями.

Если же эти элементы управления не соответствуют вашим задачам и нужно написать собственный код для ввода текста, возникает небольшая проблема. Среди функций, которых нет в библиотеках классов Windows Forms, пожалуй, самым загадочным образом пропала каретка.

Боюсь, чтобы решить нашу проблему, снова придется писать неуправляемый код, копающийся в DLL Windows. Если вы захотите использовать мой класс Caret в своих программах, учтите, что он определяется в моем собственном пространстве имен. Он основан на API каретки Windows и начинается объявлением пяти внешних функций, расположенных в библиотеке User32.dll.

Caret.cs

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

  namespace Petzold.ProgrammingWindowsWithCSharp
  {
      class Caret
      {
          [DllImport("user32.dll")]
          public static extern int CreateCaret(IntPtr hwnd, IntPtr hbm, 
                                               int cx, int cy);
          [DllImport("user32.dll")]
          public static extern int DestroyCaret();

          [DllImport("user32.dll")]
          public static extern int SetCaretPos(int x, int y);

          [DllImport("user32.dll")]
          public static extern int ShowCaret(IntPtr hwnd);

          [DllImport("user32.dll")]
          public static extern int HideCaret(IntPtr hwnd);

          // Поля

          Control ctrl;
          Size    size;
          Point   ptPos;
          bool    bVisible;

          // Конструкторы

          // Конструктор по умолчанию недоступен
          private Caret()
          {
          }

          // Доступен только конструктор с аргументом Control

          public Caret(Control ctrl)
          {
              this.ctrl = ctrl;
              Position  = Point.Empty;
              Size      = new Size(1, ctrl.Font.Height);

              Control.GotFocus  += new EventHandler(ControlOnGotFocus);
              Control.LostFocus += new EventHandler(ControlOnLostFocus);

              // Если элемент управлениЯ имеет фокус, создаем каретку

              if (ctrl.Focused)
                  ControlOnGotFocus(ctrl, new EventArgs());
          }

          // Свойства

          public Control Control
          {
              get 
              {
                  return ctrl;
              }
          }

          public Size Size
          {
              get 
              {
                  return size;
              }
              set
              {
                  size = value;
              }
          }

          public Point Position
          {
              get
              {
                  return ptPos;
              }
              set
              {
                  ptPos = value;
                  SetCaretPos(ptPos.X, ptPos.Y);
              }
          }

          public bool Visibility
          {
              get
              {
                  return bVisible;
              }
              set
              {
                  if (bVisible = value)
                      ShowCaret(Control.Handle);
                  else
                      HideCaret(Control.Handle);
              }
          }

          // Методы

          public void Show()
          {
              Visibility = true;
          }

          public void Hide()
          {
              Visibility = false;
          }

          public void Dispose()
          {
              // Если элемент управления имеет фокус, уничтожаем каретку
              if (ctrl.Focused)
                  ControlOnLostFocus(ctrl, new EventArgs());

              Control.GotFocus  -= new EventHandler(ControlOnGotFocus);
              Control.LostFocus -= new EventHandler(ControlOnLostFocus);
          }

          // Обработчики событий

          void ControlOnGotFocus(object obj, EventArgs ea)
          {
              CreateCaret(Control.Handle, IntPtr.Zero, 
                          Size.Width, Size.Height);
              SetCaretPos(Position.X, Position.Y);
              Show();
          }

          void ControlOnLostFocus(object obj, EventArgs ea)
          {
              Hide();
              DestroyCaret();
          }
     }
}

Чтобы создать каретку в форме (или любом другом объекте, производном от Control), используйте конструктор:

  Caret caret = new Caret(form);

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


Свойства Caret



Тип Свойство Доступ Описание

Control Control Чтение Объект Control, с которым связана каретка
Size Size Чтение/запись Размер каретки в пикселах
Point Position Чтение/запись Положение каретки относительно начала координат формы
bool Visibility Чтение/запись Видимость каретки


В средах, функционирующих в текстовом режиме, каретка часто принимает вид символа подчеркивания или квадратика. Однако такие каретки не очень хорошо работают с текстом переменной ширины — здесь лучше использовать вертикальную линию. В общем случае программа, использующая класс Caret со шрифтом формы по умолчанию, может установить размер каретки так:

  caret.Size = new Size(2, Font.Height);

Свойство Position указывает позицию каретки относительно левого верхнего угла клиентской области.

Свойство Visibility позволяет прятать и снова показывать каретку При рисовании на форме каретку нужно каждый раз скрывать. Это надо делать до или после, но не во время события Paint! В качестве альтернативы свойству Visibility годятся методы Hide и Show. Dispose — единственный открытый метод, поддерживаемый классом Caret:


Методы Caret



Метод Описание

void Hide() Скрывает каретку
void Show() Показывает каретку
void Dispose() Деактивизирует каретку


Вызывать метод Dispose обычно не требуется. Он нужен лишь для того, чтобы прекратить ввод текста с клавиатуры в форму, осуществляемый с использованием каретки.

Caret — хороший пример класса, который должен подключить обработчики событий к форме, с которой он связан. Caret устанавливает обработчики событий GotFocus и LostFocus. Он создает каретку, когда форма получает фокус, и уничтожает ее, когда форма теряет фокус, согласно рекомендациям по обработке каретки в программировании Win32. Метод Dispose просто отключает обработчики событий, после чего каретка больше не создается.

Но имейте в виду, что форма, использующая класс Caret и самостоятельно переопределяющая его методы OnGotFocus и OnLostFocus, рискует отключить обработчики событий в Caret! Если пришлось переопределить эти методы, обязательно вызывайте методы из базового класса:

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

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

Методы OnGotFocus и OnLostFocus из базового класса вызывают установленные обработчики событий так же, как методы Caret.


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

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