Введение
Набор данных в C++ Builder — это объект, состоящий из набора записей,
каждая из которых, в свою очередь, состоит из полей, и указателя текущей
записи. Набор данных может иметь полное соответствие с реально существующей
таблицей или быть результатом запроса, он может быть частью таблицы или
объединять между собой несколько таблиц.
Набор данных в C++ Builder является потомком абстрактного класса TDataSet
(абстрактный класс — это класс, от которого можно порождать другие классы,
но нельзя создать экземпляр объекта данного класса). Например, классы TQuery,
TTable и TStoredProc, содержащиеся на странице палитры компонентов Data
Access, — наследники TDBDataSet, который, в свою очередь, является наследником
TDataSet. TDataSet содержит абстракции, необходимые для непосредственного
управления таблицами или запросами, обеспечивая средства для того, чтобы
открыть таблицу или выполнить запрос и перемещаться по строкам.
Классика
Но пока классика еще присутствует, давайте посмотрим, что мы в ней имеем.
При ближайшем рассмотрении, к сожалению, оказывается, что практически ничего. Если Вы, как и я, провели последние лет 15 на неведомой планете, на которой ничего страшнее Builder 5.0 не существовало, то в попытках обнаружить кардинальные изменения в современном «классическом» инструментарии Вы не обнаружите практически ничего. Пара новых ключевых слов из стандарта С++ посвежее, которые не нужны, измененный способ вывода справки о ключах командной строки и несколько новых ключей для совместимости с тем, что Вам все равно не пригодится. На этом, собственно, и все. Если Вы, вдруг, рассчитывали обогатить свой код конструкциями из свежих стандартов С++, то Вам не сюда. Вы не ослышались, на главной странице С++ Builder про С++17 Вас нагло обманули. К классике это не имеет ни малейшего отношения точно так же как и раньше. Если Вы рассчитываете на появление какой-то оптимизации кода или вообще на изменение в его генерации, то нет – это не тут. Лучшее на что Вы можете рассчитывать – это на то, что Ваш существующий код соберется без лишних ошибок времени исполнения.
Для примера возьмем нашу гениальную программу описанную выше. Собрав ее классическим компилятором в «статике» мы получаем файл размером в 70 килобайт. Собрав ее clang для win32, мы получаем файл размером в 174 килобайта. Изменив платформу на win64, мы получим уже 470 килобайт. Чисто для смеха, из аналогично пустой программы на паскале получается 43 килобайта. В принципе, это ни о чем особо не говорит, конечно.
С компилятором clang ситуация другая. Это современный компилятор. Он существенно отстает по всем могущим прийти в голову фронтам от аналога, используемого Microsoft, но, в сравнении с «классическим» компилятором, крайне современный. Другой вопрос, который меня волнует — это «зачем»? Да, Embarcadero справились с задачей внедрения во «вражеский» стан __closure, биндинга с кодом из Pascal, но я не могу увидеть в этих их усилиях никакого смысла. В теории с использованием clang можно собирать приложения на VCL и, если Вы вообще часто выигрываете в лотерею, они даже соберутся и, возможно, будут работать. Но смысла в этом подвиге не так уж и много, и причин тому несколько:
-
Существующий код, сколько-нибудь завязанный на специфику платформы (оптимизированный с использованием ассемблера вставками или целиком), часто будет проще выкинуть, чем адаптировать. Виной тому, как синтаксические мелочи типа невозможность использования меток в блоках asm, так и обилие тараканов с caling-conversion.
-
Существующий С++ код, завязанный на чужие или даже свои, но от которых не осталось исходников, библиотеки можно будет выкинуть. Один только фиктивный «__fastcall» ставит жирный крест на попытках подобного code-reusing.
-
Использование всей мощи современного С++ в связке с VCL не имеет никакого смысла т.к. VCL написан исключительно на Pascal и места для применения фич из другого языка в этой библиотеке попросту нет.
-
Embarcadero – это Вам не Microsoft и адаптировать чужеродный язык к существовавшим исторически реалиям они оказались не способны. Реализация clang из комплекта напоминает престарелого франкенштейна: он еще не способен корректно работать со всем старым кодом из Builder, но уже устарел.
-
То, что лично для меня является определяющим: clang чудовищно, непредставимо медленный.
Компонент TDataSource
В типичных приложениях БД компонент DataSource, как правило, связан
с одним компоненом TDataSet (TTable или TQuery) и с одним или более компонентами
Data Controls (такими, как DBGrid, DBEdit и др.). Связь этого компонента
с компонентами TDataSet и DataControls осуществляется с использованием
следующих свойств и событий:
-
Cвойство DataSet компонента DataSource идентифицирует имя компонента TDataSet.
Можно присвоить значение свойству DataSet на этапе выполнения или с помощью
инспектора объектов на этапе проектирования. -
Cвойство Enabled компонента DataSource активизирует или останавливает взаимосвязь
между компонентами TDataSource и Data Controls. Если значение свойства
Enabled равно true, то компоненты Data Controls, связанные с TDataSource,
воспринимают изменения набора данных. Использование свойства Enabled позволяет
временно разъединять визуальные компоненты Data Controls и TDataSource,
например, для того, чтобы в случае поиска в таблице с большим количеством
записей не отображать на экране пролистывание всей таблицы. -
Свойство AutoEdit компонента DataSource контролирует, как инициируется
редактирование в компонентах Data Controls. Если значение свойства AutoEdit
равно true, то режим редактирования начинается непосредственно при получении
фокуса компонентом Data Controls, связанным с данным компонентом TDataSet.
В противном случае режим редактирования начинается, когда вызывается метод
Edit компонента TDataSet, например, после нажатия пользователем кнопки
Edit на компоненте DBNavigator. · Событие OnDataChange компонента DataSource
наступает, когда происходит изменение значения поля, записи, таблицы, запроса. -
Cобытие OnUpdateData компонента DataSource наступает, когда пользователь
пытается изменить текущую запись в TDataSet. Обработчик этого события следует
создавать, когда требуется соблюсти условия ссылочной целостности или ограничения,
накладываемые на значения полей изменяемой базы данных.
Шаг 1 — Знакомство с С++ Builder 5
Этот раздел рассказывает об объектно-ориентированном программировании в среде C++ Builder 5. Правда, я не рассказываю об общем синтаксисе C++, где нужно, просто даю пояснения о расширениях. Я рекомендую прочитать какую-нибудь из книг именно по C++, например Бьярна Страустрапа «Введение в C++».
Язык C++, используемый в этой системе, не сильно отличается от стандарта ANSI. Он дополнен некоторыми ключевыми словами, позволяющими использовать в полной мере преимущества Windows-программирования.
Прежде, чем приступить к описанию этой системы, я должен, как и любой автор, отметить, что C++ Builder и Delphi похожи, как близнецы-братья. Хотя это заезженная истина, но, тем не менее, несмотря на похожесть, методы программирования на них отличаются. Впрочем, переход от одной системы к другой не будет особенно затруднительным. Вот такой дисклеймер :).
Стандартной библиотекой C++ Builder является VCL, а не MFC или OWL, как в других системах программирования на C++ под Windows.
VCL — библиотека визуальных компонентов. Их вид можно менять на стадии проектирования, а не только на стадии выполнения (run-time).
Тем не менее, C++ Builder позволяет использовать и эти две библиотеки. Также возможно прямое обращение к функциям Windows API и вызов из DLL. В общем, куда хочешь залезь и что хочешь запусти.
С++ Builder поставляется в трех вариантах — Standard, Professional и Enterprise. Для нас большой разницы в цене нет благодаря отечественным морякам CD дисков, так что я буду рассматривать все примеры на базе Enterprise.
Вариант Enterprise позволяет работать с COM и CORBA, базами данных(SQL, Paradox, dBase, MS OLE DB, Access 97, FoxPro, InterBase, Oracle, Sybase, Informix, DB2), Интернетом(TCP/IP, HTTP, FTP, NNTP, SMTP, POP3, CGI, WinCGI, ISAPI, NSAPI). Кроме того, содержит встроенные средства интегрированной отладки, о которых я расскажу в следующих шагах.
Инсталляция обычно проходит без проблем, главное, не забудьте посмотреть код диска. Кто не знает, его обычно пишут в .diz файле или Lisense.txt.
Я думаю, сейчас я рассказал достаточно, чтобы приступить к этакому quick-tour‘у по C++ Builder.
Для начала ознакомимся со средой программирования:
На экране 4 окна — главное(верхнее), окно Инспектора объектов слева, Редактора кода справа и Дизайнер форм под окном Редактора.
В главном окне видна Палитра компонентов. Палитра — один из основных методов ускоренного программирования. На палитре размещены компоненты VCL на нескольких вкладках. Название каждой из вкладок довольно хорошо характеризует ее содержимое.
Палитра используется вместе с Дизайнером форм. Чтобы создать на форме компонент, выберите его на Палитре и растяните по необходимым размерам на форме. Дизайнер отображает форму практически в том виде, в котором она будет при запуске, если вы, конечно, не создадите какие-то компоненты «at run-time«.
Для модификации внешнего вида и параметров компонента, а также задания обработчиков(handlers) событий, используйте Инспектор объектов. Для этого выберите какой-то компонент на форме или из выпадающего списка (сама форма — тоже компонент), и на первой вкладке вы увидите свойства данного объекта, а на второй вкладке — обработчиков событий. Для создания нового обработчика или перехода к уже имеющемуся используйте двойной щелчок по соответствующей строке Инспектора. Это приведет вас к тексту в окне Редактора (а куда же еще :)).
Также существует некоторое количество других окон, некоторые из которых могут быть «причалены» в окне Редактора, о них я расскажу в последующих шагах.
Вроде для ознакомления с системой достаточно. В следующем шаге будет минимальный проект.
| Автор .
Компоненты TDBLookup
C++ Builder предоставляет четыре компонента для просмотра и ввода значений
в таблицы:
- Компонент TDBLookupListBox (страница Data Controls)
- Компонент TDBLookupComboBox(страница Data Controls)
- Компонент TDBLookupList (страница Win 3.1)
- Компонент TDBLookupCombo(страница Win 3.1)
Компоненты DBLookupList и DBLookupListBox являются похожими на ListBox
компонентами, созданными для просмотра значения в одной таблице, основанного
на значении в другой таблице. DBLookupList и DBLookupListBox содержат конечный
набор значений. Когда DBLookupList и DBLookupListBox используются для ввода
данных, пользователь должен выбрать один вариант из списка. DBLookupList
и DBLookupListBox позволяют вывести на экран набор вариантов, основанных
на значении в другой таблице.
Компоненты DBLookupList и DBLookupListBox отличаются от компонента DBListBox
тем, что позволяют согласовать выбранное значение из списка с текущей строкой
другой таблицы БД, тогда как для DBListBox список значений для выбора определен
заранее и не имеет отношения к таблицам БД.
Компоненты DBLookupCombo и DBLookupComboBox являются похожими на ComboBox
компонентами, то есть они похожи на DBLookupList и DBLookupListBox, за
исключением того, что пользователь может либо выбирать значение в списке,
либо вводить новое значение. ComboBox, на который похожи DBLookupCombo
и DBLookupComboBox, сочетает в себе возможности ListBox с возможностями
компонента Edit. DBLookupCombo и DBLookupComboBox отличаются от компонента
ComboBox тем, что позволяют согласовать выбранное значение с текущей строкой
другой таблицы БД. При размещении компонентов DBLookupList, DBLookupListBox,
DBLookupCombo или DBLookupComboBox на форме эта форма в приложении должна
содержать DataSource и компонент — потомок TDataSet (например, TTable).
Компонент TTable
- Active — указывает, открыта (true) или нет (false) данная таблица.
-
DatabaseName — имя каталога, содержащего искомую таблицу, либо псевдоним
(alias) удаленной БД (псевдонимы устанавливаются с помощью утилиты конфигурации
BDE, описание которой присутствует во многих источниках, посвященных продуктам
Borland, либо с помощью SQL Explorer, вызываемого с помощью пункта меню
Database/Explore). Это свойство может быть изменено только в случае, если
таблица закрыта (ее свойство Active равно false), например:
Table1->Active = false;
Table1->DatabaseName = "BCDEMOS"
Table1->Active = true;
TableName — имя таблицы.
Exclusive — если это свойство принимает значение true, то никакой другой
пользователь не может открыть таблицу, если она открыта данным приложением.
Если это свойство равно false (значение по умолчанию), то другие пользователи
могут открывать эту таблицу.
IndexName — идентифицирует вторичный индекс для таблицы. Это свойство нельзя
изменить, пока таблица открыта.
MasterFields — определяет имя поля для создания связи с другой таблицей.
MasterSource — имя компонента TDataSource, с помощью которого TTable будет
получать данные из связанной таблицы.
ReadOnly — если это свойство равно true, таблица открыта в режиме «только
для чтения». Нельзя изменить свойство ReadOnly, пока таблица открыта.
Eof, Bof — эти свойства принимают значение true, когда указатель текущей
записи расположен на последней или соответственно первой записи таблицы.
Fields — массив объектов TField. Используя это свойство, можно обращаться
к полям по номеру, что удобно, когда заранее неизвестна структура таблицы:
Edit1->Text=Table1->Fields->AsString;
-
Open и Close устанавливают значения свойства Active равными True и False
соответственно. - Refresh позволяет заново считать набор данных из БД.
-
First, Last, Next, Prior перемещают указатель текущей записи на первую,
последнюю, следующую и предыдущую записи соответственно, например:
Table1->First();
while (!Table1->Eof)
{
//что-то делаем...
Table1->Next();
};
MoveBy перемещает указатель на указанное число строк (оно может быть и
отрицательным) в пределах таблицы
Insert, Edit, Delete, Append — переводят таблицу в режимы вставки записи,
редактирования, удаления, добавления записи соответственно.
Post — осуществляет физическое сохранение измененных данных. Например:
Table2->Insert();
Table2->Fields->AsInteger = 100;
Table2->Fields->AsString =Edit1->Text;
Table2->Post();
Cancel — отменяет внесенные изменения, не сохраненные физически.
FieldByName — предоставляет возможность обращения к данным в полях по имени
поля:
S=Table1->FieldByName("area")->AsString;
SetKey переключает таблицу в режим поиска.
GotoKey начинает поиск строки, значение Fields которой равно выбранному,
где n — номер колонки таблицы, начиная с 0:
Table1->SetKey();
Table1->Fields->AsString=Edit1->Text;
Table1->GotoKey();
SetRangeStart, SetRangeEnd, ApplyRange позволяют выбрать нужные строки
на основе диапазона значений какого-либо поля.
Table1->SetRangeStart();
Table1->Fields->AsString = Edit1->Text;
Table1->SetRangeEnd();
Table1->Fields->AsString = Edit2->Text;
Table1->ApplyRange();
FreeBookmark, GetBookmark, GotoBookmark- позволяют создать помеченную строку
в таблице и затем вернуться к ней позже. Методы Bookmark используют класс
TBookmark. Метод GetBookmark устанавливает закладку на текущей cтроке таблицы.
GotoBookmark осуществляет перемещение в таблице к строке, ранее отмеченной
закладкой. Метод FreeBookmark используется для уничтожения объекта типа
TBookmark:
TBookmark Marker =Table1->GetBookmark();
Table1->GotoBookmark(Marker);
Table1->FreeBookmark(Marker);
Чтобы внести компонент TTable в форму, нужно выполнить следующее:
1. Используя страницу Data Access палитры компонентов, разместить компонент
TTable на форме или в модуле данных.
2. Свойству DatabaseName присвоить имя каталога, где находится БД, либо
псевдо има БД.
3. Свойству TableName присвоить имя таблицы или выбрать таблицу из выпадающего
списка.
4. Внести в форму компонент DataSource и установить значение свойства
DataSet равным имени компонента TTable.
5. Внести компоненты Data Controls и связать их с компонентом DataSource
для того, чтобы отобразить на экране данные из таблицы БД.
Компонент TDBGrid
Внешний вид таблицы (например, надписи в заголовках столбцов) может
быть изменен с помощью редактора свойств Columns Editor. Для вызова Columns
Editor нужно либо выбрать соответствующую опцию в контекстном меню компонента
DBGrid или щелкнуть мышью в колонке значений напротив свойства Columns
в инспекторе объектов.
Вторым способом получения контроля над характеристиками DBGrid или другими
компонентами является создание описанным выше способом статического набора
компонентов TField. Имея компонент типа TField, созданный для каждого из
полей в наборе данных, можно установить ширину, формат, маску, расположение,
метку для отображения в DBGrid и другие характеристики.
Поля Float, Integer и Date обладают свойством DisplayMask. Это свойство
можно использовать, чтобы форматировать данные в компоненте DBGrid или
другом компоненте Data Controls. Например, экранный формат mm-dd-yy может
использоваться для размещения полей типа дата.
Некоторые компоненты TField (например, TStringField) обладают свойством
EditMask, которое можно установить, вводя данные в DBGrid и другие компоненты
Data Controls. Для установки свойства EditMask нужно установить компонент
Field в Object Inspector и выбрать свойство EditMask, после чего появится
диалоговая панель Input Mask Editor, представленная на рис. 5.19. Чтобы
проверить маску редактирования, нужно ввести значение в поле Test Input.
Заключение
В заключение, исходя из полученного опыта, я могу дать следующую оценку современному продукту с именем Embarcadero C++ Builder.
О любых применениях clang в этой среде я рекомендую забыть. При работе с VCL он совершенно не нужен, а в тех задачах, где его применение стоит усилий, гораздо оправданнее выбрать другое средство. Его реализация в Builder ущербна, тормозна, громоздка и неудобна. Если на свете вообще существуют какие-то причины применять его в рамках этого продукта, то я с интересом бы о них узнал. Мне в голову не приходит ни одной.
Если Вы разрабатываете приложения на какой-то из версий С++ Builder и, в отличии от меня, в своей работе уже проскочили момент, когда VCL созрел для UNICODE, то я вполне могу рекомендовать Вам рассмотреть современный Builder как цель миграции своих проектов. В VCL появилось очень много нового и часть из этого может оказаться действительно полезным. Некоторые баги библиотеки и средств разработки поправили, средой вполне успешно можно пользоваться. Если у Вас есть достаточно энтузиазма и свободного времени, то рекомендую попробовать. Возможно, Вы получите от перехода на новое средство какую-то выгоду.
Если Вы случайно споткнулись о книгу «C++ Builder за Х дней», если Вы молодой и горячий или перед Вами просто стоит задача выбора средства для быстрого написания интерфейсно-нагруженных приложений под Windows, то С++ Builder это все еще самый лучший RAD на рынке для выполнения этой задачи. Текущее его состояние вполне позволит Вам создавать качественные приложения за минимальное время с вменяемыми усилиями.
Если Вам нужно писать на современном С++, если Вы горите желанием создавать модные интерфейсы и использовать наисвежайшие библиотеки из развалов гов… эээ, шедевров open-sorce разработок, то крайне рекомендую – не тратьте свое время на Builder. Изучайте что-нибудь более живое, модное и современное. Например, Visual Studio.