Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Разработка Windows - приложений в среде Borland. Учебное пособие
.pdf
bool CompName(const staff& sl, const staff& sr){
return strcmp(sl.name,sr.name)<0;
}
bool CompJob(const staff& sl, const staff& sr){
return strcmp(sl.job,sr.job)<0;
}
Теперь мы можем добавить в диалог новую кнопку, например
«сортировка по должности», и поместить в тело соответствующей
функции обработчике нажатия на эту кнопку инструкции:
if(iMax == 0){
MessageBox ("База пуста", "Сортировка", MB_OK |
MB_ICONERROR); return;
}
sort(crew.begin(), crew.end(), CompJob);
iCur=0; ShowRecord();
Плодить кучу кнопок, конечно, можно, но лучше перенести вы-
зовы операций сортировки в меню (создание меню см. в третьей
ве) или использовать для выбора типа сортировки группу переключателей. Рассмотрим вариант с использованием переключателей.
гла-
Поместите в окно диалога рамку
свойство Caption – «упорядочить по…» и разместите внутри рамки
три переключателя (элементы управления Radio Button
переключатели внутри рамки не видны, выделите рамку, вызовите
для нее контекстное меню и выберите пункт “Send to Back” – поместить рамку на задний план.
Для того чтобы переключатели функционировали как единая
группа, то есть мог быть выбран только один переключатель в рамке, необходимо в свойствах первого переключателя поставить флажок Group Flag и
свойство Group Flag было отключено.
проверить, чтобы у остальных переключателей
(элемент Group Box), задайте
). Если
51

Далее в контекстном меню элемента (или в основном меню Dia-
log) выберите пункт Set Creation Order (порядок создания элемен-
тов):
52

Вместо всех элементов управления нашего диалога мы видим
их условные обозначения с числом, соответствующим порядку их
создания. Наши переключатели имеют номера 19, 20 и 21, то есть
создаются подряд один за другим. Именно это и требуется для переключателей, работающих как единая группа. Если порядок создания
не правилен, можно просто щелкнуть по элементам в
довательности. Например, начните с элемента 19. Он станет первым
и изменится порядок создания остальных элементов. После установления необходимого порядка нужно вызвать контекстное меню и
либо подтвердить новый порядок – End Mode, либо вернуться к старому порядку – Cancel Mode. Впрочем, можно просто нажать клавиши Enter или Esc.
Назовите переключатели (задайте свойство Caption) – «по име-
ни», «
переключатели (Class Expert → Add Instance variable), соответственно rbnName, rbnJob и rbnPay. Для того чтобы сразу после появления
окна диалога была выбрана опция «по имени», откройте модуль
wrkdlgcl.cpp и добавьте в конец метода SetupWindow инструкцию:
GetCheck возвращает значение состояния переключателя. Если это
значение
бранный. Теперь измените код функции BNClickedSort на инструкции:
по должности» и «по окладу». Задайте имена указателям на
rbnName-> Check();
Метод Check помечает переключатель как выбранный, а метод
равно BF_CHECKED, то переключатель помечен как вы-
if(crew.empty()){
MessageBox ("База пуста", "Сортировка", MB_OK |
MB_ICONERROR); return;}
if ( rbnPay->GetCheck() == BF_CHECKED)
sort(crew.begin(),crew.end());
if ( rbnJob->GetCheck() == BF_CHECKED)
sort(crew.begin(),crew.end(),CompJob);
if ( rbnName->GetCheck() == BF_CHECKED)
sort(crew.begin(),crew.end(),CompName);
iCur=0; ShowRecord();
нужной после-
53

Следующая операция – поиск. Стандартный алгоритм find, име-
ющийся в библиотеке STL осуществляет поиск экземпляра последовательности, равного заданному объекту в диапазоне, заданном двумя итераторами. Результатом поиска является итератор, указывающий на первый найденный экземпляр или итератор, являющийся
следующим за последним в последовательности (значение такого
итератора дает метод end). Не стоит забывать
деляется с помощью заданной в классе операции “==” (равно). В
нашем случае два экземпляра класса staff равны, если равны соответствующие оклады. Например:
vector <staff>::iterator k;
k = find( crew.begin(), crew.end(), staff(1000, “”, “”));
значение k будет равно итератору на первую запись, в которой значение оклада равно 1000 либо значению crew.end(). Имена и должности сотрудников игнорируются. Если требуется найти следующую
запись с окладом 1000 можно продолжить поиск, задав в качестве
первого параметра итератор ++k:
k = find( ++k, crew.end(), staff(1000, “”, “”));
Искомое значение оклада можно задать с помощью стандартно-
го диалога TInputDialog или считать из соответствующего поля окна.
При втором подходе, прежде чем осуществлять поиск, необходимо
ввести искомое значение в поле «оклад». В случае если поиск оказался успешным
не дал результатов, требуется вывести соответствующее сообщение.
Итак, добавьте в диалог кнопку «Поиск», задайте имя функции
обработчика – BNClickedSearch и наберите инструкции:
// INSERT>> Your code here.
char buff[40];
if(crew.empty()){
MessageBox ("База пуста", "Поиск", MB_OK |
MB_ICONERROR); return;
}
EditPay -> GetText(buff,20); // ***
staff st(atoi(buff),"","");
, найденная запись становится текущей. Если поиск
54
, что равенство опре-

vector <staff>::iterator k;
k = find( crew.begin(), crew.end(), st);
if( k == crew.end()){
wsprintf(buff,"Оклад %i\n не найден",st.GetPay());
MessageBox(buff,"Поиск",MB_OK | MB_ICONERROR);
return;
}
iCur = k - crew.begin();
ShowRecord()
Как видно из строки, помеченной комментарием «// ***», иско-
мое значение оклада будет считано из поля EditPay диалога. В следующей строке создается образец для поиска. Здесь значения полей
класса заданы с помощью конструктора, так как если применить метод SetPay (аналогично реализации операции «Добавить» в методе
BNClickedAdd),
ровано. Напоминаю, что вычисление разности двух итераторов для
определения текущего индекса возможно не для всех типов контейнеров. В общем случае необходимо использовать функцию distance.
Если есть потребность задания искомого значения оклада с по-
мощью стандартного диалога TInputDialog, нужно вместо строки,
помеченной комментарием «// ***», поместить инструкции:
buff[0]='\0';
TInputDialog (this, "Поиск", "Введите искомый оклад",
buff,sizeof(buff)).Execute();
Не забудьте добавить в файл wrkdlgcl.cpp директиву препро-
цессора:
#include <owl/inputdia.h>
и в файл workapp.rc директиву:
#include <owl/inputdia.rc>
(если не вспомните, куда и как добавлять, посмотрите первую главу).
значения оклада меньше чем 850 будет скорректи-
55

Проверьте работу приложения:
Не сложно также реализовать поиск по различным полям. Для
решения этой задачи можно воспользоваться алгоритмом find_if,
третьим параметром которого должен быть указан функциональный
объект (класс, в котором определена операция вызова функции [2,
4]). Добавьте (раскомментируйте) в интерфейс класса staff (файл
staff.h) после объявления:
friend bool operator==(const staff& sl, const staff& sr);
объявление двух дружеских функций:
friend bool SearchName(staff sl, staff sr);
friend bool SearchJob(staff sl, staff sr);
а в модуле реализации класса (staff.cpp) раскомментируйте
ление этих функций:
bool SearchName(staff sl, staff sr){
return !strcmp(sl.name,sr.name);
}
56
опреде-

bool SearchJob(staff sl, staff sr){
return !strcmp(sl.job,sr.job);
}
Можно добавить две кнопки для поиска по имени и должности
и поместить в соответствующие функции обработчики инструкции,
аналогичные приведенным выше, поменяв вызов алгоритма find:
k = find( crew.begin(), crew.end(), st);
на вызов функции find_if:
k = find_if(crew.begin(),crew.end(), bind2nd(ptr_fun(SearchName), st)
);
Здесь функция – адаптер ptr_fun преобразует указатель на
функцию SearchName в функциональный объект, а связыватель
bind2nd заменяет правый операнд условия равенства на образец st,
то есть
взяты из модуля staff.cpp). Остается поменять текст сообщений и
задаваемый параметр в конструкторе при создании искомого экземпляра класса staff. Окончательно код функции BNClickedSearch
примет вид:
превращает условие sl == sr в условие sl == st (обозначения
// INSERT>> Your code here.
char buff[40];
if(crew.empty()){
MessageBox ("База пуста", "Поиск", MB_OK |
MB_ICONERROR); return;
}
buff[0]='\0'; //***
TInputDialog (this, "Поиск", "Введите искомое имя", //***
buff,sizeof(buff)).Execute(); //***
staff st( 0, buff, ""); //***
vector <staff>::iterator k;
k = find_if(crew.begin(),crew.end(), bind2nd(ptr_fun(SearchName),
st) );//***
if( k == crew.end()){
wsprintf(buff, "Клиент \"%s\"\n не найден", st.name); //***
57

MessageBox (buff, "Поиск", MB_OK | MB_ICONERROR);
return;
}
iCur = k - crew.begin();
ShowRecord();
В этом фрагменте кода искомое имя задается с помощью диало-
га TInputDialog. Комментарием "//***" отмечены строки, измененные по сравнению с приведенным ранее текстом функции BNClicked-
Search.
Вместо добавления дополнительных кнопок для поиска можно
воспользоваться тем же самым блоком переключателей, который
обсуждался при рассмотрении операций сортировки. Создайте группу переключателей, если
пы на «Поиск/Сортировка» и отредактируйте код функции BNClicked-
Search:
// INSERT>> Your code here.
char buff[40];
if(crew.empty()){
MessageBox ("База пуста", "Поиск", MB_OK |
MB_ICONERROR); return;
}
buff[0]='\0';
staff st;
vector <staff>::iterator k;
if( rbnPay->GetCheck() == BF_CHECKED){
TInputDialog (this, "Поиск", "Введите искомый оклад",
buff,sizeof (buff)). Execute();
st = staff (atoi(buff),"","");
k = find ( crew.begin(), crew.end(), st);
wsprintf (buff,"Оклад %i\n не найден", st.GetPay());
}
If ( rbnJob->GetCheck() == BF_CHECKED){
TInputDialog (this, "Поиск", "Введите искомую должность",
buff,sizeof(buff)).Execute();
st = staff(0,"",buff);
k = find_if(crew.begin(),crew.end(), bind2nd(ptr_fun(SearchJob),
st) );
не сделали это ранее. Поменяйте имя груп-
58

wsprintf (buff, "Должность \"%s\"\n не найдена", st.job);
}
if( rbnName->GetCheck() == BF_CHECKED){
TInputDialog (this, "Поиск", "Введите искомое имя",
buff,sizeof(buff)).Execute();
st = staff(0,buff,"");
k = find_if (crew.begin(), crew.end(), bind2nd (ptr_fun
(SearchName), st) );
wsprintf (buff,"Клиент \"%s\"\n не найден",st.name);
}
if( k == crew.end()){
MessageBox (buff, «Поиск», MB_OK | MB_ICONERROR);
return;
}
iCur = k - crew.begin();
ShowRecord();
В зависимости от выбранной опции в группе переключателей
после нажатия кнопки «Поиск» будет выполнен поиск по имени,
должности либо окладу сотрудников:
59

До сих пор рассматривались простые варианты операций сортировки и поиска – по одному выбранному полю. При этом для каждого поля мы описывали свою функцию, определяющую результат
сравнения двух объектов. Между тем, достаточно определить только
операции «меньше» и «равно» для реализации более сложных алгоритмов сортировки и поиска. Например, если наша
предназначена для «Бюро знакомств», в ней может храниться информация по росту и весу клиента. В этом случае можно осуществлять сортировку по «нормальному» весу – по разнице между ростом
и весом. Достаточно в реализации операции «меньше» определить,
что один объект меньше другого, если разность между ростом и весом одного объекта меньше этой разности второго.
Нетрудно осуществить и многоуровневую сортировку. Замените определение операции «меньше» в файле staff.cpp:
bool operator<(const staff& sl, const staff& sr){
return sl.pay < sr.pay;
}
на следующее:
bool operator<(const staff& sl, const staff& sr){
return sl.pay < sr.pay || (sl.pay == sr.pay && strcmp
(sl.name,sr.name)<0);
}
Если теперь выбрать «сортировку по окладу», то записи будут
упорядочены по размеру оклада, а записи с одинаковым значением
оклада будут дополнительно упорядочены и по имени
Произвольный поиск по шаблону можно реализовать, описав,
соответственно, более сложное условие равенства двух объектов при
перегрузке операции «равно».
Замените определение операции «равно» в файле staff.cpp:
bool operator==(const staff& sl, const staff& sr){
return sl.pay==sr.pay;
}
на следующее:
60
база данных
сотрудника.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
