Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Разработка Windows - приложений в среде Borland. Учебное пособие
.pdf
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, завершение работы программы будет отменено. Мы можем перегрузить эту функцию в нашем классе диалога TworkDlgClient, подобно тому, как мы перегружали виртуальную функцию 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 Resource (новый ресурс). Такой вид окно ресурсов приобретет после
описанного в первой главе редактирования файлов workapp.rc и
workapp.rh. Если вы не стали сокращать эти файлы,
то у вас уже есть
ресурс меню, что не мешает создать ресурс еще одного меню. В программе будет видно только то меню, которое вы подключите, указав
его идентификатор. Вызовите контекстное меню редактора ресурсов
и выберите пункт New Resource (или выберите в основном меню
Resource пункт New Resource):
В появившемся диалоге выберите тип нового ресурса – MENU:
69

и, нажав на кнопку “Options”, вид заготовки меню – Simple menubar.
Можно выбрать и другой вид, но придется больше редактировать
заготовку меню. Впрочем, попробуйте. Остальные параметры опций
не стоит менять. Подтвердите выбор вида и типа меню – кнопка
“OK”. Вы окажитесь в режиме редактирования меню:
Внизу должно появиться окно свойств – Property Inspector. Если
его нет, вызовите, как показано на рисунке, в контекстном меню
пункт Show Property Inspector. Обратите внимание, что в основном
меню среды Borland появился пункт меню «Menu», которое можно
использовать при редактировании меню в нашем приложении наряду с контекстным меню. Закройте кнопкой
меню и вернитесь в окно редактора ресурсов:
окно редактирования
70
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
