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

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

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
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
база данных
сотрудника.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]