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

Разработка Windows - приложений в среде Borland. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
bool operator==(const staff& sl, const staff& sr){
return (sl.pay==sr.pay || sr.pay ==0) &&
( !strcmp(sl.name,sr.name) || sr.name[0] == '\0') && ( !strcmp(sl.job,sr.job) || sr.job[0] == '\0');
}
При таком определении операции «равно» два объекта счита­ются равными, если значения соответствующих полей равны либо поле в искомом образце (sr) не задано – равно нулю для оклада и пустой строке для имени или должности.
Добавьте в диалог кнопку «Поиск по шаблону», задайте функ­ции обработчику события BN_CLICKED для этой кнопки BNClickedPatternSearch и введите в заготовку функции инструк­ции:
// INSERT>> Your code here.
char buff[20];
if(crew.empty()){
MessageBox ("База пуста", "Поиск", MB_OK |
MB_ICONERROR); return; } EditPay -> GetText(buff, 20); staff st(atoi(buff), "", ""); EditName -> GetText(buff,20); strcpy(st.name,buff); ComboJob -> GetText(buff,20); strcpy(st.job,buff); vector <staff>::iterator k; k = find( crew.begin(), crew.end(), st); if( k == crew.end()){
MessageBox ("Клиент не найден", "Поиск", MB_OK |
MB_ICONERROR); return; } iCur = k - crew.begin(); ShowRecord();
В данном случае искомые значения полей должны быть заданы
в соответствующих полях диалога (создание дополнительного мо­дального диалога для этой цели будет рассмотрено в третьей главе).
61
имя
Например, ищем сторожа с окладом 10000. Сначала вводим искомые значения в поля диалога «должность» и «оклад», а поле «имя» очи­щаем:
Если теперь щелкнуть по кнопке «поиск по шаблону», про-
грамма будет искать сторожа с окладом 10000 и любым именем. Для того чтобы можно было искать сотрудников с любой должностью, например по имени и окладу, необходимо изменить тип комбиниро­ванного списка на “Dropdown”, так как список типа “Dropdown List” не позволяет очистить поле должность.
При
нажатии на кнопку «поиск по…» будет выполнен описан-
ный ранее поиск по полю, выбранному в группе переключателей.
Применение еще одного алгоритма – удаления записей (remove)
– рассматривается в разделе «Просмотр списка (элемент List View)» четвертой главы, где обсуждаются способы фильтрации и просмотра записей.
Ф
АЙЛЫ
Размер одной записи в байтах равен суммарному размеру полей
объекта, то есть величине sizeof(staff). Использование контейнера не влияет на размер записей. Поскольку в нашем контейнере все записи одинаковой длины (в байтах), удобно работать с бинарным файлом прямого доступа. Использование контейнера вместо массива не влияет на размер записей. Однако в отличие от
62
массива имя контей-
нера crew не является указателем на нулевой элемент, поэтому пер­вым параметром функции fwrite должен быть указан адрес нулевого элемента, то есть &crew[0].
Включите в заголовочный файл диалога wrkdlgcl.h директиву
препроцессора #include <stdio.h>. Добавьте в диалог кнопку «Сохра­нить», создайте для нее функцию - обработчик BNClickedSave, и поместите в тело функции инструкции:
// INSERT>> Your code here. FILE *fp; char buff[20]={0}; TInputDialog (this, "Введите имя файла", "Имя
buff, sizeof(buff)).Execute(); fp = fopen (buff, “wb”); if( !fp) {
MessageBox ("Не вышло... ", "Сохранение", MB_OK |
MB_ICONWARNING); return; }
fwrite(&crew[0], sizeof(staff), iMax, fp); // *** fclose (fp); MessageBox ("Получилось... ", "Сохранение", MB_OK | MB_ICONINFORMATION);
Здесь для задания имени файла применяется стандартный диа-
лог TinputDialog. По сравнению с функцией, подробно рассмотрен­ной в предыдущей главе, внесены изменения только в строчку, по­меченную комментарием «// ***».
Несколько сложнее ситуация с чтением из файла. Прежде всего
учтем возможность того, записей, а затем открыл файл. В этом случае, желательно, преду­смотреть возможности добавления записей из файла к уже имею­щимся, удаления записей, введенных перед считыванием из файла, или отказа от чтения. Для этих целей можно использовать значение, возвращаемое диалогом MessageBox в зависимости от нажатой кнопки. Например, если то значением функции MessageBox будет целочисленная константа IDYES (подробнее возвращаемые диалогом MessageBox значения рассматриваются в третьей главе). Соответствующие инструкции могут иметь вид:
что пользователь сначала ввел несколько
в диалоге MessageBox нажать кнопку «Да»,
63
файла",
int id; if( !crew.empty()){
id=MessageBox ("Оставить имеющиеся записи", "База не
пуста",
MB_YESNOCANCEL | MB_ICONQUESTION);
switch(id){
case IDYES: break;
case IDNO:
crew.erase(crew.begin(), crew.end());
iMax = crew.size(); break; case IDCANCEL: fclose(fp); return; }
}
Здесь для очистки вектора применен метод erase, поскольку в Bor- land 5.02 метод clear для вектора отсутствует.
Размер вектора у нас в точности равен количеству уже имею­щихся записей, поэтому считывать записи из файла будем по одной, добавляя их в конец вектора гично тому, как это делается при нажатии кнопки «Добавить». Кро­ме того, учтем, что функция feof возвращает значение true не после считывания последней записи, а после следующей попытки чтения. Поэтому мы будем читать из файла записи во вспомогательный объ­ект класса staff, а уж затем дописывать их Ограничим количество считанных из файла записей максимально допустимым размером вектора – его дает метод max_size. Тогда процедура чтения из файла в вектор может иметь вид:
staff st;
for(int i=0; i<crew.max_size() - iMax; i++){
fread( &st, sizeof(staff), 1, fp); if( feof(fp) ) break; crew.push_back(st);
}
Итак, добавьте в диалог кнопку «Открыть» и создайте функ­цию-обработчик BNClickedOpen. Предлагаемый код этой функции может выглядеть так:
с помощью метода push_back, анало-
в вектор. И последнее.
64
// INSERT>> Your code here.
FILE *fp;
char buff[20]={0};
TInputDialog (this, "Введите имя файла", "Имя файла",
buff, sizeof (buff)). Execute(); fp = fopen (buff, “wb”); if( !fp) {
MessageBox ("Не вышло... ", "Чтение", MB_OK |
MB_ICONWARNING);
return; } int id; if ( !crew.empty()){
id=MessageBox ("Оставить имеющиеся записи", "База не
пуста",
MB_YESNOCANCEL | MB_ICONQUESTION);
switch(id){
case IDYES: break; case IDNO:
crew.erase(crew.begin(), crew.end()); iMax = crew.size(); break;
case IDCANCEL: fclose(fp); return; } } staff st; for(int i=0; i<crew.max_size() - iMax; i++){
fread( &st, sizeof(staff), 1, fp); if( feof(fp) ) break;
crew.push_back(st); } iMax = crew.size(); fclose (fp); MessageBox ("Получилось…", "Чтение", MB_OK | MB_ICONINFORMATION); if(iMax>0) {
iCur = 0; ShowRecord(); }
}
65
З
АВЕРШЕНИЕ РАБОТЫ
Программы, с которыми Вы работаете, обычно при завершении
предлагают сохранить информацию, если она была изменена. Не­сложно и в нашем проекте предусмотреть такую проверку. У нас в диалоге доступны три кнопки завершения работы – “OK”, “CANCEL” и на кнопки OK и
. Однако действуют они по-разному. При нажатии
в частности будет вызвана виртуальная функция
CanClose, возвращающая значение типа bool. Если это значение равно false, завершение работы программы будет отменено. Мы мо­жем перегрузить эту функцию в нашем классе диалога Twork­DlgClient, подобно тому, как мы перегружали виртуальную функ­цию SetupWindow при работе с комбинированным списком. Итак, вызовите ClassExpert, в панели событий
Events раскройте список виртуальных методов → Virtual Functions, выберите функцию Set- upWindow и перегрузите её – контекстное меню → Add handler. При перегрузке этого виртуального метода имя функции задавать не нужно – оно предопределено – CanClose. В нижней панели
ClassExpert появится заготовка нужного метода:
bool TWorkDlgClient::CanClose() {
bool result;
66
result = TDialog::CanClose(); // INSERT>> Your code here.
return result;
}
Функция возвращает значение переменной result, которое пред­варительно устанавливается равным значению, возвращаемому функ­цией базового класса TDialog::CanClose. Мы это значение можем переопределить. Если наш вектор пуст, ничего делать не надо. Если же контейнер содержит записи, то, как и в предыдущем разделе, вы­ведем окно сообщений и используем значение, возвращаемое функ­цией MessageBox.
Если нажата кнопка «Отмена», завершение рабо-
ты отменяется, а если нажата кнопка «Да», вызовем метод диалога
BNClickedSave для сохранения информации:
bool TWorkDlgClient::CanClose()
{
bool result; result = TDialog::CanClose(); // INSERT>> Your code here. int id; if(!crew.empty()){
id = MessageBox("Сохранить? ", "База не пуста", MB_YESNOCANCEL | MB_ICONWARNING); if(id == IDCANCEL) result=false;
if(id == IDYES) BNClickedSave(); } return result; }
Проверьте, все должно работать. Правда есть один недостаток:
если сохранить информацию не удалось, будет выведено предупре­ждение, а затем программа все-таки завершит работу. Замените
ин-
струкцию:
If (id == IDYES) BNClickedSave();
67
на:
if (id == IDYES) {BNClickedSave(); result=false;}
а теперь программа не завершит работу даже после удачного сохра­нения! Попробуйте сами, если, конечно, возникнет такое желание, добиться того, чтобы в случае удачного сохранения приложение за­канчивало работу. Кроме того, сохранение не требуется, если ин­формация была считана из файла, но не редактировалась. То есть если пользователь не «Изменить».
К настоящему моменту создано вполне работоспособное при-
ложение, решающее все поставленные нами перед собой задачи. Это, конечно, не означает того, что больше нельзя ничего улучшить. Можно переработать интерфейс пользователя, подключить меню, использовать иллюстрации, другие элементы управления, стандарт­ные диалоги открытия/сохранения файлов, создать дополнительные диалоги и т.п. Эти вопросы рассматриваются в последующих главах.
Кроме того, в приведенных фрагментах кода сознательно не
были использованы многие компоненты языка C++. Например, для работы с текстовой информацией вместо символьных массивов фик­сированной длины можно применить динамические массивы или объекты класса string. Не использовались потоковые классы при ор­ганизации процессов бок и повышения надежности программы стоило бы применить ме­ханизм исключений и т.д. Основной причиной такого игнорирова­ния возможностей языка C++ являлось желание максимально упро­стить предлагаемые фрагменты кода, по возможности, не требуя от читателя глубоких знаний. Напомню, что данное пособие не предна­значено для ется, что читатель обладает необходимыми базовыми знаниями и способен самостоятельно найти дополнительные сведения в литера­туре.
изучения языка программирования C/C++. Предполага-
нажимал кнопки «Добавить», «Удалить» или
ввода/вывода. Для перехвата возможных оши-
68
ГЛАВА III. РЕСУРСЫ, ОКНА, ДИАЛОГИ
ЕНЮ И АКСЕЛЕРАТОРЫ
М
До сих пор наши операции с базой данных ограничивались воз-
можностью выбора той или иной командной кнопки. Рассмотрим теперь, каким образом можно расширить интерфейс пользователя с помощью системы меню и использования акселераторов (клавиш быстрого доступа). Меню является привычным и практически обя­зательным элементом большинства приложений, и, кроме того, по­зволяет
«разгрузить» окно диалога – ведь невозможно добавлять
кнопки на все случаи жизни.
Загрузите проект, созданный в предыдущей главе. Откройте ре-
дактор ресурсов и выберите в контекстном меню пункт New Re­source (новый ресурс). Такой вид окно ресурсов приобретет после описанного в первой главе редактирования файлов workapp.rc и workapp.rh. Если вы не стали сокращать эти файлы,
то у вас уже есть ресурс меню, что не мешает создать ресурс еще одного меню. В про­грамме будет видно только то меню, которое вы подключите, указав его идентификатор. Вызовите контекстное меню редактора ресурсов и выберите пункт New Resource (или выберите в основном меню Resource пункт New Resource):
В появившемся диалоге выберите тип нового ресурса – MENU:
69
и, нажав на кнопку “Options”, вид заготовки меню – Simple menubar. Можно выбрать и другой вид, но придется больше редактировать заготовку меню. Впрочем, попробуйте. Остальные параметры опций не стоит менять. Подтвердите выбор вида и типа меню – кнопка “OK”. Вы окажитесь в режиме редактирования меню:
Внизу должно появиться окно свойств – Property Inspector. Если его нет, вызовите, как показано на рисунке, в контекстном меню пункт Show Property Inspector. Обратите внимание, что в основном меню среды Borland появился пункт меню «Menu», которое можно использовать при редактировании меню в нашем приложении наря­ду с контекстным меню. Закройте кнопкой меню и вернитесь в окно редактора ресурсов:
окно редактирования
70
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]