Шаг 57.
Библиотека OWL.
Создание управляющих элементов окна

    На этом шаге мы рассмотрим создание и использование элементов управления.

    Благодаря Resource Workshop размещение в диалоговом окне управляющих элементов является простым процессом. К сожалению Resource Workshop не может помочь, если вы захотите разместить управляющие элементы внутри окна другого типа. Для выполнения этой задачи вы должны задать не только указатель родительского окна управляющего элемента, но также и его точное расположение внутри окна. Определение положения управляющего элемента означает задание пробного набора координат, компилирование программы с целью увидеть, где на самом деле появляются управляющие элементы внутри окна, уточнение этих координат и затем перекомпилирование программы, чтобы убедиться, там ли оказался управляющий элемент, где он должен быть. Однако, когда вы установили управляющие элементы туда, куда вы и хотели, они выполняют точно такие же функции, что и в диалоговом окне. В следующем примере приведен текст программы, которая создает в родительском окне те же управляющие элементы, которые были включены в диалоговое окно предыдущей программы.

#include <owl\applicat.h>
#include <owl\framewin.h>
#include <owl\dialog.h>
#include <owl\radiobut.h>
#include <owl\edit.h>
#include <owl\listbox.h>
#include <owl\combobox.h>
#include <owl\scrollba.h>
#include <owl\groupbox.h>
#include <owl\dc.h>
#include <string.h>
#include <cstring.h>
#include "pr57_1.rc"
 
// Класс приложения.
class TApp: public TApplication
{
  public:
	 TApp():TApplication() {}
	 void InitMainWindow();
};

// Класс главного окна.
class TWndw : public  TFrameWindow
{
  public:
	 TWndw (TWindow *parent, const char far *title);
  protected:
         TEdit   *edit;
         TRadioButton *radio1, *radio2, *radio3;
         TListBox *listBox;
         TComboBox *comboBox;
         TCheckBox *check1, *check2, *check3;
         TScrollBar *scrollBar;

         void SetupWindow();
         void CmGetData();

         DECLARE_RESPONSE_TABLE(TWndw);
};

DEFINE_RESPONSE_TABLE1 (TWndw, TFrameWindow)
	  EV_COMMAND (CM_GETDATA, CmGetData),
END_RESPONSE_TABLE;

// TWndw::TWndw()
// Это конструктор главного окна.
TWndw::TWndw(TWindow *parent, const char far *title):
			 TFrameWindow (parent, title)
{
  // Допускает переход по клавише табуляции между
  // управляющими элементами. 
  EnableKBHandler();
  // Установить меню окна.
  AssignMenu(MENU_1);
  // Определить размеры и расположение окна. 
  Attr.X = 20;
  Attr.Y = 20;
  Attr.W = 600;
  Attr.H = 280;
  // Создать управляющие элементы в окне.
  new TStatic(this, -1, "Edit:", 42, 14, 50, 24, 5);
  edit = new TEdit(this, ID_EDIT, "Default", 40, 40, 100, 24, 15); 
  TGroupBox *groupBox1 = new TGroupBox(this, -1, "Check Boxes", 40, 75, 110, 125); 
  check1 = new TCheckBox(this, ID_CHECK1, "Check1", 52, 105, 68, 24, groupBox1); 
  check2 = new TCheckBox(this, ID_CHECK2, "Check2", 52, 132, 68, 24, groupBox1); 
  check3 = new TCheckBox(this, ID_CHECK3, "Check3", 52, 159, 68, 24, groupBox1); 
  TGroupBox *groupBox2 = new TGroupBox(this, -1, 
              "Radio Buttons", 184, 14, 160, 55); 
  radio1 = new TRadioButton(this, ID_RADIO1, "R1", 190, 35, 40, 24, groupBox2); 
  radio2 = new TRadioButton(this, ID_RADIO2, "R2", 240, 35, 40, 24, groupBox2); 
  radio3 = new TRadioButton(this, ID_RADIO3, "R3", 290, 35, 40, 24, groupBox2); 
  new TStatic (this, -1, "Scroll Bar:", 375, 14, 90, 24, 11);
  scrollBar = new TScrollBar(this, ID_SCROLLER, 375, 40, 200, 22, TRUE);
  new TStatic (this, -1, "List Box:", 175, 80, 80, 24, 9); 
  listBox = new TListBox (this, ID_LISTBOX, 175, 105, 150, 75);
  new TStatic (this, -1, "Combo Box:", 350, 80, 90, 24, 10); 
  comboBox = new TComboBox(this, ID_COMBOBOX, 
                     350, 105, 190, 100, CBS_DROPDOWNLIST, 30);
  new TButton(this, CM_GETDATA, "Get Data", 400, 150, 80, 50);
}

// TWndw::SetupWindow()
// Эта функция, переопределяющая функцию
// SetupWindow() базового класса, обеспечивает
// сервис по установке данного окна.
void TWndw::SetupWindow() 
{
  // Всегда вызывайте SetupWindow() базового класса.
  TFrameWindow::SetupWindow();
  // Определить начальное состояние управляющих элементов.
  radio1->Check(); 
  radio2->Uncheck(); 
  radio3->Uncheck(); 
  check1->Check(); 
  check2->Uncheck(); 
  check3->Uncheck(); 
  scrollBar->SetRange(0, 100); 
  scrollBar->SetPosition(50); 
  listBox->AddString("ListString1"); 
  listBox->AddString("ListString2"); 
  listBox->AddString("ListString3"); 
  listBox->AddString("ListString4"); 
  listBox->AddString("ListString5"); 
  listBox->AddString("ListString6"); 
  comboBox->AddString("ComboString1"); 
  comboBox->AddString("ComboString2"); 
  comboBox->AddString("ComboString3"); 
  comboBox->AddString("ComboString4"); 
  comboBox->AddString("ComboString5"); 
  comboBox->AddString("ComboString6");
  // Задать установки по умолчанию для окна 
  // списка и комбинированного окна. 
  listBox->SetSelIndex(0); 
  comboBox->SetSelIndex(0);
}


// TWndw::CmGetData()
// Эта функция реагирует на команду Get Data из 
// меню File, отображая данные, полученные от управляющих элементов окна. 
void TWndw::CmGetData()
{
  string data; 
  char s[100]; 
  int num;

  data = "EDIT CONTROL:\t";
  edit->GetText(s, sizeof(s));
  data += s;
  data += "\r\n";
  if   (radio1->GetCheck() == BF_CHECKED) num = 1; 
  else   if   (radio2->GetCheck() == BF_CHECKED) num = 2; 
         else num =  3;
  data += "RADIO BUTTON:\t";
  wsprintf(s, "Radio button #%d chosen\r\n", num); 
  data += s;
  num = scrollBar->GetPosition(); 
  wsprintf(s, "SCROLL BAR:\t%d\r\n", num); 
  data += s;
  data += "CHECK BOX 1:\t"; 
  if (check1->GetCheck() == BF_CHECKED) data += "Chosen\r\n"; 
  else  data += "Not chosen\r\n";
  data += "CHECK BOX 2:\t"; 
  if (check2->GetCheck() == BF_CHECKED) data += "Chosen\r\n"; 
  else data += "Not chosen\r\n";
  data += "CHECK BOX 3:\t";
  if (check3->GetCheck() == BF_CHECKED) data += "Chosen\r\n"; 
  else data += "Not chosen\r\n";
  data += "LIST BOX:\t"; 
  listBox->GetSelString(s, sizeof(s)); 
  data += s;
  data += "\r\nCOMBO BOX:\t"; 
  comboBox->GetSelString(s, sizeof(s)); 
  data += s;
  MessageBox (data.c_str(), "Get Data", MB_OK);
}


void TApp::InitMainWindow()
{
  TFrameWindow *wndw = new TWndw (0,"Управляющие элементы 2");
  SetMainWindow(wndw);
}

int OwlMain(int,char *[])
{
  return TApp().Run();
}

    Файл ресурсов:

#ifndef WORKSHOP_INVOKED
#include "windows.h"
#endif

#include <owl\window.rh>

#define MENU_1      100 
#define CM_GETDATA  200
#define ID_EDIT     101
#define ID_RADIO1   102
#define ID_RADIO2   103
#define ID_RADIO3   104
#define ID_SCROLLER 105
#define ID_CHECK1   106
#define ID_CHECK2   107
#define ID_CHECK3   108
#define ID_LISTBOX  109
#define ID_COMBOBOX 110

#ifdef RC_INVOKED


MENU_1 MENU
{
  POPUP "&File"
  {
          MENUITEM "&Get Data...", CM_GETDATA 
          MENUITEM SEPARATOR 
	  MENUITEM "E&xit", CM_EXIT
  }
}

#endif
Текст этого приложения можно взять здесь.

    Когда вы запустите эту программу, вы увидите окно, изображенное на рисунке 1.


Рис.1. Результат работы приложения

    В этом окне содержатся все управляющие элементы из диалогового окна предыдущей программы, а также дополнительная кнопка, которая является отражением команды Get Data меню File. С помощью этих управляющих элементов задайте такие данные, какие вам нравятся, а затем выберите в меню File команду Get Data или нажмите кнопку с соответствующей надписью. Появится окно сообщений, показанное на рисунке 2, в котором изображены те данные, которые выбраны вами в управляющих элементах окна.


Рис.2. Окно сообщений Get Data

    Все начинается в объявлении класса главного окна:

class TWndw : public  TFrameWindow
{
  public:
	 TWndw (TWindow *parent, const char far *title);
  protected:
         TEdit   *edit;
         TRadioButton *radio1, *radio2, *radio3;
         TListBox *listBox;
         TComboBox *comboBox;
         TCheckBox *check1, *check2, *check3;
         TScrollBar *scrollBar;

         void SetupWindow();
         void CmGetData();

         DECLARE_RESPONSE_TABLE(TWndw);
};

DEFINE_RESPONSE_TABLE1 (TWndw, TFrameWindow)
	  EV_COMMAND (CM_GETDATA, CmGetData),
END_RESPONSE_TABLE;

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

    В классе также содержится обычный конструктор и две функции-члена класса SetupWindow() и CmGetData(). Функция CmGetData() является функцией отклика на команду CM_GETDATA, которая генерируется, когда пользователь выбирает команду Get Data из меню File или когда он выбирает кнопку Get Data.

    Создание всех управлящих элементов окна обеспечивается в конструкторе окна. Сначала конструктор активизирует оконный драйвер клавиатуры, который позволяет пользователю переключаться между управлящими элементами окна с помощью клавиши Tab:

  EnableKBHandler();

    Эта функция унаследована из OWL-класса TFrameWindow. После включения управления клавиатурой программа устанавливает меню окна, а также задает размеры и расположение окна. Затем программа начинает создавать управляющие элементы окна с элементами TStatic, которые помечают область ввода в данном окне.

  new TStatic(this, -1, "Edit:", 42, 14, 50, 24, 5);

    В конструкторе TStatic в качестве аргументов используются указатель на родительское окно, идентификатор управляющего элемента, строка, появляющаяся в управляющем элементе TStatic, координаты х и у элемента (относительно левого верхнего угла окна), ширина и высота управляющего элемента и длина строки. (Этот конструктор, а также конструкторы всех других элементов управления, которые будут описываться ниже, в качестве последнего аргумента еще имеют объект TLibId. OWL присваивает этому аргументу значение, принятое по умолчанию.)

    Область ввода окна создается аналогично:

  edit = new TEdit(this, ID_EDIT, "Default", 40, 40, 100, 24, 15); 

    В конструкторе TEdit в качестве аргументов используются указатель на родительское окно, идентификатор управляющего элемента, строка, установленная по умолчанию, которая появляется в области ввода (если таковая имеется), координаты х и у управляющего элемента, ширина и высота окна и максимальная длина управляющего элемента (в символах).

    В главном окне программы помечаемые кнопки объединены в групповом окне:

  TGroupBox *groupBox1 = new TGroupBox(this, -1, "Check Boxes", 40, 75, 110, 125); 

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

    После построения группового окна программа создает помечаемые кнопки, которые будут размещаться внутри этого окна:

  check1 = new TCheckBox(this, ID_CHECK1, "Check1", 52, 105, 68, 24, groupBox1); 
  check2 = new TCheckBox(this, ID_CHECK2, "Check2", 52, 132, 68, 24, groupBox1); 
  check3 = new TCheckBox(this, ID_CHECK3, "Check3", 52, 159, 68, 24, groupBox1); 

    Аргументами конструктора TCheckBox являются указатель на родительское окно, идентификатор управляющего элемента, текст, следующий после управляющего элемента, координаты помечаемой кнопки, ширина и высота помечаемой кнопки и указатель на групповое окно.

    Радиокнопки окна также объединены в групповое окно, которое программа создает после помечаемых кнопок.

  TGroupBox *groupBox2 = new TGroupBox(this, -1, 
             "Radio Buttons", 184, 14, 160, 55); 

    Затем строятся радиокнопки.

  radio1 = new TRadioButton(this, ID_RADIO1, "R1", 190, 35, 40, 24, groupBox2); 
  radio2 = new TRadioButton(this, ID_RADIO2, "R2", 240, 35, 40, 24, groupBox2); 
  radio3 = new TRadioButton(this, ID_RADIO3, "R3", 290, 35, 40, 24, groupBox2); 

    Аргументами конструктора TRadioButton в данном варианте являются указатель на родительское окно, идентификатор управляющего элемента, его координаты х и у, ширина и высота, указатель на групповое окно.

    Следующей задачей конструктора TWndw является построение статического текста, который является меткой для линейки прокрутки:

  new TStatic (this, -1, "Scroll Bar:", 375, 14, 90, 24, 11);

    Затем программа строит саму линейку прокрутки:

  scrollBar = new TScrollBar(this, ID_SCROLLER, 375, 40, 200, 22, TRUE);

    Аргументами конструктора TScrollBar являются указатель на родительское окно, идентификатор управляющего элемента, координаты х и у, ширина и высота окна, а также булево значение, указывающее на горизонтальное (TRUE) или вертикальное (FALSE) положение линейки прокрутки. Затем программа создает статический текст для обозначения окна списка и само окно списка:

  new TStatic (this, -1, "List Box:", 175, 80, 80, 24, 9); 
  listBox = new TListBox (this, ID_LISTBOX, 175, 105, 150, 75);

    Аргументами конструктора TListBox, как и у большинства конструкторов управляющих элементов окна, являются указатель на родительское окно, идентификатор управляющего элемента, координаты х и у, ширина и высота управляющего элемента.

    На следующем этапе программа должна построить комбинированное окно и текст метки для этого окна:

  new TStatic (this, -1, "Combo Box:", 350, 80, 90, 24, 10); 
  comboBox = new TComboBox(this, ID_COMBOBOX, 
                350, 105, 190, 100, CBS_DROPDOWNLIST, 30);

    Аргументами конструктора TComboBox являются указатель на родительское окно, идентификатор управляющего элемента, координаты х и у, ширина и высота, флаги стиля окна и максимальная длина редактируемой области (в символах). Имеются следующие стили: CBS_SIMPLE, CBS_DROPDOWN, CBS_DROPDOWNLIST, CBS_OWNERDRAWFIXED и CBS_QWNERDRAWVARIABLE.


    Замечание. Управляющие элементы - это не что иное, как специальные окна, и как таковые имеют стиль, который определяет способ появления и функционирования окон. OWL автоматически задает стиль окна управляющего элемента, поэтому он выглядит и функционирует так, как вам это нужно. Однако управляющие элементы имеют дополнительные стили, которые отсутствуют у "обычных" окон. В Windows задаются константы для этих дополнительных стилей. Например, такой управляющий элемент как область ввода имеет следующие стили: ES_LEFT, при котором текст выравнивается влево, ES_CENTER, при котором текст центрируется, ES_LOWERCASE, при котором все символы текста - строчные литеры, и ES_AUTOVSCROLL, при котором обеспечивается вертикальная прокрутка текста по мере набора символов пользователем. (Это всего лишь немногие из возможных стилей области ввода.) Информация о разнообразных стилях, которые можно применять для каждого из управляющих элементов окна приведена в справочном руководстве по программированию в среде Windows.

    Наконец, программа строит кнопку команды Get Data:

  new TButton(this, CM_GETDATA, "Get Data", 400, 150, 80, 50);

    Аргументами конструктора TButton являются указатель на родительское окно, идентификатор кнопки, текст кнопки, координаты положения кнопки х и у и ширина и высота кнопки.


    Замечание. Все конструкторы объектов управляющих элементов в OWL являются перегружаемыми и имеют две формы. Конструкторы одной формы позволяют вам строить объект управления из объекта в диалоговом окне, а конструкторы другой формы позволяют вам строить эти объекты для окон другого типа, т.е. не являющихся диалоговыми.

    После построения управляющих элементов окна их надо инициализировать, чтобы обеспечить их надлежащее отображение. До полного построения управляющих элементов нельзя обеспечить их полную инициализацию, поэтому весьма уместно привлечь для выполнения этой задачи функцию SetupWindow(). Как всегда, первое, что должна сделать программа в SetupWindow() - это вызвать функцию SetupWindow() базового класса. Отказ вызова ТFrameWindow::SetupWindow() в данной программе приведет к потере управляющих элементов, так как OWL создает в SetupWindow() дочерние окна (содержащие эти элементы управления), в которых установлен режим автоматического создания.

    После вызова SetupWindow() из базового класса программа инициализирует радиокнопки и помечаемые кнопки, вызывая их функции-члены Check() и Uncheck():

  radio1->Check(); 
  radio2->Uncheck(); 
  radio3->Uncheck(); 
  check1->Check(); 
  check2->Uncheck(); 
  check3->Uncheck(); 

    Класс TRadioButton наследует свои функции-члены, включая Check() и Uncheck(), из TCheckBox, базового класса TRadioButton. Функция-член Check() помещает в кнопку маркер-пометку, а функция-член Uncheck() убирает его. Ни одна из этих функций не требует аргументов.

    Остальные функции-члены классов TCheckBox и TRadioBox включают функцию GetState(), которая определяет, выбрана ли кнопка, находится ли она в фокусе ввода и высвечена ли она; функцию SetCheck (WORD Check), которая в зависимости от значения Check устанавливает кнопку как выбранную, как невыбранную или блокирует ее; функцию SetState (UNIT state), которая в зависимости от значения state устанавливает кнопку как выбранную или невыбранную, высвечивает кнопку и устанавливает фокус; функцию SetStyle (UNIT style, BOOL redraw), которая преобразует стиль кнопки в стиль типа style; и функцию Toggle(), которая осуществляет переключения состояний кнопки в выбранное, невыбранное или блокирует (окрашивает в серый цвет).

    На следующем этапе инициализируется линейка прокрутки:

  scrollBar->SetRange(0, 100); 
  scrollBar->SetPosition(50); 

    Как вам известно, функция SetRange() устанавливает минимальный и максимальный диапазон линейки прокрутки. Функция-член SetPosition() класса TScrollBar устанавливает положение ползунка в линейке прокрутки. Ее единственным аргументом является положение указателя (thumb), значение которого должно находиться в пределах выбранного диапазона. Остальные функции-члены класса TScrollBar включают функцию GetPosition() и функцию GetRange (int &min, int &max), которые возвращают положение и диапазон линейки прокрутки, соответственно.

    Для добавления строк в окно списка и комбинированное окно программа вызывает функцию-член AddString() классов TListBox или TComboBox:

  listBox->AddString("ListString1"); 
  listBox->AddString("ListString2"); 
  listBox->AddString("ListString3"); 
  listBox->AddString("ListString4"); 
  listBox->AddString("ListString5"); 
  listBox->AddString("ListString6"); 
  comboBox->AddString("ComboString1"); 
  comboBox->AddString("ComboString2"); 
  comboBox->AddString("ComboString3"); 
  comboBox->AddString("ComboString4"); 
  comboBox->AddString("ComboString5"); 
  comboBox->AddString("ComboString6");

    Единственным аргументом функции AddString() является строка, которую вы хотите добавить в окно списка или комбинированное окно.

    Последним этапом инициализации окна списка или комбинированного окна является установка принимаемых по умолчанию значений с помощью функции SetSelIndex():

  listBox->SetSelIndex(0); 
  comboBox->SetSelIndex(0);

    Выше вы ознакомились с функциями-членами классов TListBox и TComboBox. Остальными функциями-членами этих двух классов являются ClearList(), которая выполняет очистку списка в окне; DeleteString(int index), которая удаляет строку с заданным относительно нуля индексом; функция GetCount(), которая возвращает количество пунктов в списке; функция SetSelIndex(), которая возвращает индекс текущего выбранного пункта; функция GetString(char far *str, int index), которая вставляет строку, содержащуюся в переменной str в список, в позицию, указанную переменной index.

    После построения управляющих элементов окна в конструкторе главного окна и их инициализации в SetupWindow(), на экране появляется главное окно, причем все его управляющие элементы готовы к работе. Теперь пользователь может обращаться с управляющими элементами так, как он считает нужным. Когда пользователь выбирает команду Get Data из меню File, на экран выводятся те данные, которые были им введены в управляющие элементы. Эта задача выполняется в функции CmGetData(), которую OWL вызывает после получения командного сообщения CM_GETDATA.

    Функция CmGetData() извлекает данные из каждого управляющего элемента окна и преобразует эти данные таким образом, чтобы построить текстовую строку, которую программа отображает в стандартном окне сообщений Windows. Чтобы выбрать данные из области ввода, программа вызывает функцию-член этого управляющего элемента GetText():

  edit->GetText(s, sizeof(s));

    Аргументами этой функции, которую TEdit наследует от TStatic, являются адрес символьного массива, по которому надо поместить текст, и длина этого массива.

    Чтобы получить состояние радиокнопок и помечаемых кнопок, программа вызывает функцию-член GetCheck() управляющего элемента:

    radio1->GetCheck();

    Функция GetCheck() возвращает значение BF_CHECKED, BF_UNCHECKED или BF_GRAYED, в зависимости от текущего состояния кнопки.

    Текущее состояние линейки прокрутки программа получает, вызывая соответствующую функцию GetPosition() линейки прокрутки:

  num = scrollBar->GetPosition(); 

    Наконец, программа возвращает выбранные строки из окон списков и комбинированных окон, вызывая функцию-член GetSelString() объектов этих управляющих элементов:

  comboBox->GetSelString(s, sizeof(s)); 

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

    Со следующего шага мы начнем рассматривать создание панелей инструментов.




Предыдущий шаг Содержание Следующий шаг