Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Теллес М. - Borland C++ Builder. Библиотека программиста - 1998

.pdf
Скачиваний:
767
Добавлен:
13.08.2013
Размер:
4.35 Mб
Скачать

Borland C++ Builder (+CD). Библиотека программиста 91

TColorDialog *ColorDialog1; TMainMenu *MainMenu1; TMenuItem *Display1; TMenuItem *ChangeFont1; TMenuItem *ChangeColor1;

private: // User declarations Tfont *FpFont;

TCOlor *FcColor; Graphics::TBitmap *Fbmp1; Graphics::TBitmap *Fbmp2; public: // User declarations

virtual __fastcall TForm1(TComponent* Owner); virtual __fastcall ~TForm1(void);

void SetListBoxItems(void);

}; //---------------------------------------------------------

extern TForm1 *Form1; //---------------------------------------------------------

#endif

В этом примере мы используем парочку вещей, которых раньше мы не использовали. Во-первых, указатель на объект TFont будет использован для сохранения шрифта, который мы будем применять к элементам списка. Этот объект является наследием HFONT Windows и содержит много методов для работы с изображением текста. К счастью, нам не нужно много методов для работы со шрифтами, так как в системе CBuilder со шрифтами легко иметь дело. Объект font будет

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

Класс TFontDialog в CBuilder позволяет пользователю выбирать все атрибуты шрифта. Пользователь может выбирать имена шрифтов, размеры, атрибуты (жирный, курсив, ...) для текста и даже посмотреть пример отображения текста выбранным шрифтом. Лучшая сторона шрифтового диалога в том, что вам ничего не нужно с ним делать. Только отобразить окно диалога, позволить пользователю выбрать в нем шрифт и его атрибуты, а потом получить новый объект TFont из диалога, когда тот закроется. Это огромное улучшение по сравнению с более ранними системами, в которых требовалось не только изобразить окно диалога, но также и собрать шрифт из частей, выбранных в окне диалога.

Объект TColor — очень простой объект (на самом деле это просто число), который содержит определения цвета в Windows. Цвета в Windows делятся на две дискретные категории: реальные цвета и относительные цвета. Реальные цвета, представленные через значения RGB (Red, Green, Blue: красный, зеленый, синий), часто используются для прямого задания цвета для изображения. В системе CBuilder вам не обязательно напрямую связываться с RGB-значениями, так как CBuilder предоставляет для этого случая константы, как например clRed (красный) или clBlue (синий).

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

Borland C++ Builder (+CD). Библиотека программиста 92

схеме. В конце концов, вы должны позволить пользователю изменять цвета, которые вы выбрали для своего приложения, во время работы программы.

Класс TColorDialog в CBuilder предоставляет средства для того, чтобы пользователь мог менять цвета. Построенный на стандартном диалоге Windows 95/NT Color Dialog, он позволяет или выбрать один из предопределенных цветов, или определить какой-либо новый. Вам не нужно волноваться на эту тему. Вы просто отображаете окно диалога, позволяя пользователю выбрать подходящий цвет, а затем используете значение цвета, выбранное пользователем. Каждый раз, когда вы решаете использовать нестандартный цвет в вашем приложении, подумайте, стоит ли разрешать его изменять. Это существенно для таких вещей, как прорисованный вручную список, который изображает текст элемента выбранным цветом.

Мы добавили все, что нужно; пора время начинать писать код для формы. Давайте начнем с конструктора формы. Вот код, который нужно добавить в конструктор:

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{

FcColor = clBlack; FpFont = NULL;

// Создаем растровые изображения

Fbmp1 = new Graphics::TBitmap; Fbmp1->LoadFromFile( "d:\\Cbuilder\\Cbuilder\\images\\icons\\earth16.bmp"); Fbmp2 = new Graphics::TBitmap; Fbmp2->LoadFromFile( "d:\\Cbuilder\\Cbuilder\\images\\icons\\ship16.bmp");

}

В первую очередь код присваивает свойствам списка шрифт и цвет некоторые значения по умолчанию. Мы будем использовать объект FcColor для хранения цвета для отображения текста, FpFont — для шрифта. По умолчанию мы берем черный цвет для текста. Шрифт будет установлен в NULL, что будет означать в нашей программе, что пользователь не выбрал никакого шрифта. Как и все нормальные компоненты, область прорисовки (canvas) списка имеет значение для шрифта по умолчанию и будет его использовать, если мы не зададим шрифт во время работы программы.

Реализация меню в форме

Когда мы все добавили и проинициализировали, время вернуться к началам. Выберите главное меню формы и добавьте в него два пункта. Первы пункт должен иметь заголовок «Change &Font» («Изменить Шрифт»). Этот пункт будет использован для вызова окна диалога шрифтов и получения нового шрифта от пользователя. Второй пункт должен иметь заголовок «Change &Color» («Изменит Цвет»). Аналогично, этот пункт используется для отображения окна диалога выбора цвета и получения из него нового цвета, выбранного пользователем.

Добавьте обработчик для команды Change &Font. В обработчик внесите следующий код:

void __fastcall TForm1::ChangeFont1Click(TObject *Sender)

{

if ( FontDialog1->Execute() )

Borland C++ Builder (+CD). Библиотека программиста 93

{

FpFont = FontDialog1->Font; SetListBoxItems();

}

}

Как видите, обработчик очень прост. Метод диалога Execute (выполнить) возвратит true (истина), если пользователь сделает выбор и нажмет в окне диалога кнопку OK. Если же пользователь нажмет на кнопку Cancel (отменить), то метод Execute вернет false (ложь). Выражения языка C++ if ( FontDialog1->Execute() ) — это на самом деле сокращение от более полного выражения:

if ( FontDialog1->Execute() == true )

{

Как видите, код в фигурных скобках запустится, только если пользователь что-нибудь выберет и нажмет на кнопку OK. Иначе возвращаемое значение от метода Execute будет равно false и код не выполнится.

До функции SetListBoxItems мы доберемся через пару минут. Сейчас давайте взглянем на код, изменяющий цвет. Обработка команды меню Change & Color очень похожа на обработку команды Change &Font. Создайте обработчик для команды меню Change &Color и добавьте в него следующий код (оставьте название обработчика по умолчанию, ChangeColor1Click):

void __fastcall TForm1::ChangeColor1Click(TObject *Sender)

{

if ( ColorDialog1->Execute() )

{

FcColor = ColorDialog1->Color; SetListBoxItems();

}

}

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

Когда пользователь выбрал новый цвет, мы сохраняем его в переменной класса формы FcColor и переустанавливаем элементы списка.

Зачем нам нужно переустанавливать элементы списка?

Вы могли бы подумать, что нам достаточно сообщить списку, что его изображение устарело и тогда он сам перерисуется, и вы были бы правы. Проблема в том, что список Windows слишком умен. Как только элемент занесен в список и установлена его высота, эта информация сохраняется в самом списке. Список не изменит эту информацию, даже если его очень хорошо об этом попросить. В результате, когда пользователь выбирает новый шрифт для списка, высота которого отличается от старого, список, не зная об этом, не станет перестраивать элементы. Изменения происходят один раз: когда элемент добавляется в список. Мы используем факт, что список перетряхнет себя при добавлении элементов. Мы будем просто убирать все существующие элементы в списке, переустанавливать шрифт и измерять высоту элементов, уже используя новый шрифт. Такой подход, однако, подразумевает знание того, что за элементы в списке и какие атрибуты с ними ассоциированы.

Borland C++ Builder (+CD). Библиотека программиста 94

Если бы вы создавали список общего назначения, вам, вероятно, нужно было бы держать четыре отдельных массива объектов в вашем компоненте. Первый содержал бы текст элемента, второй растровый рисунок, связанный с этим элементом. Учтите, что указатели на рисунки (bitmap) могут быть равны NULL и их необязательно устанавливать для всех элементов. Третий массив содержал бы цвета, связанные с элементами, которые должны были быть использованы при прорисовке элемента в списке. Последний (четвертый) массив использовался бы для хранения шрифтов, связанных с элементами, причем опять же значения могут быть не установлены (NULL) и в этом случае не применяются. Лучше, чем держать четыре массива (которые должны быть синхронизированы друг с другом при добавлении и удалении элементов), создать свой объект C++, в котором бы хранились эти атрибуты элемента. Вот такая мысль на будущее.

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

void TForm1::SetListBoxItems(void)

{

ListBox1->Clear();

// Добавить элементы в список

ListBox1->Items->AddObject( "Земля", Fbmp1); ListBox1->Items->AddObject( "Корабль", Fbmp2);

}

Ничего ужасно сложного в этой процедуре нет. Первым делом она удаляет все существующие элементы в списке, вызывая метод Clear объекта список (TListBox). Затем два элемента добавляются в список. Если вы никогда раньше не работали с TListBox и при этом знакомы с нормальным способом ассоциирования данных в программе с элементами списка, то вас ждет сюрприз. Метод AddObject класса TListBox позволяет программисту добавлять и текст, и ассоциированные с ним данные вместе. Второй параметр функции, в нашем случае растровый рисунок, является нетипизированным объектом. Вы можете передавать туда все, что угодно, если только вы сможете это потом правильно интерпретировать. Как вы увидите, когда мы дойдем до кода прорисовки списка, нам необходимо хранить такой же указатель (или как минимум унаследованный от общего предка), чтобы эффективно работать с такими данными.

Обработка измерения элемента

Вы, может быть, помните, что мы сделали список переменного owner-draw (ручной прорисовки) типа. Это заставит систему Windows посылать списку сообщение WM_MEASEUREITEM. CBuilder затем перенаправит это сообщение в обработчик MeasureItem для списка, который в свою очередь вызовет обработчик MeasureItem для родительского окна и для формы, если такие обработчики существуют. Так как мы создали обработчик события MeasureItem, то пора теперь его реализовать. Добавьте следующий код в обработчик события MeasureItem в исходном файле формы (Unit1.cpp):

void __fastcall TForm1::MeasureItem(TWinControl *Control, int Index,int &Height)

{

if ( FpFont ) ListBox1->Canvas->Font = FpFont;

// Получить высоту шрифта

Height = ListBox1->Canvas->TextHeight("M");

Borland C++ Builder (+CD). Библиотека программиста 95

}

В этом методе мы сначала проверяем, выбрал ли пользователь шрифт для списка. Если это так, то свойству Font (шрифт) свойства Canvas списка присваивается это значение. Иначе свойство Font списка будет содержать значение шрифта по умолчанию в системе. Закончив с этим, мы используем метод TextHeight для вычисления высоты строки. Так как все символы в строке одинакового шрифта, а Windows поддерживает шрифты только с одинаковой высотой, то мы можем брать высоту любого символа. Прописная M хорошо подходит для этого, так как во- первых она хорошо смотрится в одиночестве, а кроме того M и W — самые широкие символы в любом шрифте. Вас, наверное, интересует, что стало со старым шрифтом (как объектом), который был связан со значением шрифта для свойства списка Canvas. В других системах вам пришлось бы получить этот старый шрифт, связанный с Canvas, затем удалить его, после чего установить новое значение. Тогда вам бы еще пришлось побеспокоиться о том, использовался ли этот объект еще где-либо в системе; если да, то программа бы рухнула при попытке обратиться к этому шрифту где-либо в другом месте. Не мучайтесь, CBuilder не дает вам напрямую изменять свойство Font в операции присваивания. Вместо этого вы заставляете систему вызвать метод Set для свойства Font объекта Canvas. Этот метод Set автоматически освободит объект Font, если это нужно, сберегая вам тем самым нервы и время. Это еще одна приятная вещь из так называемых расширений языка.

Рисуем элементы

Наконец-то настало время заняться самой прорисовкой элементов на экране. Как вы помните, мы добавляли метод DrawItem как обработчик события DrawItem в списке для этой работы. Сам список не волнует, что вы рисуете и как вы это делаете. Вместо этого список занимается управлением выборкой элементов, связью определенных пользователем (программистом)

объектов с элементами списка и обработкой выбора с помощью клавиатуры от конечного пользователя. С точки зрения программирования под Windows список является замечательным примером объектно-ориентированного дизайна системы.

Вот полный код обработчик события DrawItem. Добавьте его в обложку метода DrawItem, которую CBuilder сгенерировал в исходном файле Unit1.cpp:

void __fastcall TForm1::DrawItem(TWinControl *Control, int Index, TRect &Rect, TOwnerDrawState State)

{

Graphics::TBitmap *pic = (Graphics::TBitmap *) ListBox1->Items->Objects[Index];

if ( pic )

{

ListBox1->Canvas->Draw(Rect.Left, Rect.Top, pic); Rect.Left += pic->Width + 5;

}

//Если пользователь выбрал шрифт, использовать его if ( FpFont != NULL )

ListBox1->Canvas->Font = FpFont;

//Установить выбранный пользователем цвет

ListBox1->Canvas->Brush->Color = FcColor;

ListBox1->Canvas->TextRect(Rect, Rect.Left, Rect.Top,

Borland C++ Builder (+CD). Библиотека программиста 96

ListBox1->Items->Strings[ Index ].c_str() );

}

Первый шаг нарисовать растровое изображение в левой части области, отведенной для элемента списка. Областью управляет список, а нам она передается в виде параметра функции Rect. Параметр функции Control — управляющий элемент, для которого мы рисуем. Мы уже и так знаем, что это за объект (у нас в форме только один список), так что мы можем использовать свойство Canvas нашего объекта. Класс TControl не содержит свойства Canvas, так что нам пришлось бы приводить объект Control к объекту типа TListBox, которым он, собственно, и является, перед тем, как мы смогли бы его использовать. Так что этот шаг просто опустили.

Как всегда, прорисовка изображения это задача грамотного расположения его во внутренней области (canvas). У нас уже есть прямоугольник (rectangle), представляющий позицию области для этого элемента списка, так что задача сводится к использованию координат верхнего левого угла этого прямоугольника. Потом мы добавляем к горизонтальной координате ширину изображения и еще пять пикселов для зазора, чтобы текст не стоял вплотную к изображению.

Если пользователь выбрал шрифт в форме для использования в списке, то мы передаем его в свойство Canvas. Точно также и цвет элемента устанавливается во внутреннее значение FcColor. И, наконец, вызывается метод TextRect, который прорисовывает текст во внутренней области списка. Заметьте использование свойства Strings для получения текста элемента перед его прорисовкой. Объект Canvas автоматически будет использовать нужные шрифт и цвет, которые мы установили, в методе TextRect, так что это все, что необходимо для прорисовки элемента.

Уточняем детали

Осталось всего парочка деталей, с которыми нужно покончить перед тем, как мы сможем скомпилировать и запустить приложение. Во-первых, нужно добавить данные в список с самого начала. Чтобы с этим разобраться, создайте обработчик события FormCreate и добавьте в него код:

void __fastcall TForm1::FormCreate(TObject *Sender)

{

SetListBoxItems();

}

И, наконец, добавьте деструктор для класса формы. Здесь мы делаем последнюю подчистку в классе, после чего форма исчезает. Нам нужно освободить память, выделенную под растровые рисунки (bitmaps) в конструкторе класса. Вот полная реализация деструктора класса, которую вам нужно внести в исходный файл Unit1.cpp:

__fastcall TForm1::~TForm1(void)

{

// Удалить из памяти растровые рисунки delete Fbmp1;

delete Fbmp2;

}

Скомпилируйте и запустите приложение. Вы увидите то, что указано на рис. 4.11. Выберите новый шрифт, выбрав команду Change &Font из меню и сделайте его больше, чем предыдущий. Нажмите на OK в окне диалога выбора шрифта и проследите изменения в изображении. Повторите тест, используя новый цвет из окна диалога выбора цвета (выбрав команду меню Change &Color). Когда вы закончите тестирование, сядьте спокойно и поразитесь простоте ручной прорисовки списков в CBuilder.

Borland C++ Builder (+CD). Библиотека программиста 97

Рис. 4.11. Новый список с ручной прорисовкой в действии

Исследуем странички

Следующая область в нашей экскурсии по VCL — страничные управляющие элементы (tab controls). Страничные управляющие элементы, или записные книжки, как их часто называют,

являются способом отобразить большое количество связанной информации в маленьком пространстве. Такие управляющие элементы впервые появились в Windows 3.1, но использовались не очень часто, пока корпорация Microsoft не начала использовать их в своих приложениях (в основном Word). Страничный управляющий элемент это метафорическая записная книжка с закладками, которая на одном и том же пространстве содержит множество диалоговых страниц. Когда страница (tab) выбирается, то диалог, относящийся к этой странице, становится видимым, а предыдущий невидимым. К счастью, с появлением новых компонентов больше не нужно знать, как работает вся эта подсистема; нужно знать, что можно делать с помощью этой технологии. Короче, страничные управляющие элементы прекрасный пример работы компонентной технологии в мире Windows.

Замечание

Исходный код для программы примера страничного диалога находится в каталоге Chapter4\Tabs на прилагаемом компакт-диске.

Простейший способ использовать странички в страничном диалоге (tab dialog). Это также и самый естественный способ их использования. Вообще-то странички могут появляться и в главных окнах программ, но это не типично для большинства приложений. Может, в будущем что-то и изменится, но пока вы можете считать страничный диалог стандартом. CBuilder позволяет действительно очень просто создавать страничные диалоги, которые вы потом можете модифицировать по своему вкусу. Это первое приближение, с которого мы начнем работу. Для изначальной генерации страничного диалога вы используете репозиторий (Repository), создавая новый диалог. Выберите File ä New из главного меню в CBuilder. Выберите закладку Dialogs, найдите элемент Tab Dialog (страничный диалог) и щелкните на нем дважды. CBuilder сгенерирует новый страничный диалог и добавит его к проекту. Каким образом CBuilder генерирует новый файл и добавляет его к проекту, мы разберем ниже в этой книге.

Форма страничного диалога по умолчанию называется TPagesDlg. Давайте взглянем на заголовочный файл формы и посмотрим, что же именно за вещи составляют страничный диалог:

Borland C++ Builder (+CD). Библиотека программиста 98

//-------------------------------------------------------

#ifndef Unit2H #define Unit2H

//-------------------------------------------------------

#include <vcl\ExtCtrls.hpp> #include <vcl\ComCtrls.hpp> #include <vcl\Buttons.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Controls.hpp> #include <vcl\Forms.hpp> #include <vcl\Graphics.hpp> #include <vcl\Classes.hpp> #include <vcl\SysUtils.hpp> #include <vcl\Windows.hpp> #include <vcl\System.hpp>

//-------------------------------------------------------

class TPagesDlg : public TForm

{

__published: TPanel *Panel1; TPanel *Panel2;

TPageControl *PageControl; TTabSheet *TabSheet1; TTabSheet *TabSheet2; TTabSheet *TabSheet3; TButton *OKBtn;

TButton *CancelBtn;

TButton *HelpBtn; private:

public:

virtual __fastcall TPagesDlg(TComponent *Owner);

}; //-------------------------------------------------------

extern TPagesDlg *PagesDlg; //-------------------------------------------------------

#endif

Изначальный дизайн страничного диалога содержит несколько важных компонентов. Во-первых, переменная типа TPageControl (PageControl1) является центром всего. Объект типа PageControl (страничный управляющий элемент) – это и есть основа, которая управляет тем, какие диалоги (называемые листами с закладками, tab sheets) отображать. Объекты типа TTabSheet (TabSheet1,

...) и есть сами страницы этого страничного диалога, которые отображаются, когда происходит щелчок мыши на соответствующей закладке. И, наконец, кнопки OK, Cancel и Help автоматически создаются внизу диалога для работы с диалогом пользователя. Если вы хотите сделать эту форму немодальной (например, дочернее окно MDI), то вам стоит убрать кнопки и растянуть панели, на которых находятся странички, до размера формы.

Отображение страничного диалога

Сначала мы отобразим новый страничный диалог. Это дает нам шанс продемонстрировать разницу в отображении форм в модальном и немодальном (обычном) виде. Добавьте новое

главное меню в основную форму и добавьте пункт меню с заголовком Показать страничный диалог. Добавьте следующий код в обработчик этой команды меню. Учтите, что вам нужно будет

Borland C++ Builder (+CD). Библиотека программиста 99

выбрать File ä Include Header (подключить заголовочный файл) для добавления файла Unit2.h в первую форму:

void __fastcall TForm1::ShowTabDialog1Click(TObject *Sender)

{

PagesDlg->ShowModal();

}

Это дает нам возможность использовать страничный диалог как модальный. Отображение диалога как модального означает, что вы не сможете вернуться к главной форме до тех пор, пока вы не закроете окно диалога с помощью кнопок OK, Cancel или кнопки закрытия на панели заголовка формы.

События в страничных диалогах

Создать страничный диалог просто. Работать с событиями страничного диалога должно бать так же просто, не так ли? И да и нет. Описать обработчик события для страничного диалога просто, поскольку все обработчики событий содержатся в системе CBuilder. Определить, которое событие вам надо отследить и как его обработать это отдельная история.

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

На первую страницу добавьте три поля редактирования, а над ними статическое текстовое поле «Введите текст в одно из нижележащих полей». Установите свойство Text всех трех полей редактирования в пустое значение. Вы можете сделать это быстро, выбрав все три поля редактирования и удалив текст в поле свойства Text в Object Inspector. Находясь в нем, измените названия страниц, выбирая объекты TabSheet и изменяя их свойство Caption. Первую страницу озаглавьте Страница 1, вторую Страница 2, третью Страница 3. Когда вы закончите, первая страница будет выглядеть, как показано на рис. 4.12.

Рис. 4.12. Первая страница страничного диалога

Borland C++ Builder (+CD). Библиотека программиста 100

Добавьте новый обработчик для события OnTabChanging, выбрав PageControl (вы можете это сделать, щелкнув мышью в поле страницы диалога) и обратившись к странице Events в Object Inspector. Озаглавьте новый обработчик события HandlePageChanging. В обработчик HandlePageChanging добавьте следующий код:

void __fastcall TPageDlg::HandlePageChanging(TObject *Sender, bool &AllowChange)

{

//Если это первая страница, то покинуть ее можно

//только после того, как ввели значение в

//одно из полей редактирования

if ( PageControl->ActivePage == TabSheet1 )

{

if ( Edit1->Text == "" && Edit1->Text == "" && Edit1->Text == "" )

{

MessageBox(NULL, "Вы ДОЛЖНЫ ввести текст!", "Ошибка", MB_OK);

Edit1->SetFocus(); AllowChange = false; return;

}

}

// В противном случае запоминаем активную страницу

FnCurTab = PageControl1->ActivePage->PageIndex;

}

Вам надо добавить описание переменной FnCurTab в заголовочный файл. Следующую строку добавьте в секцию частных объявлений заголовочного файла формы:

int FnCurTab;

Что здесь происходит?

В коде, только что добавленном вами в обработчик, есть пара важных для нас моментов. Первый

это концепция активной страницы. У каждого объекта PageControl есть единственная активная страница. В случае события OnTabChanging активной страницей будет та, с которой мы собираемся уйти, а не та, на которой щелкнул мышью пользователь. Таким образом, событие OnTabChanging используется для проверки ввода, осуществленного в текущей форме. Свойство ActivePage — это просто указатель на одну из страниц страничного диалога. И в нашей проверке мы выясняем, является ли активная страница (то есть та, с которой мы собираемся уйти) первой. Если да, то мы проверяем, введено ли что-нибудь хотя бы в одно из полей редактирования. Ведь об этом, в конце концов, просит надпись на этой странице.

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

Если пользователь все же что-то ввел в одно из полей, мы должны позволить ему перейти на другую страницу. В этом случае мы просто оставляем параметр AllowChange без изменений, ведь

Соседние файлы в предмете Программирование на C++