Стоит Windows 8 Pro, Visual Studio 2010 Express Edition . |
Самостоятельная работа 15: Создание СУБД средствами BDE (на примере протокола экзамена кандидатов в водители)
Программирование контекстного меню
Теперь продублируем наиболее важные команды управления данными через контекстное меню. Контекстное меню привяжем к компоненту DBGrid1.
- Поместите на форму невизуальный компонент PopupMenu из вкладки Standard и определите его свойство Name=PopupRecord.
- Выделите на форме элемент DBGrid1 и присоедините к нему это контекстное меню, задав значение свойства PopupMenu=PopupRecord.
- Двойным щелчком на компоненте с именем PopupRecord вызовите редактор меню, в котором определите свойства в соответствии с таблицей
Теперь внешне в редакторе контекстное меню должно выглядеть так
Теперь нужно прикрепить к опциям контекстного меню нужные обработчики, чтобы продублировать опции раздела Edit главного меню. Прикреплять обработчики будем по такой же схеме, что и для главного меню: вызовем двойным щелчком на компоненте TPopupMenu редактор меню. Установим инструмент Object Inspector на вкладку Events. В редакторе меню будем выделять соответствующий пункт, а в инспекторе объектов в поле события OnClick в раскрывающемся списке будем выбирать нужный обработчик.
- Выполните закрепление обработчиков за всеми тремя опциями контекстного меню
- Запустите приложение и проверьте работоспособность всех меню.
Программирование строки состояния
В нижней части формы мы разместили ранее строку состояния StatusBar1. В ней должны отображаться длинные подсказки о назначении элементов пользовательского интерфейса, если пользователь наведет курсор на соответствующий элемент управления.
Приложение в C++Builder является объектом Application, определенным по умолчанию. Когда свойство ShowHint объекта Application имеет значение true (значение по умолчанию) и курсор мыши находится над компонентом запущенного приложения, то независимо от того, включено или нет свойство ShowHint этого компонента, генерируется событие Hint родительского объекта Application. При этом значение свойства Hint объекта компонента копируется в значение Hint объекта Application. Если перехватить и обработать событие OnHint объекта Application и в нем вывести поступившее от компонента значение свойства Hint в строку состояния, то получим управление подсказками. Перехватим событие OnHint объекта приложения TApplication, для чего переопределим в своем приложении его обработчик
-
Добавьте в описание класса TMainForm файла UMain.h объявление функции-обработчика
Объявление функции-обработчика события OnHint class TMainForm : public TForm { ............................................ private: // User declarations int countRecord; public: // User declarations __fastcall TMainForm(TComponent* Owner); private: void __fastcall OnHint(TObject *Sender); };
Модификатор __fastcall нужно указывать обязательно для согласования с библиотечным форматом метода OnHint.
-
Добавьте в конец файла UMain.cpp определение функции-обработчика
Определение функции-обработчика события OnHint void __fastcall TMainForm::OnHint(TObject *Sender) { StatusBar1->SimpleText = Application->Hint; }
- Включите панель View/ClassExplorer, найдите в ней функцию FormCreate (мы ее создавали ранее) и двойным щелчком быстро адресуйтесь к ней в текстовом редакторе.
-
Другой способ быстрой адресации :
Выберите главную форму MainForm в селекторе объектов Object TreeView. Переключитесь на вкладку Events в инспекторе объектов, найдите созданный нами ранее обработчик события OnCreate для главной формы. Двойной щелчок на поле значений обработчика приведет к быстрой адресации к его коду в текстовом редакторе.
-
Введите переадресацию события OnHint приложения на нашу функцию-обработчик (ключевое слово this в данном коде указывать необязательно)
Переадресация на наш обработчик void TMainForm::FormCreate(TObject *Sender) { Table1->Open(); countRecord = Table1->RecordCount; // Настройка подсказок строки состояния Application->OnHint = &this->OnHint; }
Теперь все готово для отображения длинных подсказок объектом приложения. Но нужно ввести в каждый компонент интерфейса (кнопки, пункты меню) сами подсказки. Для этого нужно последовательно выделять каждый компонент приложения, включать свойство ShowHint, если мы хотим отображения всплывающих (коротких) подсказок, и заполнять нужным текстом свойство Hint по формату
всплывающая_подсказка | текст_строки_состояния
-
Выделите в режиме Design кнопку btnBof на панели инструментов. Проверьте, что свойство ShowHint для отображения всплывающей подсказки включено, а в свойство Hint добавьте текст
В начало|Перейти на первую запись таблицы
-
Повторите эти шаги для других элементов в соответствии с таблицей. Для выделения компонентов меню пользуйтесь редактором меню или инструментом Object TreeView. Следите за тем, чтобы для кнопок и соответствующих пунктов меню текст подсказок был одинаков, иначе можно ввести в заблуждение, утомить и огорчить бедного пользователя. Обратите внимание, что для объектов-пунктов меню свойство ShowHint отсутствует, поскольку всплывающие подсказки для них не предусмотрены, чтобы не создавать избыточности информации. Поэтому в свойстве Hint опций меню можно короткую подсказку не указывать (а можно и указать, только она не будет отображаться).
- Запустите проект и проверьте функционирование длинных подсказок.
Программирование выхода
При завершении работы приложения нам нужно проверить, сохранялись ли на диске последние изменения данных, выполненные пользователем. Несохраненные изменения можно обнаружить по цвету панели Panel1->Color == clRed. Но это будет промежуточный признак, на который лучше не операться, поскольку мы можем его изменить и забыть, что от него зависит дальнейшая логика кода. Проверять нужно специально введенный флаг, который будем поднимать при любых изменениях в данных.
-
Введите в класс TMainForm файла UMain.h объявление логической переменной flagIsModified
Объявление флага изменения данных в классе TMainForm class TMainForm : public TForm { .............................................. private: // User declarations int countRecord; bool flagIsModified; public: // User declarations __fastcall TMainForm(TComponent* Owner); private: void __fastcall OnHint(TObject *Sender); };
-
Инициализируйте флаг в функции-обработчике события OnCreate формы
Инициализация флага изменения данных void __fastcall TMainForm::FormCreate(TObject *Sender) { Table1->Open(); countRecord = Table1->RecordCount; flagIsModified = false; // Настройка подсказок строки состояния Application->nHint = &this->OnHint; }
Для установки признака модификации данных используем события компонента Table1
- Выделите компонент Table1 и через вкладку Events инспектора объектов создайте (вначале заполните поле с именем, затем нажмите клавишу Enter ) обработчик для события AfterEdit с именем DataModified
-
Заполните обработчик следующим кодом поднятия флага модификации данных
Код обработчика поднятия флага модификации данных void __fastcall TMainForm::DataModified(TDataSet *DataSet) { flagIsModified = true; Panel1->Color = clRed; }
Обратите внимание, что в обработчике мы предусмотрели изменение цвета панели Panel1 в одном месте, а ранее мы вынуждены были размещать его в нескольких обработчиках. Найдите такой код в обработчиках btnInsertClick, btnAppendClick, btnDeleteClick и удалите его, после чего обработчики должны выглядеть так
Удаляем излишний код в обработчиках void __fastcall TMainForm::btnInsertClick(TObject *Sender) { Table1->Insert(); // Panel1->Color = clRed; } //--------------------------------------------------------------------------- void __fastcall TMainForm::btnAppendClick(TObject *Sender) { DBGrid1->SelectedIndex = 0; // Выделить первое поле Table1->Append(); // Panel1->Color = clRed; } //--------------------------------------------------------------------------- void __fastcall TMainForm::btnDeleteClick(TObject *Sender) { Table1->Delete(); // Panel1->Color = clRed; }
- Этот же обработчик DataModified прикрепите к событиям AfterDelete и AfterInsert
-
В обработчике btnSaveClick поместите код сброса флага
Код обработчика сброса флага модификации данных void __fastcall TMainForm::btnSaveClick(TObject *Sender) { Panel1->Color = clGreen; if(!Table1->Modified && !flagIsModified) return; Table1->Edit(); Table1->Post(); Table1->Close(); Application->ProcessMessages(); //Прокачка сообщений Table1->Open(); flagIsModified = false; // countRecord = Table1->RecordCount; }
Обратите внимание, что прежний признак countRecord нам теперь не нужен, поскольку мы ввели более универсальный флаг модификации.
- Удалите из кода все, что связано с переменной countRecord, включая ее объявление в файле UMain.h
Теперь, когда мы имеем флаг flagIsModified, поддерживаемый в актуальном состоянии, можно приступать к коду завершения приложения. Приложение можно завершить щелчком по кнопке системного меню (кнопка-крестик) или программным путем с помощью выполнения метода Close() главной формы (а у нас пока всего одна форма и есть).
-
Создайте обработчик для элемента меню FileExit опции Файл/Выход завершения приложения программным путем и заполните его так
Обработчик опции FileExit завершения приложения void __fastcall TMainForm::FileExitClick(TObject *Sender) { this->Close(); }
Для того, чтобы проверить, сохранялись изменения перед завершением или нет, воспользуемся событием OnCloseQuery формы, в обработчике которого предупредим пользователя о несохраненных изменениях, если таковые будут. В обработчик события OnCloseQuery передается ссылка на булеву переменную CanClose, которая является флагом продолжения закрытия и изначально равна true. Если эту переменную сбросить, то закрытие формы прекратится.
-
Через инструмент Object TreeView выделите экземпляр MainForm, откройте вкладку Events и двойным щелчком на событии OnCloseQuery создайте обработчик с со следующим кодом
Обработчик события закрытия формы void __fastcall TMainForm::FormCloseQuery(TObject *Sender, bool &CanClose) { if(flagIsModified) { int result = Application->MessageBox( "Сохранить изменения в данных?", "Завершение работы...", MB_YESNOCANCEL | MB_ICONWARNING ); switch(result) { case IDYES: btnSaveClick(Sender); // Вызвали наш обработчик break; case IDCANCEL: CanClose = false; return; } Table1->Close(); } }
-
Подобным же образом предупредите пользователя при удалении записи в обработчике btnDeleteClick
Дополнение обработчика btnDeleteClick void __fastcall TMainForm::btnDeleteClick(TObject *Sender) { int result = Application->MessageBox( "Удалить запись?", "Удаление", MB_YESNO | MB_ICONWARNING ); if(result == IDYES) Table1->Delete(); }
- Испытайте новые возможности. Теперь при удалении записи или попытке выхода при несохраненных изменениях будут выдаваться следующие окна сообщений
Создание СУБД средствами BDE (на примере протокола экзамена кандидатов в водители)
Передача результатов экзамена
Кандидат в водители, сдававший теоретический экзамен на другой программе, ответил на двадцать вопросов. Его ответы экзаменационная программа сохранила в промежуточном файле tmp_base.dbf, структура которого показана в таблице
Структура таблицы tmp_base.dbf | ||||
---|---|---|---|---|
Field Name | Type | Size | Dec | Пояснения |
Name | Numeric | 3 | 0 | Регистрационный номер экзаменуемого (уникальный идентификатор результатов, равный значению поля Number в таблице Base0.dbf) |
Question | Numeric | 3 | 0 | № ответа (№ записи в файле Exam.dbf, в котором хранятся номера вопросов) |
Answer | Numeric | 1 | 0 | № правильного ответа |
Result | Logical | 1 | Да/Нет (Верно/Неверно) | |
Time | Numeric | 2 | 0 | Время в секундах, затраченное на ответ |
Сама промежуточная таблица может выглядеть так