1 Что такое bde?

1.1. Что такое BDE? 11.2. Базы данных в BDE 11.3. Создание alias. 21.4. Косметическая настройка BDE 31.5. Таблица в Database Desktop 41.6. Мастер форм 41.7. Каким образом это все работает. 51.8. Компонент TTable. Создание таблиц. Типы полей 61.9. Создание таблиц. Ключи и индексы 81.10. Класс TFieldDef. 91.11. Коллекция TFieldDefs 101.12. Изменение значений полей 121.13. Проект приложения CView 131.14. Создание произвольной таблицы 15 1.1.Что такое BDE? BDE – в C++Builder механизм управления базами данных. Это посредник между Вашей программой и базами данных разных форматов – Paradox, MS Access, dBase и так далее. BDE – набор системных DLL файлов, которые включатют драйвера. Вашей программе не придется вручную эти самые драйвера создавать, просто можно воспользоваться встроенным механизмом. В C++Builder BDE не является монополистом. В программу включены также такие механизмы, как ADO и InterBase. ADO представляет собой также набор библиотек, как и BDE. В отличие от их обоих, InterBase позволяет обращаться к базам данных через COM-интерфейсы, минуя посреднические механизмы. В этом плане InterBase более эффективен для распространения, поскольку нет необходимости включать установочный файл BDE в дистрибутив программы, который, кстати, имеет большой размер. В любом случае BDE манипулировать проще всего. Основное для работы с базами данных церез BDE предоставляется на палитрах Data Access и Data Controls. BDE имеет довольно мощные средства для работы с SQL. SQL – язык транзакций RDBMS реляционных баз данных.^ 1.2.Базы данных в BDE Чаще всего базы данных адресуются в программах своим псевдонимом [alias]. Псевдоним – приблизительно то же самое для базы данных, что и домен для сайта. То есть через псевдоним можно обращаться к базе данных, не зная ее физического расположения. Чтобы узнать, какие alias есть на Вашем компьютере, нужно запустить командой Database-Explore т.н. SQL Explorer. Его окно показано на скриншоте: В левой части показаны псевдонимы баз данных, в правой – их свойства. Отметьте, что получить доступ к базе данных можно только с установленным сервером этой базы. Например, после установки InterBase сервера становится доступным база данных IBLocal. Сразу же доступными являются базы данных BCDEMOS и DBDEMOS. Никто не ограничивает Вас в выборе alias. Можно создать и свой собственный alias для рабочих файлов.На скриншоте виден псевдоним Local tables, как раз в нем все примеры баз данных и размещены. С BDE поставляется довольно много примеров баз данных. Эти таблицы, как и все другие, можно посмотреть, если два раза щелкнуть на BCDEMOS, а затем на появившемся Tables. ^ 1.3.Создание alias. Запустите SQL Explorer командой Database-Explore. Как обычно, alias с левой, свойства с правой строны. Выберите команду Object-New. Появится оконо: Оконо дает возможность выбрать тип драйвера для базы данных. Стандартный нам подходит. Жмите OK. Слева появится поле для ввода имени для таблицы. Введем, например, “Local tables”, и нажмем Enter. Обратите внимание, что рядом со значком базы данных в данный момент изображена зеленая стрелка. Эта стрелка означает, что над базой проводятся изменения типа транзакции. Чтобы изменения вошли в силу, надо из контекстного меню выбрать команду Apply. Для того, чтобы Explorer знал, откуда брать таблицы, нужно задать путь к директории с таблицами. Например каталог “C:\program files\borland\database desktop\workdir”. После всех этих махинаций можно выполгить команду Apply. До ее выполнения ничего работать не будет, а возникнет ошибка “Operation not supported”: Теперь все таблицы, помещенные в эту директорию, Проводник будет отображать в раскрывающемся дереве.^ 1.4.Косметическая настройка BDE Чтобы работать с BDE, надо ее немного поднастроить, чтобы русский выводила как положено. Для настройки BDE используется утилита BDE Administrator. Выглядит она довольно схоже с SQL Explorer’ом: Вкладка Databases нам не нужна, мы ее и из Проводника видим. Зато на вкладке Configuration есть настройки по драйверам баз данных и системным параметрам. Открываем ветвь Drivers. Там должны быть пункты Native и ODBC. Второй нам пока не нужен, открываем первый. Там есть значок Paradox. По нему и щелкаем. В правой части, как обычно, свойства. Пока установим правлильный драйвер для языка, как на скриншоте: Чтобы в Database Desktop отображался нормальный шрифт, нужно в файл win.ini, в раздел FontSubstitutes подставить строку Arial,0=Arial,204. После этого перезагрузиться. ^ 1.5.Таблица в Database Desktop Запускается Database desktop через Tools-Database Desktop.Выбираем команду File-New-Table, появляется окно, в котором предлагается выбрать тип создаваемой таблицы. Выберем Paradox 7. Жмите OK. Появится другое окно: Кто работал с MS Access в режиме конструктора. Первый столбец – номер поля, второй – его имя. Третий определяет тип (выпадающий по правой клавише мыщи список), четвертый – размер, а пятый – является ли поле ключевым. Для начала – строковые типы – ALPHA, числовые – NUMBER. Поля, то есть столбцы, когда они уже готовы, создаются как обычно. Для начала создайте простую записную книжки и нажмите Save as для сохранения таблицы. Внизу можно выбирать alias для сохранения.^ 1.6.Мастер форм Попробуем создать форму на основе базы данных, используя Мастер форм (Form Wizard). Этот мастер запускается командой Database-Form Wizard… Как и у всякого другого мастера, у него несколько окон. В первом окне предлагается выбрать, какие компоненты будет использовать форма. Для начала лучше согласиться с вариантами по умолчанию, поскольку мы используем простую таблицу, без связи ведущий-ведомый, а запросы нам пока не нужны. В следующем окне предлагается выбрать источник для построения формы. Выберите alias базы данных в выпадающем списке справа внизу, и название таблицы слева. Предпочтительнее выбрать таблицу из BCDEMOS, называемую Clients. Жмите Next. Далее будет предложено выбрать поля из таблицы, которые будут использоваться в форме. Можно выбрать все поля кнопкой “>>”. Если какие-то Вам не подходят, уберите их. В следующем окне мастера будет предложен вариант размещения полей таблицы. В последнем окне этого, довольно долгого мастера, Вас спросят, нужно ли создавать модуль данных и является ли создаваемая форма главной.В итоге получится: ^ 1.7.Каким образом это все работает. Общая схема работы типичного BDE-приложения базы данных такова: [База данных]|BDE|Компоненты доступа к BDE [TTable, TQuery]|Компонент TDataSource|Компоненты Data Controls [TDBLabel, TDBEdit]|ПользовательЭто не единственный вариант доступа к базе данных. Как уже отмечалось, есть еще ADO и InterBase. Но общий принцип работы такой. В данном случае всю информацию о доступе к конкретной базе данных в данной программе хранит TTable. В ней и были заданы свойства DatabaseName и TableName. В компоненте же DataSource1 был задан набор данных как Table1. После этого DataSource стал промежуточным звеном между таблицей и компонентами TDBEdit и TDBImage, отвечавшими за отображение и редактирование записей. Последние компоненты “понимают”, к какому полю таблицы относятся, по свойству FieldName. ^ 1.8.Компонент TTable. Создание таблиц. Типы полей Этот компонент отвечает за системное соединение с выбранной базой данной и соответствующей таблицей. Для подключения используется текущая конфигурация BDE. Выбранный alias задается в свойстве DatabaseName, а выбранная таблица в свойстве TableName. При этом этот компонент автоматически сканирует все возможные таблицы для предоставления доступа к ним. Если для доступа к выбранной базе (например, MS Access 97 Database) необходим ввод логина и/или пароля, при соединении появится дилоговое окно. Это окно чаще всего используется при доступе к базам данных ODBC. Свойство Active таблицы дает возможность активировать ее уже на стадии выполнения. При этом автоматически тестируется соединение. Если при подобном тестировании вылетает какая-нибудь ошибка, чаще всего это какая-то ошибка настройки alias. Но этот компонент может не только считывать данные с уже готовых таблиц. С его помощью можно создать и таблицу с “нуля”. Так, в принципе, и должно быть, ведь каждая серьезная программа баз данных должна это уметь. Насчет создания таблиц. Как мы знаем, таблица определяется полями и их типами. Типы бывают разные. Можно привести их все, правда, много места займет. DD – это Database DeskTop. Название поля в DD Константа Описание   ftUnknown Неизвестный, неограниченный тип. Alpha A ftString Одиночный символ или целая строка. Short S ftSmallInt Короткое целое, размерностью 16 бит. Integer I ftInteger Стандартное целое, размерность 32 бит. ftWord Слово – целое размерностью 16. В отличие от short, не имеет знака. Logical L ftBoolean Логическая переменная – принимает значения true ftFloat Число с плавающей точкой. ftCurrency Всеми нами любимая валюта – спецформат :). ftBCD Поле, содержащее кодированное в бинарном формате десятичное значение. Date D ftDate Дата – тоже специальный формат. Time T ftTime Аналогично время. ftDateTime И дата, и время в одном флаконе 🙂 Bytes Y ftBytes Фиксированное количество байтов. ftVarBytes Вариантное (нефиксированное) количество байтов. AutoIncrement + ftAutoInc Поле-автоинкремент, которое увеличивается автоматически при добавлении новой записи. ftBlob Большой Бинарный ОБъект – оюычно что-то вроде изображения. Memo M ftMemo Поле типа Memo. В обще по своей структуре напоминает AnsiString – неограниченный размер. Graphic G ftGraphic Поле типа Bitmap – стандартный BMP файл. Formatted Memo F ftFmtMemo Форматированное поле Memo. OLE O ftParadoxOle Поле OLE для таблиц типа Paradox. ftDBaseOle Поле OLE для таблиц dBase. Binary B ftTypedBinary Типизированный бинарный формат. ftCursor Содержит образ курсора, выдаваемого хранимой процедурой данных Oracle. ftFixedChar Поле – одиночный символ. ftWideString Строка UNICODE-символов – wide chars. Аналогично типу WideString. Long Integer L ftLargeInt Написано LargeInt, читай long int. ftADT Поле абстрактного типа. ftArray Массив. ftReference Ссылка. ftDataSet Набор данных. ftOraBlob Большой Бинарный ОБъект для баз данных Oracle 7 и иже с ними. ftOraClob CLOB – тип для той же компании. ftVariant Вариантное поле. Его тип может динамически изменяться во время работы программы ftInterface Интерфейс. ftIDispatch Интерфейс IDispatch. ftGuid Стандартный GUID – универсальный OLE/COM идентификатор. ^ 1.9.Создание таблиц. Ключи и индексы Поле – это ячейка в таблице. Запись – набор из полей. Существуют разные типы полей – обычные, индексные и ключевые. Обычные поля – просто данные. Индексное поле – поле, по которому данные сортируются. Ключевое – поле, значение которого уникально. В общем-то четкого разделения нет. Ведь программа базы данных может сортировать таблицу и по обычным полям, а индексное поле может быть также уникальным. В BDE достаточно логично поределена структура построения полей и их типов. Для этого имеются классы TxxxDef (три икса здесь обозначают подстановку, а то мало ли что Вы подумаете ;)), произведенные ото абстрактного базового класса TNamedItem. В компоненте TTable имеются и соответствующие свойства TIndexDefs TFieldDefs Как и следовало предполагать, эти свойства содержат в себе определения индексных и обычных полей. Здесь нет свойства типа TKeyDefs, потому что в таблицах типа Парадокс индексные поля могут быть сами по себе уникальны. За счет этих свойств и задаются параметры таблицы, ее сетка. Создание таблицы довершает метод CreateTable. Пример: if (!Table1->Exists) // Проверка существования таблицы { Table1->Active = false; // Компонент TTable должен быть отключен.// Опишем параметры таблицы. Table1->DatabaseName = “BCDEMOS”;//это по желанию Table1->TableType = ttParadox; //тип таблицы – Парадокс. Table1->TableName = “CustInfo”;//имя создаваемой таблицы.// Опишем поля и их типы. Table1->FieldDefs->Clear(); TFieldDef *pNewDef = Table1->FieldDefs->AddFieldDef(); pNewDef->Name = “Field1”;// имя, обычной строкой. pNewDef->DataType = ftInteger; //установим, является ли поле обязательным pNewDef->Required = true; //еще одно поле. pNewDef = Table1->FieldDefs->AddFieldDef();pNewDef->Name = “Field2”; pNewDef->DataType = ftString; //определим размер поля. pNewDef->Size = 30;// Теперь взялись за индексыTable1->IndexDefs->Clear();/* Первый индекс безымянный, поскольку это основной индекс Парадокса. */Table1->IndexDefs->Add(“”,”Field1″, TIndexOptions() Table1->IndexDefs->Add(“Fld2Index”,”Field2″, TIndexOptions() // Ну и наконец, создаем таблицу.Table1->CreateTable();^ 1.10.Класс TFieldDef. Этот класс описывает поле, его тип и т.п. Свойства этого класса. AttributesЭто свойство содержит аттрибуты данного поля. Это множество, состоящее из значений faHiddenCol, faReadonly, faRequired, faLink, faUnNamed, faFixed. Вот что они значат: faHiddenCol Внутренний флаг, обозначающий, что столбец данных скрыт. Используется в динамических запросах к таблице. faReadOnly Если этот флаг установлен, то редактирование данного поля запрещено. faRequired Данное поле обязательно должно содержать установленное значение. faLink Внутренний флаг для вложенных таблиц. faUnNamed Только для внутреннего использования. faFixed Обозначает, что поле имеет фиксированный размер. ChildDefsЭто свойство и с ним связанные относятся не ко всем разновидностям (потомкам) класса TFieldDef, а только к производным TObjectField, например TADTField. Определяет вложенные определения полей – дочерние поля. Это указатель на объект класса TFiledDefs. Для добавления вложеннных полей используется метод AddChild(void), возвращающий указатель на объект TFieldDef. Свойство ParentDef содержит указатель на родительское поле. Взаимосвязь – fDef = fDef->AddChild()->ParentDef. Метод HasChildDefs(void) возвращает, есть ли у данного поля вложенные. DataTypeЭто свойство определяет реальный тип физического поля (того, которое записано в таблице или выдается по SQL запросу). Разные специализированные потомки TFieldDef автоматически проставляют значение этого свойсва. Пользователи, впрямую работающему с TFieldDef, приходится вручную устанавливать его значение. FieldClassОпределяет метакласс поля, основываясь на значении DataType. Возвращается значение, к которому можно приравнять с помощью оператора __classid, например, fDef->DataType = ftInteger; fDef->FieldClass==__classid(TIntegerField); InternalCalcFieldЕсть понятие RequestLive запроса, то есть запроса, который выдает динамически просчитываемые данные. Например, как в часто бывает на практике, есть поле ЦЕНА и поле КОЛИЧЕСТВО. Какое-либо поле типа ИТОГ не должно быть ведено отдельно и вводится отдельно. Это источник ошибок и вообще нерациональный метод ведения базы. Для этого есть запросы, например ^ SELECT ЦЕНА, КОЛИЧЕСТВО (ЦЕНА*КОЛИЧЕСТВО)FROM DATAВот третье поле-то и будет ИТОГ. InternalCalcField как раз и определяет, является ли поле динамическим или нет. Это read-only property, его значение менять нельзя. Required, SizeСвоство Required определяет, обязательно ли поле должно иметь значение вообще. Свойство Size дает возможность установить или считать размер для поля. Тип поля должен быть следующий: ftString, ftBCD, ftBytes, ftVarBytes, ftBlob, ftMemo или ftGraphic. CollectionОпределяет указатель на содержащий данный объект (this) объект-список, коллекцию, производный абстрактного класса TCollection. Это наиболее значимые свойства данного класса. Надо отметить, что обычно вместо этого класса используются более специализированные, например TADTFiled, TGraphicField, TStringField. Но основные свойства у них эти.^ 1.11.Коллекция TFieldDefs Коллекция – в общем-то, специальный список с конкретизированными под данные нужды методами и свойствами. Вот TFieldDefs – коллекция для определений TFieldDef:HiddenFields Определеят, следует ли отображать дополнительные скрытые поля в запросе к базе данных. Преимущественно для внутреннего использования. Items Свойство типа массив, содержащее указатели на объекты типа TFieldDef. ParentDef Вроде мы уже это видели :). Определяет родительское (parent)поле. Логично :). DataSet Набор данных, использующий данную коллекцию. Я уже говорил, что по иерархии к DataSet относятся TTable и TDataSource. Updated Определяет, совпадают ли определения полей в реальном наборе данных и в данной коллекции. Count Количество полей. Это были свойства. А теперь методы. AddОписание – HIDESBASE void __fastcall Add(const AnsiString Name, TFieldType DataType, int Size, bool Required); Параметр Name определяет имя для нового FieldDef, dataType тип поля, Size его размер, ну а Required – обязательно ли присвоение значения этому полю. Пример использования – Table1->FieldDefs->Add(“IntField”,ftInteger,4,false);. AddFieldDefОписание – TFieldDef* __fastcall AddFieldDef(void); Этот метод возвращает указатель на новый объект типа TFieldDef, а потом уже можно с этим указателем делать все что угодно. Пример: void TForm1::Example(){TFieldDef* def = Table1->FieldDefs->AddFieldDef();def->DataType=ftString; //напримерdef->Size=20;def->Required=true;//тоже например}UpdateОписание – HIDESBASE void __fastcall Update(void); Обновляет записи в источнике данных (чаще всего таблице). FindОписание – HIDESBASE TFieldDef* __fastcall Find(const AnsiString Name); Производит поиск по коллекции, сравнивая значения Name полей. Как видно из описания, возвращает указатель на объект найденный. Если он не найден, то… Как это ни странно, возвращается не NULL, а чтобы определить, найден или нет, нужно вызвать метод IndexOf класса TDefCollection (предок TFieldDefs). О нем. IndexOfОписание – int __fastcall IndexOf(const AnsiString AName); Возвращает индекс данного объекта TFieldDef. Если нет такого, возвращается -1. ^ 1.12.Изменение значений полей А сейчас мы попробуем создать форму в стиле “Мастера форм” MS Access. В этом нам очень помогут компоненты с вкладки Data Controls, а именно TDBEdit, TDBComboBox, TDbCheckBox, TDBNavigator. После размещения всех элементов на форме получим следующее окно: Теперь переходим к начинке системы. Бросаем объект TDataSource туда же. Выбираем все уже брошенные компоненты (кроме само собой TDataSource), и ставим их DataSource = DataSource1. Просто оценивая ситуацию поверхностным взглядом, ясно, что чего-то не хватает… А, нужно еще обозначить, к каким полям таблицы имеют отношение все элементы. Так как design-time таблицу мы подключить по ясным причинам (разные формы) не можем, то с клавиатуры впечатываем в свойства DataField компонентов имена соответствующих полей. Реализуем свой просмотрщик в виде ^ MDI-приложения, как это делали ранее. Напомню, что для MDI приложения одно окно (главное) должно иметь FormStyle = fsMDIForm, а все остальные принадлежащие клиентской области этого окна окна должны иметь FormStyle = fsMDIChild. Настоятельно рекомендуется все формы, кроме главной, создавать динамически (вкладка Forms меню Project->Options). Функция создания окон должна выглядеть так: TForm* TTextMain::AddChild(String fName,String caption){ TForm* child = NULL; if(fName==”BOOKLIST”) child = new TBookList(this); if(fName==”EDITBOOK”) child = new TEditBook(this); if(!child) { child = new TTextView(this); try { ((TTextView*)child)->Output->Lines->LoadFromFile(fName); } catch(…) { delete child; return 0; } } Pages->Tabs->AddObject(caption,child); Pages->TabIndex = Pages->Tabs->Count – 1; child->Caption = caption; child->Tag = Pages->Tabs->Count – 1; return child;}В программе-просмотрщике окна подразделяются на несколько типов – список книг (^ TDBGrid), редактор элементов таблицы (созданный только что) и далее мы еще напишем список истории чтения. Соответственно fName – это имя файла с текстом книги. Если fName – некоторое предопределенное значение (“BOOKLIST” например), то создается вариант окна на эту тему, иначе открывается файл с книгой. Компонент TTabControl* Pages – некий суррогат панели задач, предоставляет быстрый доступ к окнам. Если все делалось правильно, то должна получится такого рода форма: ^ 1.13.Проект приложения CView Далее в разработке этого приложения созданим историю по принципу FIFO. Реализация представлена ниже: void TTextHist::LoadHistory(String fName){ hist->Items->BeginUpdate(); hist->Clear(); dataset->DisableControls(); TListItem* itm = hist->Items->Add(); int p = dataset->RecNo; dataset->First(); int cur = -1; for(int i=0;iCount;i++) { dataset->RecNo = history->Names[i].ToInt(); cur = dataset->RecNo; TListItem* itm = hist->Items->Add(); itm->Caption = dataset->Fields->Fields[1]->AsString; itm->SubItems->Add(dataset->Fields->Fields[0]->AsString); itm->SubItems->Add(dataset->Fields->Fields[2]->AsString); itm->Data = (void*)cur; } dataset->RecNo = p; dataset->EnableControls(); hist->Items->EndUpdate();}Формат файла истории hist.inf выглядит следующим образом: ;номер книги=позиция полосы прокрутки23=100Занесение в историю выполняется при добавлении очередного TextView. TForm* TTextMain::AddChild(String fName,String caption,int id){ TForm* child = NULL; if(fName==”BOOKLIST”) child = new TBookList(this); if(fName==”EDITBOOK”) child = new TEditBook(this); if(fName==”TEXTHIST”) child = new TTextHist(this); if(!child) { for(int i=0;iClassName())==”TTextView”) if(((TTextView*)MDIChildren[i])->id==id) { BringWindowToTop(MDIChildren[i]->Handle); return 0; }; child = new TTextView(this);try { ((TTextView*)child)->Output->Lines->LoadFromFile(fName); }catch(…) { delete child; return 0; }((TTextView*)child)->id = id; int x = history->IndexOfName(id);if(x!=-1) { history->Exchange(0,x); SendMessage(((TTextView*)child)->Output->Handle, EM_LINESCROLL,0,history->Values[id].ToInt()); } else { history->Insert(0,String(id)+”=0″); if(history->Count>count) history->Delete(count); } } Pages->Tabs->AddObject(caption,child); Pages->TabIndex = Pages->Tabs->Count – 1; child->Caption = caption; child->Tag = Pages->Tabs->Count – 1; child->OnActivate = (TNotifyEvent)&ChildShow; return child;}Принцип FIFO предполагает, что последний внесенный объект будет стоять на первом месте, а первый внесенный объект при этом удаляется. Сохранение истории происходит при закрытии окна: void __fastcall TTextMain::FormClose(TObject *Sender, TCloseAction &Action){for(int i=0;iClassName())==”TTextView”) history->Values[((TTextView*)MDIChildren[i])->id] = IntToStr(GetScrollPos(((TTextView*)MDIChildren[i])->Output->Handle,SB_VERT));history->SaveToFile(“hist.inf”);}В данном случае перебором всех дочерних окон выбираются только относящиеся к типу TTextView. Для определения позиции полосы прокрутки используется стандартная WinAPI функция GetScrollPos. ^ 1.14.Создание произвольной таблицы Для создания таблицы используется метод CreateTable() компонента TTable (или любого другого аналогичного ему). Строго говоря, в таблице существуют простые поля и индексные. По индексным полям производится автоматическая сортировка. Предварительные описания полей содержатся в свойстве FieldDefs. В качестве примера создадим программу создающую произвольную таблицу . Форма ее будет такова: Компонент TTable нужно настроить на конкретный алиас, используем ^ BCDEMOS. В TComboBox* FieldType и заполним все значения типов полей: ftUnknown ftString ftSmallint ftInteger ftWordftBoolean ftFloat ftCurrency ftBCD ftDateftTime ftDateTime ftBytes ftVarBytes ftAutoIncftBlob ftMemo ftGraphic ftFmtMemo ftParadoxOleftDBaseOle ftTypedBinary ftCursor ftFixedCharftWideString ftLargeint ftADT ftArray ftReferenceftDataSet ftOraBlob ftOraClob ftVariant ftInterfaceftIDispatch ftGuid ftTimeStamp ftFMTBcdОчень важным является соблюдения порядка, соответствующего enum TFieldType. Затем пишем код: //—————————————void __fastcall TForm1::AddDefClick(TObject *Sender){ ListBox->Enabled = false; AddBox->Enabled = true;}//—————————————void __fastcall TForm1::FormCreate(TObject *Sender){ table->FieldDefs->Clear();}//—————————————void __fastcall TForm1::AddFieldClick(TObject *Sender){ TFieldDef* def = table->FieldDefs->AddFieldDef(); def->Name = FieldName->Text; def->Size = FieldSize->Text.ToInt(); def->DataType = (TFieldType)FieldType->ItemIndex; def->Attributes Checked)| (faRequired&FieldRequired->Checked)| (faReadonly&FieldReadOnly->Checked)| (faFixed&FieldFixed->Checked)); Fields->Items->AddObject(FieldName->Text,def); Fields->ItemIndex = Fields->Items->Count – 1; CancelFieldClick(0);}//—————————————void __fastcall TForm1::CancelFieldClick(TObject *Sender){ ListBox->Enabled = true; AddBox->Enabled = false;}//—————————————void __fastcall TForm1::BitBtn1Click(TObject *Sender){for(int i=0;iItems->Count;i++) ((TFieldDef*)Fields->Items->Objects[i])->FieldNo = i;table->TableType = (TTableType)TableType->ItemIndex;table->TableName = TableName->Text;table->CreateTable();}//—————————————void __fastcall TForm1::RemoveDefClick(TObject *Sender){ table->Active = false; if(Fields->ItemIndex==-1)return; TFieldDef* def = (TFieldDef*)Fields->Items->Objects[Fields->ItemIndex]; table->FieldDefs->Delete(def->Index); Fields->DeleteSelected();}//—————————————void __fastcall TForm1::FieldsChange(TObject *Sender){ TFieldDef* def = (TFieldDef*)Fields->Items->Objects[Fields->ItemIndex]; FieldSize->Text = def->Size; FieldType->ItemIndex = def->DataType; FieldName->Text = def->Name; FieldHidden->Checked = def->Attributes.Contains(faHiddenCol); FieldRequired->Checked = def->Attributes.Contains(faRequired); FieldReadOnly->Checked = def->Attributes.Contains(faReadonly); FieldFixed->Checked = def->Attributes.Contains(faFixed);}