Автор: Пользователь скрыл имя, 09 Октября 2011 в 01:57, статья
Borland C++ Builder - выпущенное недавно компанией Borland средство быстрой азработки приложений, позволяющее создавать приложения на языке C++, используя при этом среду разработки и библиотеку компонентов Delphi. В настоящей статье рассматривается среда разработки C++ Builder и основные приемы, применяемые при проектировании пользовательского интерфейса.
Введение
Среда разработки C++ Builder
Компоненты C++ Builder
Свойства компонентов
События
Методы
Менеджер проектов
Создание приложений в С++ Builder
Пример: создание простейшего приложения
Создадим простейшее приложение для переноса данных. Для этого создадим форму следующего вида (рис.23):
Рис.23. Форма приложения для переноса данных на сервер
Для переноса данных с одной платформы на другую обычно используется компонент TBatchMove. Этот компонент обеспечивает копирование данных из одной таблицы в другую. Основные свойства этого компонента следующие: Source – таблица (или запрос), откуда копируются данные, Destination – таблица, куда копируются данные, Mapping – определяет соответствие между колонками исходной и результирующей таблиц (для идентичных таблиц это свойство определять не обязательно), Mode – тип перемещения (batAppend – добавляет новые строки в результирующую таблицу, batUpdate – заменяет строки в результирующей таблице на соответствующие строки оригинала, batCopy – копирует строки в результирующую таблицу, переписывая ее, batDelete – удаляет записи в результирующей таблице, соответствующие записям оригинала), KeyViolTableName и ProblemTableName – имена дополнительных таблиц для помещения записей, чье копирование запрещено правилами ссылочной целостности или по каким-либо причинам невозможно (например, из-за несоответствия типов данных), ChangedTableName – имя таблицы для помещения измененных записей. Копирование данных происходит при выполнении метода Execute(). Отметим, что этот метод может быть вызван непосредственно из среды разработки с помощью контекстного меню компонента TBatchMove.
Установим следующие значения свойств используемых компонентов:
|
Создадим также обработчики событий для кнопок:
//----------------------------
#include <vcl\vcl.h>
#pragma hdrstop
#include "upsize1.h"
//----------------------------
#pragma link "Grids"
#pragma resource "*.dfm"
TForm1 *Form1;
//----------------------------
__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
{
}
//----------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Table1->Close();
Table2->Close();
Table1->TableName="CLIENTS";
Table2->TableName="CLIENTS.
Table1->Open();
Table2->Open();
}
//----------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Table1->Close();
Table2->Close();
Table1->TableName="HOLDINGS";
Table2->TableName="HOLDINGS.
Table1->Open();
Table2->Open();
}
//----------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
Table1->EmptyTable();
}
//----------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
BatchMove1->Execute();
}
//----------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
Close();
}
//----------------------------
Скомпилируем и запустим приложение. Кнопки CLIENTS и HOLDINGS осуществляют выбор между той или иной парой таблиц. При нажатии кнопки Добавить происходит перенос данных из активной в данный момент таблицы dBase (CLIENTS или HOLDINGS) в соответствующую таблицу Oracle. Отметим, что наличие поддержки ссылочной целостности можно проверить, попытавшись перенести данные из таблицы HOLDINGS до того, как перенесены данные из таблицы CLIENTS. При этом перенос осуществлен не будет, и в процессе выполнения приложения появится диагностическое сообщение примерно следующего вида (рис.24):
Рис.24. Диагностическое сообщение при попытке добавления записей в detail-таблицу при пустой master-таблице.
Примерно такие же последствия будет иметь попытка очистить таблицу CLIENTS после того, как перенесены записи в таблицу HOLDINGS.
После
переноса данных на сервер можно вернуться
к созданному ранее приложению с
формой master-detail и попробовать снова
проделать действия, приводящие к
нарушению ссылочной
Теперь, если мы попытаемся удалить запись из таблицы CLIENTS при наличии связанных с ней записей в таблице HOLDINGS, нам это не удастся. При этом клиентским приложением будет выдано диагностическое сообщение о наличии записей в дочерней таблице (рис. 25):
Рис.25. Диагностическое сообщение при попытке удаления записей из master-таблицы при наличии связанных с ней записей в detail-таблице.
Точно так же окажется невозможным добавить запись с произвольным значением поля ACC_NBR в таблицу HOLDINGS. Причина такого поведения созданной информационной системы очевидна: при проектировании базы данных с помощью ERwin помимо самих таблиц и индексов были созданы также специальные объекты базы данных, называемые триггерами. Триггер - это специальная процедура, выполняющаяся при наступлении определенного события, например, при попытке удаления записи в таблице CLIENTS. При описании свойств связи между таблицами мы выбирали, как сервер будет реагировать на подобные события, и в соответствии с нашим выбором были сгенерированы триггеры для выполнения соответствующих действий (в данном случае - для передачи клиентскому приложению диагностического сообщения).
Разумеется, пользователь приложения должен видеть нечто более вразумительное, нежели англоязычное сообщение с именем триггера и словами про "integrity constraint" и "key violation". Можно сделать это путем перехвата исключения в клиентском приложении, но более предпочтительно делать это на сервере, так как тогда будет исключена необходимость в повторении кода в случае, когда с одной и той же базой данных работают несколько приложений. Современные CASE-средства позволяют это сделать, и интересующиеся этой проблемой могут найти ее решение в документации по используемому CASE-средству и в документации, прилагаемой к соответствующему серверу баз данных.
Таким образом,
архитектура клиент/сервер обладает
рядом существенных преимуществ
по сравнению с традиционной архитектурой
информационных систем, основанных на
сетевых версиях настольных СУБД:
более высокой производительностью, более
низким сетевым трафиком, улучшенными
средствами обеспечения безопасности
и целостности данных, возможностью задания
бизнес-правил. Отметим также, что при
использовании современных средств проектирования
баз данных, и, в частности, CASE-технологии,
разработчик имеет возможность возложить
на сервер значительную часть проблем,
которые ранее были проблемами самих клиентских
приложений, что может существенно облегчить
их создание.
Сейчас мы рассмотрим для чего нужны DLL (Dynamic Link Library - динамически компануемая библиотека) и как их создавать. DLL- это участок кода хранимый в файле с расширением .dll. Код может быть использован другими программами, но сама посебе библиотека прораммой не является. Вобщем-то, динамически компонуемые библиотеки представляют собой набао скомпилированныых функций. Но у ютих библиотек есть свой особенности, так например, если каккието две или более программы для Windows одновременно исполняются и используют функции, находящиеся в одной DLL, то в памяти будет постоянно находится только одна библиотека, обеспечивая тем самым экономное расходование памяти. Загрузка библиотеки в память может быть статической и динамической.
При
статической загрузке DLL автоматически
загружается при запуске
При диамической загрузке вы можете загружать DLL при необходимости, выгрузить ее когода она ненужна. Однако работать с такими библиотеками сложнее чем со статическими. Рассмотрим созздание и использование DLL статической загрузки.
Создадим сперва проект (File / New / DLL). Будет создан проект, содержащий следующее:
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) {
return 1;
}
и длинный коментарий предупреждающий вас о том, что для работо способности вашей DLL необходимо снеи обеспечить поствку некоторых dll если вы используете экземпляры класса String.
Для экспорта и импорта из DLL необходимо использовать моди фикаторы __export и __import соответсвенно. Но в C++ Builder можно использовать новое ключевое слово __delspec() с параметрами dllexport и dllimport соответсвенно. Сами понимаете, что для того чтобы эспортировать функции из библиотеки еужен один заголовочный файл с описаниями _delspec(dllexport) для экспортируемых функций, для импорта функций в приложение вам необходимо будет поставить анологичный заголовочный файл но с _delspec(dllimport) описаниями, что достаточно неудобно. Эта проблема решается легко: добавте в заголовочный файл библиотеки следующее:
#if defined(BUILD_DLL)
# define DLL_EXP __declspec(dllexport)
#else
# if defined(BUILD_APP)
# define DLL_EXP __declspec(dllimport)
# else
# define DLL_EXP
# endif
#endif
в исходном файле DLL напишите #define BUILD_DLL, а вместо __declspec(dllexport) пишите DLL_EXP. При написании программы добавте строчку #define BUILD_APP, и просто подключите заголовочный файл DLL.
Пример DLL: файл P.cpp
//----------------------------
#define BUILD_DLL
#include
#include "p.h"
#pragma hdrstop
//----------------------------
// Important note about DLL memory management when your DLL uses the
// static version of the RunTime Library:
//
// If your DLL exports any functions that pass String objects (or structs/
// classes containing nested Strings) as parameter or function results,
// you will need to add the library MEMMGR.LIB to both the DLL project and
// any other projects that use the DLL. You will also need to use MEMMGR.LIB
// if any other projects which use the DLL will be perfomring new or delete
// operations on any non-TObject-derived classes which are exported from the