Win32-приложение Картотека аудио дисков
УЧРЕЖДЕНИЕ ОБРАЗОВАНИЯ «БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ» |
|
ПОЯСНИТЕЛЬНАЯ ЗАПИСКА к курсовому проекту по предмету “Системное программное обеспечение ЭВМ” Тема: Win32-приложение Картотека аудио дисков |
|
Выполнил: Проверил: |
|
УЧРЕЖДЕНИЕ ОБРАЗОВАНИЯ «БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ»
Институт повышения квалификации и переподготовки руководящих работников и специалистов по информационным технологиям и радиоэлектронике
Факультет компьютерных технологий
"УТВЕРЖДАЮ” зав. Каф. ПОИТ
–––––––––––––––––/ В.В. Бахтизин// " " ____2006 г.
Курс: Системное программное обеспечение ЭВМ
Тема курсовой работы: Win32-приложение Картотека аудио дисков.
Задание 3 по курсовой работе студенту гр. _________________________.
Разработать программный продукт для ведения картотеки аудиодисков.
Для каждого произведения в файле на диске хранится
Наименование диска (группы), наименование произведения, исполнитель, учетный номер диска в картотеке, кто взял, дата.
Максимальное количество добавляемых в одном сеансе записей –50.
Основные функции приложения:
Меню Файл - создание нового файла данных, загрузка существующего, сохранение, сохранение как...;
Меню Правка - добавление, изменение, удаление элемента списка. Отображение информации элемента списка в виде окна свойств(Property Scheet;
Меню Вид - команды режима отображения(большие и малые значки, список и таблица). В режиме таблица обеспечивается сортировка по соответствующему параметру при щелчке мыши по заголовку колонки;
Меню Помощь - вызов помощи и окна информации о программе.
Требования к программе.
Программа должна работать под Windows 95/98
Язык интерфейса – русский. Тип интерфейса - Explorer(Проводник).
Обязательные элементы итерфейса: 1) меню;
2) панель инструментов (ToolBar) с появляющимися подсказками - Tool Tips;
3) элемент TreeView ("древовидное отображение") для списка дисков и исполнителей на каждом диске;
4) элемент ListView ("графический список") для списка произведений выбранного диска и исполнителя;
5) элемент StatusBar (строка состояния )- наименование диска, исполнитель, количество произведений в списке.
6) контекстное меню, вызываемое при щелчке правой кнопкой мыши по элементу графического списка, содержит команду "Свойства" из меню Правка для отображения всех данных записи для выбранного элемента списка "ListView". Данные вывести в диалоговом окне в виде “Блокнота свойств”(Property Sheed), содержащего не менее двух страниц свойств;
Содержание пояснительной записки
Введение.
1.Анализ задания и постановка задачи.
2.Описание логического представления данных и их назначения.
3.Описание структуры программы.
4. Разработка программы (пояснения к тексту программы, примененным технологиям и принятым решениям, схемы основных алгоритмов)
5.Тестирование программы и тестовые наборы данных.
6.Технические требования и инструкция по применению.
Заключение.
Литература
Приложения – исходные тексты, заголовочные файлы, сценарии ресурсов, тестовые данные.
Срок выдачи задания 15.09.2006г
Срок выполнения курсовой работы 25.12.2006 г Руководитель курсовой работы __________________
Задание принял к исполнению: дата ___________________ подпись_________________
Содержание
TOC o "1-3" h z Введение
2. Структура выходных и входных данных
3. Описание основных классов и структур
5.5.2 Добавление новой композиции
5.6.2 Редактирование композиции
Введение
Язык программирования служит двум связанным между собой целям: он дает программисту аппарат для задания действий, которые должны быть выполнены, и формирует концепции, которыми пользуется программист, размышляя о том, что делать. Первой цели идеально отвечает язык, который настолько "близок к машине", что всеми основными машинными аспектами можно легко и просто оперировать достаточно очевидным для программиста образом. С таким умыслом первоначально задумывался C. Второй цели идеально отвечает язык, который настолько "близок к решаемой задаче", чтобы концепции ее решения можно было выражать прямо и коротко. С таким умыслом предварительно задумывались средства, добавленные к C для создания C++.
Связь между языком, на котором мы думаем/программируем, и задачами и решениями, которые мы можем представлять в своем воображении, очень близка. По этой причине ограничивать свойства языка только целями исключения ошибок программиста в лучшем случае опасно. Язык предоставляет программисту набор концептуальных инструментов; если они не отвечают задаче, то их просто игнорируют. Например, серьезные ограничения концепции указателя заставляют программиста применять вектора и целую арифметику, чтобы реализовать структуры, указатели и т.п. Хорошее проектирование и отсутствие ошибок не может гарантироваться чисто за счет языковых средств. Система типов должна быть особенно полезна в нетривиальных задачах. Действительно, концепция классов в C++ показала себя мощным концептуальным средством.
1. Постановка задачи
Разработать программный продукт для ведения картотеки аудиодисков. Программный продукт должен позволять:
- вести учет всех дисков картотеки (наименование, группа, учетный номер в картотеке, кем был взят, дата) – добавление, удаление, редактирование, сохранение, загрузка сохраненной информации;
- вести учет каждой композиции на диске (номер трека, исполнитель).
Система должна обеспечить выполнение этих возможностей путем реализации алгоритмов удаления, редактирования и добавления новой информации.
При добавлении необходимо обеспечить проверку на допустимые значения и ограничивать действия пользователя в тех случаях, когда он пытается ввести пустые значения.
При редактировании следует аналогичным образом проверять редактируемые значения.
Для реализации поставленной задачи использовать Visual Studio C++ версии не ниже 6.0. В частности применить winapi.
2. Структура выходных и входных данных
Данные предполагается хранить в структурированном файле. Так как структура данных может быть выражена лишь одной таблицей, то нет необходимости прибегать к применению каких либо СУБД. Файл с данными можно размещать как на локальном компьютере, так и в сети, предоставляющей открытый доступ к такому виду ресурса.
Вся структура данных может быть выражена одной таблицей:
Таблица 1 - схема данных |
|
название |
тип |
название_диска |
строка |
название_трека |
строка |
исполнитель |
строка |
учетный номер |
длинное целое |
кем_взят |
строка |
дата_добавления |
дата |
Рисунок 1 – размещение данных в файле |
3. Описание основных классов и структур
В проекте были использованы встроенные классы и структуры windows api. Их перечисление дается ниже:
WNDCLASSEX |
|
поле |
тип |
cbSize |
LONG |
style |
LONG |
lpfnWndProc |
WNDPROC |
cbClsExtra |
LONG |
cbWndExtra |
LONG |
hInstance |
HANDLE |
hIcon |
HANDLE |
hIconSm |
HANDLE |
hCursor |
HANDLE |
lpszMenuName |
LPCTSTR |
lpszClassName |
LPCTSTR |
MENUITEMINFO |
|
поле |
тип |
cbSize |
LONG |
fMask |
LONG |
fType |
LONG |
fState |
LONG |
dwTypeData |
* LPCTSTR |
cch |
LONG |
wID |
UINT |
hSubMenu |
HMENU |
OPENFILENAME |
|
поле |
тип |
lStructSize |
LONG |
hwndOwner |
HWND |
lpstrFile |
LPCTSTR |
nMaxFile |
LONG |
lpstrFilter |
LPCTSTR |
nFilterIndex |
LONG |
lpstrFileTitle |
LPCTSTR |
nMaxFileTitle |
LONG |
lpstrInitialDir |
LPCTSTR |
ACCEL |
|
поле |
тип |
fVirt |
LONG |
key |
LONG |
cmd |
LONG |
tagBITMAP |
|
поле |
тип |
bmType |
LONG |
bmWidth |
LONG |
bmHeight |
LONG |
bmWidthBytes |
LONG |
bmPlanes |
WORD |
bmBitsPixel |
WORD |
bmBits |
LPVOID |
4. Алгоритм работы программы
Алгоритм работы программы можно представить диаграммой 1.
Диаграмма 1 – алгоритм работы программы |
5. Результат работы программы
Запуск приложения осуществляется традиционным способом (двойным/одинарным кликом по иконке приложения).
Рисунок 2 – Запуск приложения |
Поскольку приложение написано с использованием только winapi, оно исключает необходимость в дополнительным библиотеках, фреймах, виртуальных машинах (подобной java virtual machine). Работа приложения также гарантированна в ОС Windows 98 и более поздних версиях.
5.1 Ознакомление
После запуска, приложение создает окно типичное для windows приложений со встроенной возможностью его сворачивания в панель задач, максимизации, минимизации и закрытия приложения.
Рисунок 3 – главное окно приложения |
Приложение имеет главное меню со следующей структурой:
- Файл
- Новый
- Открыть
- Сохранить
- Сохранить как
- Правка
- Добавить
- Изменить
- Удалить
·
- большие значки
- малые значки
- список
- таблица
- Помощь
- О программе
Вход в меню осуществляется путем нажатия клавиши alt, а перемещение путем нажатия стрелок вверх/вниз/влево/вправо (←↑→↓).
Рисунок 4 – меню |
Ниже главного меню, в окне приложения располагается панель инструментов, частично дублирующая функциональность главного меню.
Дублируются следующие пункты:
- Файл
- Новый
- Открыть
- Сохранить
- Сохранить как
- Вид
- большие значки
- малые значки
- список
- таблица
Этот элемент управления представляет собой набор кнопок, как привило без подписей, но с интуитивно понятными изображениями. Такой набор объединяется в группу и может стать перемещаемым в пределах окна и вне его при условии поддержки данной функции разработчиком.
Панель инструментов обеспечивает более быстрый доступ, нежели главное меню приложения и содержит наиболее часто используемые пункты главного меню.
Рисунок 5 – панель инструментов |
Панель инструментов поддерживает систему помощи, называемой “всплывающие подсказки”. Для их активизации следует подержать курсор 2 секунды над интересующей кнопкой панели инструментов.
Рисунок 6 – всплывающие подсказки |
Ниже панели инструментов располагается древовидная структура и параллельно ей, графический список.
В древовидной структуре отображается список дисков. Список дисков привязан к логическому корню “коллекция”. В свою очередь каждый диск в отдельности может содержать список произведений и соответственно быть корнем для них (дисков).
Графический список способен работать в двух режимах. Когда в древовидной структуре активным (выделенным) является диск, то графический список отображает все произведения в данном диске – это первый режим. Если активным является не диск, а одно из его произведений, то графический список преобразуется в блокнот свойств этого произведения – это второй режим.
В сущности, графический список и блокнот свойств, это абсолютно разные элементы управления, никак между собой не связанные, однако в данном случае они приобретают логическую связь и могут рассматриваться как единый элемент управления.
Рисунок 7 – Состояния древовидной структуры и графического списка |
Последним элементов в окне является строка состояния. Она реагирует на действия пользователя и отображает подсказки согласно контексту работы.
В начале работы программы строка состояния пуста. Если пользователь выберет диск, то в ней отобразится:
- название диска;
- количество произведений в нем;
- количество произведений во всей коллекции.
Если пользователь выберет конкретное произведение, то к вышеописанному списку добавятся названия композиции и имя исполнителя.
Рисунок 8 – Состояния строки состояния |
5.2 Работа с программой
После небольшого ознакомления можно приступить к описанию работы программы.
Данные программы (коллекции) хранятся в файлах с расширением *.ddb. Конечно, не кто не может помешать нам сохранять их с другими расширениями, однако такой выработанный годами подход не позволяет запутаться в бесчисленном множестве других файлов.
Если подобных файлов не было создано раньше, то следует приступить к созданию новой коллекции. Это можно сделать при помощи:
· Файл”→“Новый” либо аналогичной кнопкой в панели инструментов;
· Windows).
В итоге мы увидим окно, изображенное на рисунке 3. Теперь мы можем работать с новой коллекцией. В данных условиях у нас имеются следующие конструктивные возможности:
- мы можем сохранить новый документ (коллекцию);
- добавить новый диск.
5.3 Сохранение документа
Функция сохранение документа позволяет указать программе о необходимости сохранения данных на жесткий диск, что уменьшает вероятность потери информации в результате сбоя в сети.
Для сохранения документа необходимо в главном меню выбрать пункт “Файл”→“Сохранить как” либо “Файл”→“Сохранить”. Кнопка с аналогичной функциональностью есть и в панели инструментов.
Действия этих пунктов ничем друг от друга не отличаются. “Сохранить как” выбирается только в том случае, когда требуется сохранить документ с другими параметрами (имя документа и/или месторасположение). Если документ новый, и мы выбираем пункт “Сохранить”, программа автоматически вызовет функцию “Сохранить как” т.к. новый документ пока не имеет ни имени, ни месторасположения.
После выбора пункта “Сохранить как” вызывается одноименный диалог, который позволяет задать новое имя документа и/или месторасположение. Его изображение показано на рисунке 9.
Рисунок 9 – диалог “Сохранить как” |
5.4 Открытие документа
“Открытие документа” позволяет загрузить ранее созданную коллекцию. Если ранее не было создано каких-либо коллекций, то следует приступить к процедуре создания нового документа, описанной выше.
Для открытия документа следует выбрать пункт главного меню “Файл”→“Открыть” либо воспользоваться аналогичной кнопкой в панели инструментов. После этого пользователю будет предложено несколько действий в зависимости от текущего состояния программы:
- Если пользователь не производил каких-либо изменений в текущем документе, произойдет вызов диалога “Открыть”.
- Если пользователь производил изменения в текущем документе, ему будет предложен запрос, о необходимости сохранения текущих изменений. В запросе у пользователя имеется 3 варианта ответа:
- Yes – согласен сохранить изменения, после чего пользователю будет выведен диалог “Сохранить как”. Если пользователь в диалоге “Сохранить как” выберет “Отмена”, то все последующие действия по сохранению старого документа и открытию нового будут отменены и произойдет возврат в программу. Если пользователь выберет “Сохранить”, он перейдет к диалогу “Открыть документ”.
- No – продолжить без сохранения. Пользователь сразу переходит к диалогу “Открыть документ” минуя процедуру сохранения документа.
- Cancel – отменить открытие документа и предотвратить все последствия связанные с открытием документа.
Рисунок 10 – предупреждение “Вы хотите сохранить изменения в документе?” |
Диалог “Открыть документ” изображен на рисунке 11.
Рисунок 11 – диалог “Открыть документ” |
5.5 Добавление информации
Добавление новой информации осуществляется посредством пункта главного меню “Правка”→“добавить”. Данный пункт функционирует в двух режимах:
- добавление нового диска;
- добавление новой композиции.
Выбор режима работы зависит от того, какой объект в данным момент выделен в древовидной структуре. Выделенными могут оказаться 3 типа элемента:
- вся коллекция;
- один из дисков;
- один из треков.
Рисунок 12– выделенные объекты |
Если выделенной оказалась вся коллекция, то пункт главного меню “Правка”→“добавить” вызывает диалог “добавление нового диска”. Если выделенным оказывается непосредственно диск, то вызываться будет уже диалог “добавление новой композиции”. Он также будет вызываться и при условии, если выделен один трек.
5.5.1 Добавление нового диска
Для добавления нового диска в новую либо уже существующую коллекцию, следует выбрать пункт “Правка”→“добавить”. При соблюдении вышеописанных условий в разделе “добавление информации”, это повлечет за собой вызов диалога “добавление диска”. Он изображен на рисунке 13.
Рисунок 13 – диалог “добавление диска” |
В данном диалоге имеется два поля для ввода текста и две кнопки. Поля предназначены для ввода названия группы и названия альбома.
При нажатии кнопки “добавить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!”.
Рисунок 14 – предупреждение “Поля не могут иметь пустые значения!!!” |
Если добавление прошло успешно, пользователю выдается сообщение “Данные добавлены”.
Рисунок 15 – отчет “Данные добавлены” |
При этом после добавления данных не происходит выхода из диалога. Это дает возможность пользователю делать множественные добавления минуя постоянное обращение к главному меню.
Для выхода из диалога достаточно нажать кнопку “отмена”.
5.5.2 Добавление новой композиции
Для добавления новой композиции (трека), следует выбрать пункт “Правка”→“добавить”. При соблюдении вышеописанных условий в разделе “добавление информации” (добавление новой композиции возможно лишь в том случае, если в проекте имеется хотя бы один диск, и он является выделенным в древовидной структуре), это повлечет за собой вызов диалога “добавление новой композиции”. Он изображен на рисунке 16..
Рисунок 16 – диалог “добавление новой композиции (трека)” |
В данном диалоге имеется три поля для ввода текста и две кнопки. Поля предназначены для ввода названия трека, имени исполнителя и даты добавления. При нажатии кнопки “добавить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!” изображенное на рисунке 14.
Если добавление прошло успешно, пользователю выдается сообщение “Данные добавлены” изображенное на рисунке 15.
При этом после добавления данных происходит выход из диалога. Также выход осуществляется нажатием кнопки “отмена”.
5.6 Редактирование информации
Редактирование информации осуществляется посредством пункта меню “Правка”→“изменить”. Данный пункт функционирует в двух режимах:
- редактирование диска;
- редактирование композиции.
Выбор режима работы зависит от того, какой объект в данным момент выделен в древовидной структуре. Выделенными могут оказаться 3 типа элемента:
- вся коллекция;
- один из дисков;
- один из треков.
Если выделенной оказалась вся коллекция, то пункт главного меню “Правка”→“изменить” не выполняет каких-либо действий т.к. не выделен объект для редактирования (диск или трек). Если выделенным оказывается непосредственно диск, то вызывается диалог “редактирование диска”. Если выделен один трек, то вызывается диалог “редактирование трека”.
5.6.1 Редактирование диска
Для редактирование, следует выбрать пункт “Правка”→“изменить”. При соблюдении вышеописанных условий в разделе “редактирование информации”, это повлечет за собой вызов диалога “редактирование диска”. Он изображен на рисунке 17.
Рисунок 17 – диалог “редактирование диска” |
В данном диалоге имеется такие же поля, как и в диалоге “добавление диска” но уже заполненные добавленными ранее значениями.
При нажатии кнопки “сохранить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!” изображенное на рисунке 14.
Если сохранение прошло успешно, пользователю выдается сообщение “Данные сохранены” изображенное на рисунке 18.
Рисунок 18 – отчет “Данные сохранены” |
При этом после редактирования данных происходит выход из диалога. Также выход осуществляется нажатием кнопки “отмена”.
5.6.2 Редактирование композиции
Для редактирования композиции (трека), следует выбрать пункт “Правка”→“изменить”. При соблюдении вышеописанных условий в разделе “редактирование информации” это повлечет за собой вызов диалога “редактирование трека”. Он изображен на рисунке 19..
Рисунок 19 – диалог “редактирование композиции (трека)” |
В данном диалоге имеется такие же поля, как и в диалоге “добавление трека” но уже заполненные добавленными ранее значениями.
При нажатии кнопки “сохранить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!” изображенное на рисунке 14.
Если сохранение прошло успешно, пользователю выдается сообщение “Данные сохранены” изображенное на рисунке 18.
При этом после редактирования данных происходит выход из диалога. Также выход осуществляется нажатием кнопки “отмена”.
5.7 Удаление информации
Удаление информации осуществляется посредством пункта меню “Правка”→“удалить”. Данный пункт функционирует в двух режимах:
- удаление диска;
- удаление композиции.
Выбор режима работы зависит от того, какой объект в данным момент выделен в древовидной структуре. Выделенными могут оказаться 3 типа элемента:
- вся коллекция;
- один из дисков;
- один из треков.
Если выделенной оказалась вся коллекция, то пункт главного меню “Правка”→“удалить” не выполняет каких-либо действий т.к. не выделен объект для удаления (диск или трек).
Если выделенным оказывается непосредственно диск, то пункт главного меню “Правка”→“удалить” вызывает запрос, обращенный к пользователю, о подтверждении его действий по удалению диска и всех треков, привязанных к нему. В запросе у пользователя имеется 2 варианта ответа:
- OK – подтверждает возможность удаления диска и всех треков, привязанных к нему;
- Cancel – отменяет работу по удалению диска.
Рисунок 20 – предупреждение “Данные диска и всех его треков будут безвозвратно утеряны!!! Вы уверены?” |
Если выделенным оказывается непосредственно один трек, то пункт главного меню “Правка”→“удалить” вызывает запрос, обращенный к пользователю, о подтверждении его действий по удалению трека. В запросе у пользователя имеется 2 варианта ответа:
- OK – подтверждает возможность удаления трека;
- Cancel – отменяет работу по удалению трека.
Рисунок 21 – предупреждение “Данные трека будут безвозвратно утеряны!!! Вы уверены?” |
5.8 Вид
В программе имеется пункт меню “вид”. Он позволяет назначать внешний вид графического списка. Имеются следующие варианты вида:
- большие значки
- малые значки
- список
- таблица
На панели инструментов имеется дублирующие кнопки данной функции. На рисунке 22 показаны возможные виды графического списка.
Рисунок 22 – возможные виды графического списка |
5.9 О программе
Для получения информации и версии продукта и о его разработчиках следует обратиться к пункту “Помощь”→“ О программе”. После выбора этого пункта на экране появиться сообщение, изображенное на рисунке 23.
Рисунок 23 – отчет “ О программе ” |
5.10 Выход из программы
Выход из программ можно осуществить путем выбора пункта главного меню “Файл”→“Выход”.
Также выход осуществляется нажатием кнопки “X” в заголовке главного окна приложения.
Рисунок 24 – кнопка выхода в заголовке главного окна приложения |
6. Тестирование программы
Для тестирования программы необходимо проверить ряд функций программы:
- создание нового документа;
- сохранение существующего документа;
- открытие документа;
- наполнение документа.
Все эти действия можно объединить в группу и проверить одновременно. Для этого достаточно составить один сценарий, в котором будут следующие действия:
- запуск программы;
- создание нового документа;
- наполнение документа;
- сохранение документа;
- выход из программы;
- запуск программы;
- открытие документа.
Ниже приводятся описанные действия.
1. запуск программы: После запуска программы, на экране должно отобразиться главное окно программы, изображенное на рисунке 3.
2. создание нового документа: После запуска программы можно приступить к созданию нового документа. Это можно сделать при помощи:
- пункта главного меню “Файл”→“Новый” либо аналогичной кнопкой в панели инструментов;
- ничего не делать – при запуске изначально происходит работа с новой коллекцией.
3. наполнение документа: Для наполнения документа следует добавить в коллекцию диски и треки для них.
Для добавления новых дисков нужно выполнить следующие действия:
- в древовидной структуре выделить всю коллекцию;
- посредством пункта главного меню “Правка”→“добавить” вызвать диалог “добавление диска”, изображенного на рисунке 13;
- в поле “группа” диалога вписать название “Ария”;
- в поле “название альбома” диалога вписать название “Диск 1”;
- нажать кнопку “добавить”;
- должна произойти проверка введенной информации на допустимость введенных значений, добавление данных и вывестись отчет “Данные добавлены”, изображенный на рисунке 15 (диалог не должен закрыться т.к. он предполагает множественное добавление информации);
- в поле “группа” диалога вписать название “Ария”;
- в поле “название альбома” диалога вписать название “Диск 2”;
- нажать кнопку “добавить”;
- должна произойти проверка введенной информации на допустимость введенных значений, добавление дынных и вывестись отчет “Данные добавлены”, изображенный на рисунке 15;
- после этого следует нажать на кнопку “отмена”, произойдет выход из диалога;
- после этих действий в древовидной структуре появятся два новых узла: “Ария: Диск 1” и “Ария: Диск 2” корнем которых станет “коллекция”;
Для добавления новых треков к дискам нужно выполнить следующие действия:
1)
2) Правка”→“добавить” вызвать диалог “добавление трека”, изображенного на рисунке 16;
a) X” (вместо “X” в первой итерации записать “1”);
b) Кипелов”;
c)
d)
e)
3) a, b, c и d с получение результата из пункта e в количестве четырех итераций с начальным значением 2, в качестве данных брать те же значения изменяя “X” на номер итерации.
4)
5)
В результате всех действий получим пример, изображенный на рисунке 7.
4. сохранение документа: Для сохранения документа необходимо в главном меню выбрать пункт “Файл”→“Сохранить как” либо “Файл”→“Сохранить”. Кнопка с аналогичной функциональностью есть и в панели инструментов. После выбора пункта сохранения вызывается одноименный диалог, который позволяет задать новое имя документа и/или месторасположение. Его изображение показано на рисунке 9. В диалоге следует задать новое имя документа и его месторасположение и нажать на кнопку “Сохранить”.
5. выход из программы: Выход из программ можно осуществить путем выбора пункта главного меню “Файл”→“Выход”. Также выход осуществляется нажатием кнопки “X” в заголовке главного окна приложения.
6. запуск программы: смотреть действие 1.
7. открытие документа: Для открытия документа следует выбрать пункт главного меню “Файл”→“Открыть” либо воспользоваться аналогичной кнопкой в панели инструментов. В результате всех действий должен получиться результат, как и в “3. наполнение документа ”, который изображен на рисунке 7.
Заключение
Проделав значительную работу я изучил возможности работы с winapi (и в частности способы манипулирования данными в элементах управления). Изучил механизмы создания пользовательских классов и принципы наследования в языке C++.
Литература
- MSDN Library - техническая справка для разработчиков программного обеспечения. - MicroSoft Corp., 2004.
- Е. Демидович - «Основы алгоритмизации и программирования на си». - Бестпринт, 2003.
- Страуструп - «Язык программирования C++». - Бином, 2004.
Приложение |
A Листинг программы
Исходные тексты
#include "includes.h"
#include "main.h"
#define WX 600
#define WY 300
#define COLOR RGB(0xff,0xff,0xff)
#define WIN_STYLE WS_OVERLAPPED|WS_SYSMENU|WS_CAPTION|WS_BORDER|WS_MINIMIZEBOX
#define Error_title "Error"
#define AplicationTitle "Картотека дисков"
#define ClassName "MY_CLASS"
HINSTANCE ghInst;
/* ############################### */
/* ### ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ### */
/* ############################### */
char buf[10]; char* toString(int value,int radix=10){
itoa(value,buf,radix);
return buf;};
/* ######################################### */
/* ### ДИАЛОГИ - ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ### */
/* ######################################### */
bool getFileDlg(HWND hWnd,char *name,char *mask,int mask_size=0){
char szF[1024]="";
OPENFILENAME ofn;
memset(&ofn,0,sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.hwndOwner=hWnd;
ofn.lpstrFile=szF;
ofn.nMaxFile=sizeof(szF);
ofn.lpstrFilter=mask;
ofn.nFilterIndex=2;
ofn.lpstrFileTitle=NULL;
ofn.nMaxFileTitle=0;
ofn.lpstrInitialDir=NULL;
ofn.Flags=OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn)==TRUE){
sprintf(name,"%s",ofn.lpstrFile);
return 1;}
sprintf(name,"%s","");
return 0;}
/* ##################################### */
/* ### ДИАЛОГИ - ОБРАБОТКА СООБЩЕНИЙ ### */
/* ##################################### */
LRESULT CALLBACK addTrackDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int id=LOWORD(wParam);
static int ind=lParam,pos=0;
int i;
switch (uMsg)
{
case WM_INITDIALOG:
ind=lParam;
for (i=0;i<dwWkCount;i++)
if (WkRec[i].ind==ind)
pos = i;
SetDlgItemText(hwndDlg,IDC_EDIT_TRACK,WkRec[pos].cTrack);
SetDlgItemText(hwndDlg,IDC_EDIT_SINGER,WkRec[pos].cSinger);
SetDlgItemText(hwndDlg,IDC_EDIT_DATE,WkRec[pos].cDate);
return FALSE;
break;
case WM_COMMAND:
switch (id)
{
case IDC_OK:
GetDlgItemText(hwndDlg,IDC_EDIT_TRACK,WkRec[pos].cTrack,100);
GetDlgItemText(hwndDlg,IDC_EDIT_SINGER,WkRec[pos].cSinger,30);
GetDlgItemText(hwndDlg,IDC_EDIT_DATE,WkRec[pos].cDate,20);
EndDialog(hwndDlg,0);
break;
case IDC_CANCEL:
EndDialog(hwndDlg,1);
break;
}
break;
default:
return FALSE;
}
}
int GetMaxInd()
{
int maxind=0;
for (int i=0;i<dwWkCount;i++)
{
if (WkRec[i].iNum>maxind)
{
maxind=WkRec[i].iNum;
}
}
return maxind;
}
LRESULT CALLBACK addDiskDlgProc(HWND hwndDlg,UINT uMsg,
WPARAM wParam,LPARAM lParam)
{
int id=LOWORD(wParam);
static int ind=lParam,pos=0;
int i;
switch (uMsg)
{
case WM_INITDIALOG:
ind=lParam;
for (i=0;i<dwWkCount;i++)
if (WkRec[i].ind==ind)
pos = i;
SetDlgItemText(hwndDlg,IDC_EDIT_GROUP,WkRec[pos].cGroup);
SetDlgItemText(hwndDlg,IDC_EDIT_ALBUM,WkRec[pos].cDisc);
return FALSE;
break;
case WM_COMMAND:
switch (id)
{
case IDC_OK:
GetDlgItemText(hwndDlg,IDC_EDIT_GROUP,WkRec[pos].cGroup,50);
GetDlgItemText(hwndDlg,IDC_EDIT_ALBUM,WkRec[pos].cDisc,30);
WkRec[pos].iNum=GetMaxInd()+1;
EndDialog(hwndDlg,0);
break;
case IDC_CANCEL:
EndDialog(hwndDlg,1);
break;
}
break;
default:
return FALSE;
}
}
LRESULT CALLBACK AboutDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG: {return TRUE;};
case WM_COMMAND:
switch(LOWORD(wParam)){
case IDOK:{
EndDialog(hDlg,0);
return TRUE;}}
break;
default:
return(FALSE);
}
return(TRUE);
}
UINT AddNewItem(UINT iType,UINT iParent)
{
//Создаем временную рабочую структуру
WorkRecord *temp;
temp=new WorkRecord[dwWkCount];
UINT max=WkRec[0].ind;
//Копируем во временную структуру рабочую. Находим последний индекс
// в рабочей структуре
for (int i=0;i<dwWkCount;i++)
{
if (max<WkRec[i].ind)
max=WkRec[i].ind;
temp[i]=WkRec[i];
}
// Пересоздаем рабочую структуру с новым размером
delete [] WkRec;
WkRec=new WorkRecord[++dwWkCount];
//Копируем записи из временной структуры в рабочую
for (i=0;i<dwWkCount-1;i++)
{
//ZeroMemory(&WkRec[i],sizeof(WorkRecord));
WkRec[i]=temp[i];
}
// Очищаем последний "новый" элемент рабочей
// структуры и заносит значения по умолчанию
ZeroMemory(&WkRec[dwWkCount-1],sizeof(WorkRecord));
WkRec[dwWkCount-1].ind=++max;
WkRec[dwWkCount-1].iType=iType;
WkRec[dwWkCount-1].indParent=iParent;
delete []temp;
return max;
}
BOOL DeleteRec(int index)
{
// Проверяем есть ли связанные записи
for (int i=0;i<dwWkCount;i++)
if (WkRec[i].indParent==index)
{
MessageBox(NULL,"Удалите связанные данные","Ошибка",MB_OK);
return FALSE;
}
// Ищем позицию удаляемого элемента
int pos;
for (i=0;i<dwWkCount;i++)
if (WkRec[i].ind==index)
pos=index;
// Если удаляемый элемент не последний,
//то переносим последний на место удаляемого.
dwWkCount--;
if (pos!=dwWkCount)
WkRec[pos] = WkRec[dwWkCount];
// Копируем записи во временную структуру
WorkRecord *temp;
temp=new WorkRecord[dwWkCount];
for ( i=0;i<dwWkCount;i++)
{
temp[i]=WkRec[i];
}
//Удаляет рабочие записи
delete [] WkRec;
// Создает новые рабочие записи
WkRec=new WorkRecord[dwWkCount];
for (i=0;i<dwWkCount;i++)
{
WkRec[i]=temp[i];
}
delete []temp;
return TRUE;
}
void MakeTree()
{
TV_DeleteAll();
WkRec[0].ind=0;
WkRec[0].indParent=0;
WkRec[0].iType=5;
WkRec[0].hTree= TV_InsertItem("Коллекция", HANDLES.hWndTreeView, TVI_ROOT, 0,0);
HTREEITEM parent=WkRec->hTree;
// Инициализация дисков
for (int i=1;i<dwWkCount;i++)
{
if (WkRec[i].iType==0)
WkRec[i].hTree=TV_InsertItem(WkRec[i].cDisc,
HANDLES.hWndTreeView,parent,1,WkRec[i].ind);
if (WkRec[i].iType==1)
for (int j=1;j<dwWkCount;j++)
if (WkRec[i].indParent==WkRec[j].ind)
WkRec[i].hTree=TV_InsertItem(WkRec[i].cTrack,
HANDLES.hWndTreeView,WkRec[j].hTree,2,WkRec[i].ind);
}
LV_RemoveAllItems(HANDLES.hWndListView);
}
// Инициализация списка при выборе нового элемента
void MakeList(UINT selDisk)
{
LV_RemoveAllItems(HANDLES.hWndListView);
for (int i=0;i<dwWkCount;i++)
{
if (WkRec[i].indParent==selDisk)
LV_AddItem(HANDLES.hWndListView, 0, WkRec[i].cTrack,&WkRec[i]);
}
}
void InitTree()
{
TV_DeleteAll();
lstrcpy(FileName, "");
dwWkCount=1;
delete []WkRec;
WkRec=new WorkRecord[dwWkCount];
ZeroMemory(WkRec,sizeof(WorkRecord));
HANDLES.iSelDisk=-1;
HANDLES.iSelTrack=-1;
MakeTree();
}
/* ####################################### */
bool WndProc_OnCreate(HWND hWnd,LPCREATESTRUCT lpCreateStruct)
{
HANDLES.hWndMain=hWnd;
if (!SB_Create(hWnd))
return FALSE;
if (!TB_Create(hWnd))
return FALSE;
if (!LV_Create(hWnd))
return FALSE;
if (!TV_Create(hWnd))
return FALSE;
InitTree();
ResizeWindows(hWnd);
return TRUE;
return 1;
}
void WndProc_OnResize(HWND hWnd,int cx, int cy, int cz)
{
if (!ResizeWindows(hWnd))
MessageBox(NULL, "Window resizing failed!", NULL, MB_OK);
}
void WndProc_OnDestroy(HWND hWnd)
{
PostQuitMessage(0);
}
void Main_OnCommand( HWND hWnd, int iCmd, HWND hwndCtl, UINT uCode )
{
int wCommand = iCmd;
int iTypeEdit,iNumRec;
GetStateOfCommonControls();
switch(iCmd)
{
case IDM_FILE_NEW:
iTypeEdit=MessageBox(NULL,"Вы хотите сохранить изменения?",
"Предупреждение",MB_YESNO);
if (iTypeEdit==IDYES)
{
if (strlen(FileName)==0)
{
if (!GetFlNameDialog(HANDLES.hWndMain,1))
break;
else
{
if (!SaveItems(FileName))
MessageBox(NULL,"Ошибка сохранения файла.","Ошибка",MB_OK);
else
InitTree();
}
}
else
{
if (!SaveItems(FileName))
MessageBox(NULL,"Ошибка сохранения файла.","Ошибка",MB_OK);
else
InitTree();
}
}
else
{
InitTree();
}
break;
case IDM_FILE_OPEN:
if (GetFlNameDialog(HANDLES.hWndMain,0))
{
if (!LoadItems(FileName))
MessageBox(NULL,"Ошибка загрузки файла.","Ошибка",MB_OK);
else MakeTree();
}
else
MessageBox(NULL,"Файл не выбран.","Ошибка",MB_OK);
break;
case IDM_FILE_SAVEAS:
if (!GetFlNameDialog(HANDLES.hWndMain,1))
{
MessageBox(NULL,"Файл не выбран.","Ошибка",MB_OK);
}
else
if (!SaveItems(FileName))
MessageBox(NULL,"Ошибка сохранения файла.","Ошибка",MB_OK);
break;
case IDM_FILE_SAVE:
if (strlen(FileName)==0)
{
if (!GetFlNameDialog(HANDLES.hWndMain,1))
{
break;
// MessageBox(NULL,"Файл не выбран.","Ошибка",MB_OK);
}
else
if (!SaveItems(FileName))
MessageBox(NULL,"Ошибка сохранения файла.","Ошибка",MB_OK);
}
break;
case IDM_EDIT_ADD:
if (HANDLES.iSelDisk<0)
{
iNumRec=AddNewItem(0,0);
iTypeEdit=DialogBoxParam(ghInst,MAKEINTRESOURCE(IDD_DIALOG_ADD_DISK),
hWnd,(DLGPROC)addDiskDlgProc,
(LPARAM) iNumRec);
if (iTypeEdit)
DeleteRec(iNumRec);
}
else
{
iNumRec=AddNewItem(1,HANDLES.iSelDisk);
iTypeEdit=DialogBoxParam(ghInst,MAKEINTRESOURCE(IDD_DIALOG_ADD_TRACK),
hWnd,(DLGPROC)addTrackDlgProc,(LPARAM) iNumRec);
if (iTypeEdit)
DeleteRec(iNumRec);
}
MakeTree();
break;
case IDM_EDIT_CHANGE:
if (HANDLES.iSelTrack>=0)
{
DialogBoxParam(ghInst,MAKEINTRESOURCE(IDD_DIALOG_ADD_TRACK),
hWnd,(DLGPROC)addTrackDlgProc,(LPARAM) HANDLES.iSelTrack);
MakeTree();
break;
}
if (HANDLES.iSelDisk>=0)
{
DialogBoxParam(ghInst,MAKEINTRESOURCE(IDD_DIALOG_ADD_DISK),
hWnd,(DLGPROC)addDiskDlgProc,
(LPARAM) HANDLES.iSelDisk);
MakeTree();
}
break;
case IDM_EDIT_DELETE:
if (HANDLES.iSelTrack>=0)
{
DeleteRec(HANDLES.iSelTrack);
MakeTree();
break;
}
if (HANDLES.iSelDisk>=0)
{
DeleteRec(HANDLES.iSelDisk);
MakeTree();
}
break;
case IDM_PROPERTY:
if (HANDLES.iSelTrack>=0)
CreatePropertySheet(hWnd,1);
break;
case IDM_VIEW_BIG:
case IDM_VIEW_SMALL:
case IDM_VIEW_LIST:
case IDM_VIEW_TABLE:
LV_ChangeView(wCommand);
break;
case IDM_HELP_ABOUT:
DialogBox(ghInst,MAKEINTRESOURCE(IDD_DIALOG_HELP_ABOUT),hWnd,(DLGPROC)AboutDlgProc);
break;
case IDM_FILE_EXIT:
SendMessage(hWnd,WM_DESTROY,0,0);
break;
default:
break;
}
}
void WndProc_OnMenu(HWND hwnd, HWND hwndCtl, UINT xPos, UINT yPos)
{
HMENU hMenu,hMenuTrackPopup ;
if (hwndCtl == HANDLES.hWndListView)
{
// Get the context menu from the resource file.
hMenu = LoadMenu(HANDLES.hInst, MAKEINTRESOURCE(IDR_TRACKPOPUP));
// Get the first item in the menu for TrackPopupMenu().
hMenuTrackPopup = GetSubMenu(hMenu, 0);
// Draw and track the "floating" menu.
TrackPopupMenu(hMenuTrackPopup,
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
xPos, yPos,
0, HANDLES.hWndMain, NULL);
// Destroy the menu
DestroyMenu(hMenu);
}
}
LRESULT WINAPI CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hWnd, WM_CONTEXTMENU, WndProc_OnMenu );
HANDLE_MSG(hWnd,WM_CREATE,WndProc_OnCreate);
HANDLE_MSG(hWnd,WM_DESTROY,WndProc_OnDestroy);
HANDLE_MSG(hWnd, WM_SIZE, WndProc_OnResize);
HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand );
case WM_NOTIFY:
if (TV_NotifyHandler(hWnd, msg, wParam, lParam))
{
break;
}
if (TT_NotifyHandler(hWnd, msg, wParam, lParam))
{
break;
}
if (LV_NotifyHandler(hWnd, msg, wParam, lParam))
{
break;
}
default:
return(DefWindowProc(hWnd,msg,wParam,lParam));
}
return 0;}
ATOM RegisterAppClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=(WNDPROC)WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=LoadIcon(hInstance,(LPCTSTR)IDI_ICON_APP);
wcex.hIconSm=LoadIcon(hInstance,(LPCTSTR)IDI_ICON_APP);
wcex.hCursor=NULL;
wcex.hbrBackground=CreateSolidBrush(COLOR);
wcex.lpszMenuName=MAKEINTRESOURCE(IDM_MENU_MAIN);
wcex.lpszClassName=ClassName;
return RegisterClassEx(&wcex);
}
BOOL InitInstanceWindow(HINSTANCE hInstance,int nCmdShow)
{
HWND hWnd=CreateWindow(ClassName,AplicationTitle,
WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,
hInstance,NULL);
if(!hWnd) return 0;
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
return 1;
};
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine,int nCmdShow)
{
HANDLES.hInst=hInstance;
InitCommonControls();
if(!RegisterAppClass(hInstance))
{
MessageBox(NULL,"Ошибка регистрации класса окна!!!",
Error_title,MB_OK|MB_ICONERROR);
return 0;
}
if(!InitInstanceWindow(hInstance,nCmdShow))
{
MessageBox(NULL,"Ошибка создания окна!!!",
Error_title,MB_OK|MB_ICONERROR);
return 0;
}
HWND hwndDlg=(HWND)0;
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
if(!IsDialogMessage(PropHandle,&msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);}}
return msg.wParam;
}