Примечание | задача: Разработать программный продукт для ведения картотеки аудиодисков |
Загрузить архив: | |
Файл: ref-25755.zip (596kb [zip], Скачиваний: 175) скачать |
УЧРЕЖДЕНИЕ ОБРАЗОВАНИЯ «БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ИНФОРМАТИКИ ИРАДИОЭЛЕКТРОНИКИ» |
|
ПОЯСНИТЕЛЬНАЯ ЗАПИСКА к курсовому проекту по предмету “Системное программное обеспечение ЭВМ” Тема: Win32-приложение Картотека аудио дисков |
|
Выполнил: Проверил: |
|
УЧРЕЖДЕНИЕ ОБРАЗОВАНИЯ «БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ИНФОРМАТИКИ ИРАДИОЭЛЕКТРОНИКИ»
Институт повышения квалификации и переподготовки руководящих работников и специалистов по информационным технологиям и радиоэлектронике
Факультет компьютерных технологий
"УТВЕРЖДАЮ” зав. Каф. ПОИТ
–––––––––––––––––/ В.В. Бахтизин//
" " ____2006 г.
Курс: Системное программное обеспечение ЭВМ
Тема курсовой работы: Win32-приложение Картотека аудио дисков.
Задание 3 по курсовой работе студенту гр. _________________________.
Разработать программный продукт для ведения картотеки аудиодисков.
Для каждогопроизведения в файле на диске хранится
Наименование диска (группы), наименование произведения, исполнитель, учетный номер диска в картотеке, кто взял, дата.
Максимальное количество добавляемых в одном сеансе записей –50.
Основные функции приложения:
Меню Файл - создание нового файла данных, загрузка существующего, сохранение, сохранение как...;
Меню Правка - добавление, изменение,
удаление элемента списка. Отображение информации элемента списка
в виде окна свойств(Property Scheet;
Меню Вид - команды режима
отображения(большие и малые значки, список и таблица). В режиме таблица
обеспечивается
сортировка по соответствующему
параметру при щелчке мыши по заголовку колонки;
Меню Помощь - вызов помощи и окна информации о программе.
Требования к программе.
Программа должна работать под Windows 95/98
Язык интерфейса – русский. Тип интерфейса - Explorer(Проводник).
Обязательные элементы итерфейса: 1) меню;
2) панель инструментов (ToolBar) с появляющимися подсказками - Tool Tips;
3) элемент TreeView ("древовидное отображение") для списка дисков и исполнителей на каждом диске;
4) элемент ListView ("графический список") для списка произведений выбранного диска и исполнителя;
5) элемент StatusBar (строка состояния )- наименование диска, исполнитель, количество произведений в списке.
6) контекстное меню, вызываемое при щелчке правой кнопкой мыши по элементу графического списка, содержиткоманду "Свойства" из меню Правка для отображения всех данных записи для выбранногоэлемента списка "ListView". Данные вывести в диалоговом окне в виде “Блокнота свойств”(PropertySheed), содержащего не менее двух страниц свойств;
Содержание пояснительной записки
Введение.
1.Анализ задания и постановка задачи.
2.Описание логического представления данных и их назначения.
3.Описание структуры программы.
4. Разработка программы (пояснения к тексту программы, примененным технологиями принятым решениям, схемы основных алгоритмов)
5.Тестирование программы и тестовые наборы данных.
6.Технические требования и инструкция по применению.
Заключение.
Литература
Приложения – исходные тексты, заголовочные файлы, сценарии ресурсов, тестовые данные.
Срок выдачи задания 15.09.2006г
Срок выполнения курсовой работы25.12.2006 г Руководитель курсовой работы __________________
Задание принял к исполнению: дата ___________________ подпись_________________
2. Структура выходных и входных данных
3. Описание основных классов и структур
5.5.2 Добавление новой композиции
5.6.2 Редактирование композиции
Язык программирования служит двум связанным между собой целям: он дает программисту аппарат для задания действий, которые должны быть выполнены, и формирует концепции, которыми пользуется программист, размышляя о том, что делать. Первой цели идеально отвечает язык, который настолько "близок к машине", что всеми основными машинными аспектами можно легко и просто оперировать достаточно очевидным для программиста образом. С таким умыслом первоначально задумывался C. Второй цели идеально отвечает язык, который настолько "близок к решаемой задаче", чтобы концепции ее решения можно было выражать прямо и коротко. С таким умыслом предварительно задумывались средства, добавленные к C для создания C++.
Связь между языком, на котором мы думаем/программируем, и задачами и решениями, которые мы можем представлять в своем воображении, очень близка. По этой причине ограничивать свойства языка только целями исключения ошибок программиста в лучшем случае опасно. Язык предоставляет программисту набор концептуальных инструментов; если они не отвечают задаче, то их просто игнорируют. Например, серьезные ограничения концепции указателя заставляют программиста применять вектора и целую арифметику, чтобы реализовать структуры, указатели и т.п. Хорошее проектирование и отсутствие ошибок не может гарантироваться чисто за счет языковых средств. Система типов должна быть особенно полезна в нетривиальных задачах. Действительно, концепция классов в C++ показала себя мощным концептуальным средством.
Разработать программный продукт для ведения картотеки аудиодисков. Программный продукт должен позволять:
Система должна обеспечить выполнение этих возможностей путем реализации алгоритмов удаления, редактирования и добавления новой информации.
При добавлении необходимо обеспечить проверку на допустимые значения и ограничивать действия пользователя в тех случаях, когда он пытается ввести пустые значения.
При редактировании следует аналогичным образом проверять редактируемые значения.
Для реализации поставленной задачи использовать VisualStudioC++ версии не ниже 6.0. В частности применить winapi.
Данные предполагается хранить в структурированном файле. Так как структура данных может быть выражена лишь одной таблицей, то нет необходимости прибегать к применению каких либо СУБД. Файл с данными можно размещать как на локальном компьютере, так и в сети, предоставляющей открытый доступ к такому виду ресурса.
Вся структура данных может быть выражена одной таблицей:
Таблица 1 - схема данных |
|
название |
тип |
название_диска |
строка |
название_трека |
строка |
исполнитель |
строка |
учетный номер |
длинное целое |
кем_взят |
строка |
дата_добавления |
дата |
Рисунок 1 – размещение данных в файле |
В проекте были использованы встроенные классы и структуры windowsapi. Их перечисление дается ниже:
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 |
Алгоритм работы программы можно представить диаграммой 1.
Диаграмма 1 – алгоритм работы программы |
Запуск приложения осуществляется традиционным способом (двойным/одинарным кликом по иконке приложения).
Рисунок 2 – Запуск приложения |
Поскольку приложение написано с использованием только winapi, оно исключает необходимость в дополнительным библиотеках, фреймах, виртуальных машинах (подобной javavirtualmachine). Работа приложения также гарантированна в ОС Windows 98 и более поздних версиях.
После запуска, приложение создает окно типичное для windows приложений со встроенной возможностью его сворачивания в панель задач, максимизации, минимизации и закрытия приложения.
Рисунок 3 – главное окно приложения |
Приложение имеет главное меню со следующей структурой:
Вход в меню осуществляется путем нажатия клавиши alt, а перемещение путем нажатия стрелок вверх/вниз/влево/вправо (←↑→↓).
Рисунок 4 – меню |
Ниже главного меню, в окне приложения располагается панель инструментов, частично дублирующая функциональность главного меню.
Дублируются следующие пункты:
Этот элемент управления представляет собой набор кнопок, как привило без подписей, но с интуитивно понятными изображениями. Такой набор объединяется в группу и может стать перемещаемым в пределах окна и вне его при условии поддержки данной функции разработчиком.
Панель инструментов обеспечивает более быстрый доступ, нежели главное меню приложения и содержит наиболее часто используемые пункты главного меню.
Рисунок 5 – панель инструментов |
Панель инструментов поддерживает систему помощи, называемой “всплывающие подсказки”. Для их активизации следует подержать курсор 2 секунды над интересующей кнопкой панели инструментов.
Рисунок 6 – всплывающие подсказки |
Ниже панели инструментов располагается древовидная структура и параллельно ей, графический список.
В древовидной структуре отображается список дисков. Список дисков привязан к логическому корню “коллекция”. В свою очередь каждый диск в отдельности может содержать список произведений и соответственно быть корнем для них (дисков).
Графический список способен работать в двух режимах. Когда в древовидной структуре активным (выделенным) является диск, то графический список отображает все произведения в данном диске – это первый режим. Если активным является не диск, а одно из его произведений, то графический список преобразуется в блокнот свойств этого произведения – это второй режим.
В сущности, графический список и блокнот свойств, это абсолютно разные элементы управления, никак между собой не связанные, однако в данном случае они приобретают логическую связь и могут рассматриваться как единый элемент управления.
Рисунок 7 – Состояния древовидной структуры и графического списка |
Последним элементов в окне является строка состояния. Она реагирует на действия пользователя и отображает подсказки согласно контексту работы.
В начале работы программы строка состояния пуста. Если пользователь выберет диск, то в ней отобразится:
Если пользователь выберет конкретное произведение, то к вышеописанному списку добавятся названия композиции и имя исполнителя.
Рисунок 8 – Состояния строки состояния |
После небольшого ознакомления можно приступить к описанию работы программы.
Данные программы (коллекции) хранятся в файлах с расширением *.ddb. Конечно, не кто не может помешать нам сохранять их с другими расширениями, однако такой выработанный годами подход не позволяет запутаться в бесчисленном множестве других файлов.
Если подобных файлов не было создано раньше, то следует приступить к созданию новой коллекции. Это можно сделать при помощи:
· Файл”→“Новый” либо аналогичной кнопкой в панели инструментов;
· Windows).
В итоге мы увидим окно, изображенное на рисунке 3. Теперь мы можем работать с новой коллекцией. В данных условиях у нас имеются следующие конструктивные возможности:
Функция сохранение документа позволяет указать программе о необходимости сохранения данных на жесткий диск, что уменьшает вероятность потери информации в результате сбоя в сети.
Для сохранения документа необходимо в главном меню выбрать пункт “Файл”→“Сохранитькак” либо “Файл”→“Сохранить”. Кнопка с аналогичной функциональностью есть и в панели инструментов.
Действия этих пунктов ничем друг от друга не отличаются. “Сохранитькак” выбирается только в том случае, когда требуется сохранить документ с другими параметрами (имя документа и/или месторасположение). Если документ новый, и мы выбираем пункт “Сохранить”, программа автоматически вызовет функцию “Сохранитькак” т.к. новый документ пока не имеет ни имени, ни месторасположения.
После выбора пункта “Сохранитькак” вызывается одноименный диалог, который позволяет задать новое имя документа и/или месторасположение. Его изображение показано на рисунке 9.
Рисунок 9 – диалог “Сохранить как” |
“Открытие документа” позволяет загрузить ранее созданную коллекцию. Если ранее не было создано каких-либо коллекций, то следует приступить к процедуре создания нового документа, описанной выше.
Для открытия документа следует выбрать пункт главного меню “Файл”→“Открыть” либо воспользоваться аналогичной кнопкой в панели инструментов. После этого пользователю будет предложено несколько действий в зависимости от текущего состояния программы:
Рисунок 10 – предупреждение “Вы хотите сохранить изменения в документе?” |
Диалог “Открыть документ” изображен на рисунке 11.
Рисунок 11 – диалог “Открыть документ” |
Добавление новой информации осуществляется посредством пункта главного меню “Правка”→“добавить”. Данный пункт функционирует в двух режимах:
Выбор режима работы зависит от того, какой объект в данным момент выделен в древовидной структуре. Выделенными могут оказаться 3 типа элемента:
Рисунок 12– выделенные объекты |
Если выделенной оказалась вся коллекция, то пункт главного меню “Правка”→“добавить” вызывает диалог “добавлениеновогодиска”. Если выделенным оказывается непосредственно диск, то вызываться будет уже диалог “добавление новой композиции”. Он также будет вызываться и при условии, если выделен один трек.
Для добавления новогодиска в новую либо уже существующую коллекцию, следует выбрать пункт “Правка”→“добавить”. При соблюдении вышеописанных условий в разделе “добавление информации”, это повлечет за собой вызов диалога “добавлениедиска”. Он изображен на рисунке 13.
Рисунок 13 – диалог “добавлениедиска” |
В данном диалоге имеется два поля для ввода текста и две кнопки. Поля предназначены для ввода названия группы и названия альбома.
При нажатии кнопки “добавить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!”.
Рисунок 14 – предупреждение “Поля не могут иметь пустые значения!!!” |
Если добавление прошло успешно, пользователю выдается сообщение “Данные добавлены”.
Рисунок 15 – отчет “Данные добавлены” |
При этом после добавления данных не происходит выхода из диалога. Это дает возможность пользователю делать множественные добавления минуя постоянное обращение к главному меню.
Для выхода из диалога достаточно нажать кнопку “отмена”.
Для добавления новой композиции (трека), следует выбрать пункт “Правка”→“добавить”. При соблюдении вышеописанных условий в разделе “добавление информации” (добавление новой композиции возможно лишь в том случае, если в проекте имеется хотя бы один диск, и он является выделенным в древовидной структуре), это повлечет за собой вызов диалога “добавление новой композиции”. Он изображен на рисунке 16..
Рисунок 16 – диалог “добавление новой композиции (трека)” |
В данном диалоге имеется три поля для ввода текста и две кнопки. Поля предназначены для ввода названия трека, имени исполнителя и даты добавления. При нажатии кнопки “добавить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!” изображенное на рисунке 14.
Если добавление прошло успешно, пользователю выдается сообщение “Данные добавлены” изображенное на рисунке 15.
При этом после добавления данных происходит выход из диалога. Также выход осуществляется нажатием кнопки “отмена”.
Редактирование информации осуществляется посредством пункта меню “Правка”→“изменить”. Данный пункт функционирует в двух режимах:
Выбор режима работы зависит от того, какой объект в данным момент выделен в древовидной структуре. Выделенными могут оказаться 3 типа элемента:
Если выделенной оказалась вся коллекция, то пункт главного меню “Правка”→“изменить” не выполняет каких-либо действий т.к. не выделен объект для редактирования (диск или трек). Если выделенным оказывается непосредственно диск, то вызывается диалог “редактированиедиска”. Если выделен один трек, то вызывается диалог “редактированиетрека”.
Для редактирование, следует выбрать пункт “Правка”→“изменить”. При соблюдении вышеописанных условий в разделе “редактирование информации”, это повлечет за собой вызов диалога “редактированиедиска”. Он изображен на рисунке 17.
Рисунок 17 – диалог “редактированиедиска” |
В данном диалоге имеется такие же поля, как и в диалоге “добавлениедиска” но уже заполненные добавленными ранее значениями.
При нажатии кнопки “сохранить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!” изображенное на рисунке 14.
Если сохранение прошло успешно, пользователю выдается сообщение “Данные сохранены” изображенное на рисунке 18.
Рисунок 18 – отчет “Данные сохранены” |
При этом после редактирования данных происходит выход из диалога. Также выход осуществляется нажатием кнопки “отмена”.
Для редактирования композиции (трека), следует выбрать пункт “Правка”→“изменить”. При соблюдении вышеописанных условий в разделе “редактирование информации” это повлечет за собой вызов диалога “редактирование трека”. Он изображен на рисунке 19..
Рисунок 19 – диалог “редактирование композиции (трека)” |
В данном диалоге имеется такие же поля, как и в диалоге “добавлениетрека” но уже заполненные добавленными ранее значениями.
При нажатии кнопки “сохранить” идет проверка данных на допустимость введенных значений. Если значениями полей, являются пустые строки, то выдается предупреждающее сообщение “Поля не могут иметь пустые значения!!!” изображенное на рисунке 14.
Если сохранение прошло успешно, пользователю выдается сообщение “Данные сохранены” изображенное на рисунке 18.
При этом после редактирования данных происходит выход из диалога. Также выход осуществляется нажатием кнопки “отмена”.
Удаление информации осуществляется посредством пункта меню “Правка”→“удалить”. Данный пункт функционирует в двух режимах:
Выбор режима работы зависит от того, какой объект в данным момент выделен в древовидной структуре. Выделенными могут оказаться 3 типа элемента:
Если выделенной оказалась вся коллекция, то пункт главного меню “Правка”→“удалить” не выполняет каких-либо действий т.к. не выделен объект для удаления (диск или трек).
Если выделенным оказывается непосредственно диск, то пункт главного меню “Правка”→“удалить” вызывает запрос, обращенный к пользователю, о подтверждении его действий по удалению диска и всех треков, привязанных к нему. В запросе у пользователя имеется 2 варианта ответа:
Рисунок 20 – предупреждение “Данные диска и всех его треков будут безвозвратно утеряны!!! Вы уверены?” |
Если выделенным оказывается непосредственно один трек, то пункт главного меню “Правка”→“удалить” вызывает запрос, обращенный к пользователю, о подтверждении его действий по удалению трека. В запросе у пользователя имеется 2 варианта ответа:
Рисунок 21 – предупреждение “Данные трека будут безвозвратно утеряны!!! Вы уверены?” |
В программе имеется пункт меню “вид”. Он позволяет назначать внешний вид графического списка. Имеются следующие варианты вида:
На панели инструментов имеется дублирующие кнопки данной функции. На рисунке 22 показаны возможные виды графического списка.
Рисунок 22 – возможные виды графического списка |
Для получения информации и версии продукта и о его разработчиках следует обратиться к пункту “Помощь”→“ О программе”. После выбора этого пункта на экране появиться сообщение, изображенное на рисунке 23.
Рисунок 23 – отчет “ О программе ” |
Выход из программ можно осуществить путем выбора пункта главного меню “Файл”→“Выход”.
Также выход осуществляется нажатием кнопки “X” в заголовке главного окна приложения.
Рисунок 24 – кнопка выхода в заголовке главного окна приложения |
Для тестирования программы необходимо проверить ряд функций программы:
Все эти действия можно объединить в группу и проверить одновременно. Для этого достаточно составить один сценарий, в котором будут следующие действия:
Ниже приводятся описанные действия.
1.запуск программы: После запуска программы, на экране должно отобразиться главное окно программы, изображенное на рисунке 3.
2.создание нового документа: После запуска программы можно приступить к созданию нового документа. Это можно сделать при помощи:
3.наполнение документа: Для наполнения документа следует добавить в коллекцию диски и треки для них.
Для добавления новых дисков нужно выполнить следующие действия:
Для добавления новых треков к дискам нужно выполнить следующие действия:
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++.
Приложение |
#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 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 { 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 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 { if
(max max=WkRec[i].ind; temp[i]=WkRec[i]; } // Пересоздаем рабочую
структуру с новым размером delete [] WkRec; WkRec=new
WorkRecord[++dwWkCount]; //Копируем записи из
временной структуры в рабочую for
(i=0;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 if
(WkRec[i].indParent==index) { MessageBox(NULL,"Удалите
связанные данные","Ошибка",MB_OK); return
FALSE; } // Ищем позицию
удаляемого элемента int pos; for
(i=0;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 { temp[i]=WkRec[i]; } //Удаляет рабочие
записи delete [] WkRec; // Создает новые
рабочие записи WkRec=new
WorkRecord[dwWkCount]; for
(i=0;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 { 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 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 { 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; }