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

Переключатели и групповые блоки

Когда-нибудь все забудут, откуда взялось название кнопок-переключателей (radio buttons, радиокнопки). Видите ли, раньше на автомагнитолах помещали ряд кнопок, каждую из которых можно было настроить на какую-нибудь радиостанцию. Чтобы выбрать станцию, надо было нажать на кнопку, при этом нажатая ранее кнопка отщелкивалась. Так как одновременно может быть нажата только одна кнопка, набор кнопок-переключателей всегда представляет набор взаимоисключающих возможностей.

От других элементов управления переключатели отличает то, что они всегда объединены в группы. Так как одновременно может быть отмечена только одна кнопка-переключатель, состояние одного переключателя влияет на другие. Если отметить одну кнопку, отметка с другой снимется. Перемещение с помощью клавиш тоже в некотором роде нестандартно. Внутри группы кнопок-переключателей клавиши-стрелки переводят фокус ввода с одной кнопки на другую. При изменении фокуса меняется также и отмеченная кнопка-переключатель. Клавиша Tab позволяет перейти от группы переключателей к следующему элементу управления. При переходе с помощью клавиши Tab к группе переключателей отмеченный переключатель получает фокус ввода.

К счастью, большинство деталей реализации этого интерфейса скрыто от вас. Все, что вам нужно сделать, — это для каждой группы переключателей создать элемент управления GroupBox и сделать его дочерним элементом формы. А потом сделать все объекты RadioButton в группе дочерними элементами GroupBox.

Сначала взглянем на класс RadioButton. Как и CheckBox, он содержит свойства Checked и AutoCheck:


Свойства RadioButton (выборочно)



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

bool Checked Чтение/запись По умолчанию равно false
bool AutoCheck Чтение/запись По умолчанию равно true


Свойство Checked определяет, отмечен ли переключатель (это обозначает точка внутри круга). Свойство AutoCheck, установленное в true, автоматизирует использование кнопок-переключателей. Как только пользователь щелкает по переключателю (или перемещает фокус ввода внутри группы), переключатели автоматически отмечаются/сбрасываются. Если свойству AutoCheck присвоить значение false придется установить обработчик события Click и отмечать/сбрасывать переключатели самостоятельно.

Кроме этих свойств, в RadioButton определены еще только два открытых свойства: Appearance и CheckAlign, работающие так же, как и в классе CheckBox.

Событие CheckedChanged вызывается каждый раз, когда состояние кнопки меняется либо пользователем, либо программно:


События RadioButton (выборочно)



Событие Метод Делегат Аргументы

CheckedChanged OnCheckedChanged EventHandler EventArgs


События CheckedChanged вызываются парно: одно для кнопки, становящейся отмеченной, и еще одно — для сбрасываемой кнопки. Их можно различить, проанализировав свойство Checked переключателя. Во время события CheckedChanged свойство Checked соответствует новому состоянию.

Класс GroupBox является потомком Control, но реализует только одно открытое свойство (FlatStyle) и не определяет дополнительных по сравнению с Control методов и событий.

Рассмотрим пример. В следующей программе рисуется эллипс, чей вид зависит от состояния восьми переключателей и одного флажка.

RadioButtons.cs

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

  class RadioButtons: Form
  {
      bool  bFillEllipse;
      Color colorEllipse;

      static void Main()
      {
          Application.Run(new RadioButtons());
      }
      RadioButtons()
      {
          Text = "Radio Buttons Demo";
          ResizeRedraw = true;

          string[] astrColor = { "Black", "Blue", "Green", "Cyan",
                                 "Red", "Magenta", "Yellow", "White"};

          GroupBox grpbox = new GroupBox();
          grpbox.Parent   = this;
          grpbox.Text     = "Color";
          grpbox.Location = new Point(Font.Height / 2, Font.Height / 2);
          grpbox.Size     = new Size(9 * Font.Height, 
                              (3 * astrColor.Length + 4) * Font.Height / 2);

          for (int i = 0; i < astrColor.Length; i++)
          {
              RadioButton radiobtn = new RadioButton();
              radiobtn.Parent      = grpbox;
              radiobtn.Text        = astrColor[i];
              radiobtn.Location    = new Point(Font.Height,
                                               3 * (i + 1) * Font.Height / 2);
              radiobtn.Size        = new Size(7 * Font.Height, 
                                              3 * Font.Height / 2);
              radiobtn.CheckedChanged += 
                              new EventHandler(RadioButtonOnCheckedChanged);
              if(i == 0)
                  radiobtn.Checked = true;
          }
          CheckBox chkbox = new CheckBox();
          chkbox.Parent   = this;
          chkbox.Text     = "Fill Ellipse";
          chkbox.Location = new Point(Font.Height, 
                              3 * (astrColor.Length + 2) * Font.Height / 2);
          chkbox.Size     = new Size(Font.Height * 7, 3 * Font.Height / 2);
          chkbox.CheckedChanged += 
                         new EventHandler(CheckBoxOnCheckedChanged);
      }
      void RadioButtonOnCheckedChanged(object obj, EventArgs ea)
      {
          RadioButton radiobtn = (RadioButton) obj;

          if(radiobtn.Checked)
          {
              colorEllipse = Color.FromName(radiobtn.Text);
              Invalidate(false);
          }
      }
      void CheckBoxOnCheckedChanged(object obj, EventArgs ea)
      {
          bFillEllipse = ((CheckBox)obj).Checked;
          Invalidate(false);
      }
      protected override void OnPaint(PaintEventArgs pea)
      {
          Graphics  grfx = pea.Graphics;
          Rectangle rect = new Rectangle(10 * Font.Height, 0,
                                         ClientSize.Width - 
                                             10 * Font.Height - 1,
                                         ClientSize.Height - 1);
          if(bFillEllipse)
              grfx.FillEllipse(new SolidBrush(colorEllipse), rect);
          else
              grfx.DrawEllipse(new Pen(colorEllipse), rect);
      }
  }

В начале конструктора определяется массив из 8 названий цветов. Все вертикальные координаты и размеры в программе вычисляются так, чтобы они вместили дополнительные названия цветов из этого массива, если это корректные названия цветов .NET Framework. (Однако ширина элементов управления недостаточна, чтобы вместить некоторые длинные названия.)

Сначала конструктор создает элемент управления GroupBox. Родительским элементом группового блока является форма. Затем конструктор создает 8 переключателей — дочерних элементов группового блока. Заметьте: в конце цикла for свойство Checked устанавливается в true для первой кнопки. Эта инструкция приводит к вызову RadioButtonOnCheckedChanged, в котором инициализируется поле colorEllipse. Конструктор завершается созданием элемента управления CheckBox — дочернего элемента формы.

Клавиатурный интерфейс работает так, как я и описывал. При использовании клавиш-стрелок для перемещения между переключателями кнопки вызывают метод RadioButtonOnCheckedChanged, который использует статический метод Соlor.FromName и преобразует текст кнопки в объект Color. Как этот метод, так и CheckBoxOnCheckedChanged делают недействительной клиентскую область, что приводит к вызову OnPaint, рисующего эллипс:


Рис. 12.17.


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

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