Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Сценарий выполнения работы. Приложение с таблицей




Вариант 1

Приложение с таблицей

Try

Класс TVector с перегруженными операциями

Пример класса TVector

Класс вектор

Программы без ошибок можно написать двумя способами, но работает — третий

Закон Мерфи

Цель работы – разработать собственный (конечно же, гениальный!) класс, предназначенный для обработки массивов чисел (4 час.)

Задание. Требуется разработать свой собственный класс, облегчающий работу с числовыми массивами. Класс должен иметь, помимо конструктора (ов) и деструктора, перечисленные в табл. 1 методы.

Таблица 1

Методы класса

Метод Назначение
Size Возвращает фактическое число элементов массива
Capacity Возвращает число элементов массива, для которых зарезервирована память
SetCapacity Позволяет задать число элементов массива, для которых должна быть зарезервирована память
SetElem Задать значение элемента массива с заданным индексом
GetElem Получить значение элемента массива с заданным индексом
InsertElem Вставить в заданную позицию новый элемент массива
DeleteElem Удалить элемент массива с заданным индексом
AddElem Добавить новый элемент в конец массива
InsertVec Вставить в заданную позицию данного массива другой массив
DeleteVec Удалить заданное число элементов массива, начиная с элемента с заданным индексом
AddVec Добавить новый массив в конец данного массива
SortVec Отсортировать массив в заданном порядке

 

Класс должен быть реализован таким образом, чтобы тип его элементов можно было изменить или задать наиболее безболезненным способом. Методы класса должны быть оптимизированы по времени. Это, в частности, значит, что вставка или удаление нескольких элементов массива (методы InsertVec() и DeleteVec()) не должна быть сведена к многократному вызову методов вставки и удаления одного элемента массива.

В работе также требуется реализовать программу – главную функцию, которая позволит тестировать методы класса. Уделите коду тестирования должное внимание, чтобы можно было как можно более легко и просто реализовать как корректные операции по использованию класса вектор, так и ошибочные.

Методические указания. При реализации класса можно воспользоваться примером класса TVector, приведенном в конспекте лекций и ниже.

Для отслеживания вызовов конструкторов и деструкторов класса рекомендуется поместить в них макросы TRACE, которые будут выводить в окно Debug соответствующие сообщения. Можно, естественно, поместить эти макросы и в другие функции класса.

 

Этот пример реализован в проекте Vector (консольное приложение с поддержкой MFC). Содержимое заголовочного файла TVector.h (директивы препроцессора и компилятора опущены):

Содержимое файла реализации TVector.cpp (директивы препроцессора и компилятора опущены):

 

Тестирование класса:

 

Хотелось бы при работе с массивом, т.е. классом TVector, иметь возможность использовать операцию [] доступа к элементу массива по индексу для того, чтобы получить значение элемента массива или модифицировать его. Совсем не вредно, чтобы при этом класс проверял корректность индекса с тем, чтобы не было попыток выхода за границы массива. Ну и еще хотелось бы иметь возможность вывода значений всех элементов массива с помощью стандартного потока cout. Все это, и многое другое, действительно возможно выполнить с помощью перегрузки операций. Для того чтобы все эти мечты воплотить в жизнь, надо в объявление класса (файл TVector.h) добавить такие описания:

Если перегруженную операцию включения вектора в поток вывода ostream Вы включаете в тело класса, т.е. в файл TVector.h, то не забудьте в начале этого файла добавить директиву using namespace std. Впрочем, если Вы этого не сделаете – не страшно: компилятор выдаст сообщение об ошибке, не понимая имени ostream.

В файл реализации класса TVector.срр остается добавить реализацию функции, выполняющей перегрузку операции доступа к элементам массива по индексу:

 
 

 

Теперь в программе, использующей данный класс, можно использовать выражения такого вида:

TVector MyVec(3,5,-1);

cout<<MyVec; // вывод всех элементов массива

MyVec[k]=12.3; // присваивание значения к-тому элементу массива

ElemType Val= MyVec[k]; // получение значения к-того элемента массива

 

Если Вы внимательно посмотрите на функцию перегрузки операции [], то у Вас, наверное, возникнет вопрос: а что функция вернет, если индекс будет вне границ массива? А неизвестно что, т.е. случайное значение, что не есть хорошо. Ну и как же быть в этом случае? Приемлемым выходом является генерация исключительной ситуации (исключения), которую может перехватить вызывающая функция. Текст функции перегрузки операции [] можно в этом случае записать так:

 

В этом случае вызывающая функция может поступать таким образом:

{

// …

MyVec[i]=0;

// …

}

catch(char * Mes)

{

AfxMessageBox(Mes);

}

 

Если при вычислении выражения MyVec[i] индекс будет вне диапазона, выполнится оператор, указанный в блоке catch, т.е. в данном случае на дисплее будет показано окно с текстом "Bad index". Естественно, что в реальной программе для обработки такой ошибки надо реализовать что-то более целесообразное, чем вывод такого бестолкового сообщения пользователю Вашей программы.


 


По мере увеличения размера программы средняя наработка на отказ постоянно уменьшается

Цель работы – освоить приемы разработки приложения, выполняющего вывод данных в форме таблицы и их сортировку (4 час.).

Задание.

Ознакомьтесь с методическими указаниями и выполните работу в соответствии с приведенным ниже сценарием. Вариант 1 работы выполняется на компьютерах с нечетными номерами, а вариант 2 – соответственно на остальных компьютерах.

После получения работоспособного приложения внесите в него свою изюминку: добавьте в структуру TStudent компоненту вещественного типа и обеспечьте корректную сортировку элементов списка и по этой компоненте. Вы можете поменять структуру TStudent и ее поля на любые другие по своему желанию, но число полей структуры и, соответственно, столбцов таблицы должно быть не менее трех.

Даже чайник знает, что список файлов, выводимый в окне Проводника Windows, можно сортировать путем щелчка по заголовку соответствующего столбца таблицы. В данной работе приводится сценарий создания приложения, в котором на основе управляющего элемента List Control (MFC класс CListCtrl) показана последовательность создания подобного списка.

Шаг 1. Создайте заготовку приложения, включающего поддержку MFC и архитектуры документ-вид. В качестве базового для класса вида выберите класс CFormView для того, чтобы можно было в окне приложения разместить управляющий элемент List Control. Предполагается, что проекту присвоено имя SL (Sort List).

Шаг 2. В окне приложения разместите управляющий элемент List Control и задайте для него значение свойства View==Report. Можно собрать приложение, запустить его на выполнение и убедиться в том, что среда MVS способна создавать работоспособные каркасы приложений (рис. 1). Строки и столбцы списка, по сути дела таблицы, нам придется создавать путем написания программного кода, а не путем задания каких-либо свойств управляющих элементов, как это реализовано в Delphi.

 

 
 

Рис. 1. Окно приложения с элементом List Control

 

Шаг 3. Создание столбцов таблицы. Первым делом с помощью мастера создадим переменную objList (рис. 2) для получения доступа к нашему управляющему элементу список как к экземпляру класса CListCtrl.

 

 
 

 

Рис. 2. Добавление переменной objList, являющейся объектом класса CListCtrl

 

Далее добавим в функцию CSLView::OnInitialUpdate() код, который задает число столбцов в списке и их наименования, отображаемые в заголовке списка:

 
 

 

Назначение членов структуры LV_COLUMN можно (и нужно!) узнать из MSDN.

 

Замечание. Если бы элемент ListControl был размещен в диалоговом окне, то приведенный выше код надо было бы добавить в функцию OnInitDialog() класса диалогового окна.

 

Если Вы теперь запустите приложение на выполнение, то увидите пока еще пустую таблицу, но уже с наименованиями столбцов (рис. 3).

 
 

Рис. 3. Список с добавленными столбцами

Шаг 4. Задание начальных значений элементов списка. Для того чтобы впоследствии можно было сортировать элементы списка по выбранному столбцу, надо значения этих элементов задать в массиве структур и разместить в списке (классе CListCtrl) указатели на них. В дальнейшем для сортировки списка мы будем просто сортировать этот массив по выбранному компоненту структуры. Так как в список можно заносить только строковые данные, то для компонент структуры проще всего выбрать строковый тип.

В соответствии с архитектурой документ-вид мы должны размещать данные в классе документа. Предварительно создайте заголовочный файл Student.h с таким содержимым:

 
 

 

Как Вы думаете, что обозначает ключевое слово static перед объявлением массива объектов-строк? Если понадобится (а нам это понадобится) включать файл Student.h в более чем один другой файл, то линкер выдаст сообщение об ошибке: имя Data[][2] определено повторно. Именно для предотвращения этой ошибки и используют в данном контексте ключевое слово static, которое указывает линкеру на необходимость использования так называемой «внутренней» компоновки (internal linkage), при которой имя Data[][2] видимо только внутри данного компилируемого модуля (файла).

Правда, Б.Страуструп считает такой подход устаревшим и предлагает использовать вместо него неименованное пространство имен, что приводит к тому же результату:

 

Выбор того или иного способа – за Вами.

 

Для того чтобы файл Student.h был добавлен средой MVS-2008 в перечень файлов проекта, создайте его с помощью команды ProjectèAdd Class.

Тип TStudent представляет собой структуру из двух указателей на строки.

Подключите файл Student.h с помощью директивы include в заголовочный файл документа SLDoc.h и добавьте в класс документа массив указателей на данные Group и число строк списка (число студентов) Count:

 
 

 

Конструктор и деструктор класса документа (файл SLDoc.cpp) наполните таким кодом:

CSLDoc::CSLDoc() { Count=sizeof Data / sizeof Data[0]; Group=new PStudent [Count]; for(int i=0;i<Count;i++) { Group[i]=new TStudent; Group[i]->Name =(LPTSTR)(LPCTSTR)Data[i][0]; Group[i]->Tails=(LPTSTR)(LPCTSTR)Data[i][1]; } } CSLDoc::~CSLDoc() { for(int i=0;i<Count;i++) delete Group[i]; delete [] Group; }

 

 

Проанализировав приведенный код, Вы легко обнаружите, что в классе документа мы создали массив указателей на структуру TStudent, которая в свою очередь содержит два указателя на строки: «Имя студента» и «Число хвостов» студента.

Таким образом, в классе документа мы задали все значения элементов списка. Пусть Вас не смущает то обстоятельство, что данные в конечном итоге заданы в виде констант. Если Вы подключите свой могучий интеллект, то элементарно сообразите, что эти данные можно загрузить из файла или, на худой конец, из полноценной БД.

Эти данные пока находятся в классе документа и не отображаются каким-либо чудодейственным образом в управляющем элементе (списке) CListCtrl. Восполним этот пробел на следующем шаге.

Шаг 5. Занесем данные в список CListCtrl следующим образом:

 
 

 

Если теперь собрать приложение и запустить его на выполнение, то окно приложения должно приобрести примерно такой вид, как на рис. 4. (Если это не так, то надо, естественно, приобрести новый компьютер, по крайней мере с полутораядерным процессором.)

Работа со списком, т.е. добавление новых строк, сводится к вызову одной из перегруженных функций CListCtrl::InsertItem(), которая собственно и вставляет новую строку. Версия функции CListCtrl::InsertItem() с единственным параметром типа LV_ITEM вставляет пустую строку, если компонент структуры LV_ITEM.pszText указывает на пустую строку, как в приведенном выше тексте функции CSLView::OnInitialUpdate(). Занесение данных в столбцы строки в данном примере выполняется с помощью функции CListCtrl::SetItemText(), первый параметр которой указывает на номер строки, а второй – номер столбца. Попробуйте закомментировать строки с вызовом функции CListCtrl::SetItemText(), запустите приложение на выполнение и пощелкайте мышью в первом столбце строк таблицы. Несмотря на то, что список пустой, вы обнаружите присутствие пяти строк (рис. 5). С помощью функции CListCtrl::SetItemData() мы сохраняем в объекте список указателей на данные, помещенные в соответствующую строку списка, что нужно только для последующей сортировки данных списка.

 

 
 

Рис. 4. Список с данными

 

 
 

Рис. 5. Список с пустыми строками

 

Приведенный в функции CSLView::OnInitialUpdate() способ вставки столбцов и строк и собственно заполнения списка конкретными данными не является единственно возможным. Класс CListCtrl предлагает много разных член-функций, которые позволяют выполнять со списком разнообразные операции, в том числе, например, помещать в список изображения. Читайте MSDN или шарьте в Интернете!

Шаг 6. Сортировка данных в списке. Вы хорошо знаете, что если в окне Проводника щелкнуть по заголовку какого-либо столбца со списком файлов, то список будет чудесным образом отсортирован по данному столбцу, что не только приятно, но и полезно. Выполним и мы такую сортировку. Для этого, как Вы догадываетесь, надо создать обработчик соответствующего события.

В окне ClassView выберите класс вида CSLView, вызовите для него окно свойств, в нем выберите вкладку Events, в ней раскройте ветвь IDC_LIST1 (если Вы не изменяли идентификатор списка CListCtrl) и уже в этой ветви создайте обработчик OnHdnItemclickList1() события HDN_ITEMCLICK (рис. 6). Текст обработчика наполните таким нехитрым содержанием:

 
 

 
 

Рис. 6. Добавление обработчика события HDN_ITEMCLICK

 

Если Вы попытаетесь компилировать приложение, то увидите сообщение об ошибке:

'SortFunc': undeclared identifier

 

Первый параметр функции CListCtrl::SortItems() должен быть именем функции «обратного вызова» (callback function), которая должна выполнять сравнение сортируемых значений и возвращать его результат в виде целого числа. Как следует из MSDN, эта функция должна иметь такой формат:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,

LPARAM lParamSort);

 

Функция сравнения CompareFunc() должна возвращать:

· отрицательное значение, если первый параметр больше второго;

· положительное значение, если первый параметр меньше второго;

· нулевое значение при равенстве значений параметров.

 

Параметр lParam1 должен быть 32-битовым значением, ассоциированным с первым сравниваемым значением, а lParam2 – соответственно вторым. Это те величины, которые были указаны в члене lParam структуры LVITEM, когда они помещались в список. Параметр lParamSort такой же, как и второй параметр функции SortItems().

С учетом сказанного текст функции может быть таким:

 
 

 

Если Вас удивляет, что число хвостов студентов сравниваются с помощью функции strcmp(), предназначенной для сравнения строк текста, то вспомните, что число хвостов, как и фамилия, хранятся в виде строк текста (см. выше массив строк Data). Так как (пока) число хвостов студента не может превышать девяти (одна цифра), то такой подход работает. При большем числе хвостов начнутся глюки, для устранения которых необходимо будет преобразовывать строку в число и сравнивать уже числовые значения.

Запустите приложение на выполнение и убедитесь в том, что оно работает корректно, т.е. список выводится и сортируется. Попробуйте доказать преподавателю, что вы достойно справились с поставленной перед вами задачей.

 




Поделиться с друзьями:


Дата добавления: 2014-12-26; Просмотров: 352; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.068 сек.