Полезное:
Как сделать разговор полезным и приятным
Как сделать объемную звезду своими руками
Как сделать то, что делать не хочется?
Как сделать погремушку
Как сделать так чтобы женщины сами знакомились с вами
Как сделать идею коммерческой
Как сделать хорошую растяжку ног?
Как сделать наш разум здоровым?
Как сделать, чтобы люди обманывали меньше
Вопрос 4. Как сделать так, чтобы вас уважали и ценили?
Как сделать лучше себе и другим людям
Как сделать свидание интересным?
Категории:
АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника
|
Рекомендации по написанию программыЗадание 1. Разработка программы редактирования файлов специализированного формата.
Исходные данные:
Требования к внешнему виду программы:
- отображение BMP файлов в двух форматах по выбору: как рисунок и как информация о рисунке (реальный размер); - в случае просмотра рисунка его размер должен изменяться автоматически с изменением окна просмотра; - количество одновременно открытых файлов не ограничено; - если файл уже открыт и производится попытка его повторного открытия, то соответствующий файл вновь не открывается, а окно просто перемещается на передний план.
Рекомендации по написанию программы.
Запустите Visual C++. Menu -> File -> New -> Projects -> MFC AppWizard (exe) Задайте Имя проекта и его расположение. Выберите: - Multiple Documents (step 1 of 6) - Document/View architecture support (step 1 of 6) - No database support (step 2 of 6) - No compound document support (step 3 of 6) - No Automation (step 3 of 6) - Not an ActiveX control (step 3 of 6) - Docking Toolbar (step 4 of 6) - Initial Status bar (step 4 of 6) - Printing and Print preview (step 4 of 6) - NO Context-sensitive Help (step 4 of 6) - 3D Controls (step 4 of 6) - NO MAPI (step 4 of 6) - NO Windows Socket (step 4 of 6) - Toolbar looks Normal (step 4 of 6) - MFC Standard project style (step 5 of 6) - Do not change any file names (step 6 of 6) В средах VS.NET, VS2005 последовательность действий практически идентична.
Добавление чего-то, что вносит существенные изменения, требует создания дополнительного класса. В нашем случае это поддержка BMP файлов: загрузка и отображение. Для добавления классов удобно использовать ClassWizard - запускаем ClassWizard (Menu -> View -> ClassWizard) - нам нужен новый класс, поэтому выбираем Add Class ->New… - называем его MyBMP - в качестве базового нам подходит самый простой класс CObject, однако такого в списке нет и приходится выбирать наипростейший, например, CStatic В VS.NET и VS2005 ClassWizard отсутствует в явном виде, но функциональность вся тем не менее поддерживается. В частности добавить класс здесь можно в окне Solution Explorer в закладке Class View выбрать корневой элемент (название проекта) и в меню по правой кнопке мыши выбрать элемент “Add” -> “Add Class…”, далее в Categories выбрать MFC, в правой части окна MFC Class. Далее Open, задаем имя класса и в качестве базового выбираем CObject. В результате в проекте появятся два файла MyBMP.cpp и MyBMP.h Теперь «упростим» наш класс, т.е. уберем все лишнее. - в качестве базового класса укажем CObject вместо CStatic - удалим карту сообщений и оставим только Конструктор и деструктор Теперь при любой попытке войти в ClassWizard, он будет ругаться, что не может найти информацию о данном классе и предложить найти ее вручную или исключить класс из списка классов, контролируемых Wizardом. Нам подходит последнее, т.к. все, что надо мы и вручную добавим. Проблема не появилась бы, если использовать среду Visual C++ 7.0, т.к. там есть CObject класс в качестве непосредственного базового (так и есть). Другим путем создания класса (впрочем с теми же трудностями) является использование закладки ClassView в проекте. Там можно также использовать контекстное меню Add Class. Заметьте также, что добавление данного класса можно было осуществить и вручную, а не с использованием ClassWizard и результат был бы таким же.
Первым делом убедимся в работоспособности нашего класса. Для этого добавим в него функцию прорисовки: BOOL Draw(CDC *pDC,RECT *pRect); Типы параметров должны быть вам знакомы. Первый – класс контекста дисплея и второй – прямоугольная область (где осуществлять прорисовку). В качестве тела (в cpp файл) добавим прорисовку прямоугольника (пока): pDC->FillSolidRect(0,0,100,100,0xFF0000); return TRUE; Класс документа должен содержать структуру нашего объекта, коим является BMP рисунок. Так как поддержка BMP у нас возложена на MyBMP класс, то логично добавить в класс формата документа (…Doc) объект класса MyBMP: MyBMP ozbmp; // в публичную секцию (не забудьте также про h файл) Теперь у нас две задачи. В классе Doc осуществить загрузку информации, а в классе View отображать ее корректно. В этом основной принцип Documrnt/View модели. С загрузкой пока подождем, а прорисовку добавим. Нам необходим класс …View. Там есть метод OnDraw (вы можете найти его напрямую или через ClassWizard). Там уже есть код получения объекта документа – это тот объект, который описан в Doc классе. Добавим прорисовку: pDoc->ozbmp.Draw(pDC,NULL); Проверьте, теперь в каждом окне при запуске программы будет прорисован квадрат синего цвета 100 на 100.
Теперь займемся определением области вывода. Проблема в том, что вывод может осуществляться как в окно, так и на внешнее растровое устройство, например принтер. Пути «прохождения» сообщений для прорисовки в этих случаях различны. Попробуем это решить. Добавим в публичную секцию класса View прямоугольник: RECT m_rectDraw; В методе прорисовки класса View чуть поменяем код: GetClientRect(&m_rectDraw); pDoc->ozbmp.Draw(pDC, &m_rectDraw); и, соответственно в методе прорисовки класса MyBMP: pDC->FillSolidRect(pRect,0xFF0000); Проверим. Теперь при смене габаритов окна прямоугольник всегда принимает нужный размер. Однако, если вы попытаетесь просмотреть как рисунок будет выглядеть на странице принтера (Menu->File->Print Preview), то увидите, что там рисуется лишь маленький прямоугольник и он не масштабируется на всю страницу. Займемся этим. При печати на принтере (и при просмотре макета страницы) используется метод OnPrint, обрабатывающий соответствующее сообщение от Windows. У нас в классе View такого метода нет. Добавим его. Запустите ClassWizard, выбирите класс View, в списке Messages выберите OnPrint. Теперь нажмите кнопку AddFunction. Достаточно просто. В VS.NET и VS2005 это следует делать так. Переходим в обзор Class View, выбираем наш класс, открываем его и там находим элемент Maps. Это карты класса MFC. Нам нужна карта сообщений MESSAGE (она там единственная). Выберите ее. Теперь вам надо перейти к реализации карты в исходном файле (участок кода в *.cpp файле-реализации класса между макросами BEGIN_MESSAGE_MAP и END_MESSAGE_MAP). Обычно это можно сделать двойным кликом на элементе MESSAGE. Ваша задача расположить курсор ввода внутри кода карты сообщений. Тогда в тулбаре окна Properties появится кнопка Messages. Нажмите на нее и выберите сообщение, обработчик которого надо добавить/изменить. Однако, если обработчик сообщения уже реализован в базовом классе, вам следует искать обработчик в списке методов базового класса, а не обработчиков сообщений. Для этого нажмите другую кнопку в тулбаре окна Properties. Она называется Overrides. В списке найдите нужный метод и в опциях выберите <Add> … В нашем случае найдите метод OnPrint и выберите опцию <Add> OnPrint. В ваш код будут добавлен соответствующий метод. До добавления нами функции, тем не менее, какая-то обработка была – мы ведь видели, что прямоугольник рисуется. В данном случае мы подменили функцию базового класса нашей собственной и должны либо вызвать функцию базового класса, либо написать свою. Последнее нам подходит, т.к. тело функции достаточно просто. Установим нужный размер поля вывода и вызовем функцию прорисовки: m_rectDraw = pInfo->m_rectDraw; OnDraw(pDC); Вызов же базовой функции закоментируем. Однако, в этом случае мы получаем m_rectDraw здесь, а не в функции прорисовки, поэтому и там необходимо внести изменения: if(pDC->IsPrinting()){ pDoc->ozbmp.Draw(pDC, &m_rectDraw); } else{ GetClientRect(&m_rectDraw); pDoc->ozbmp.Draw(pDC, &m_rectDraw); }
Добавим функцию загрузки BMP файла в наш класс MyBMP: BOOL ZBmp::Load(const char *szFileName); параметр – имя файла для загрузки (с путем) Для подгрузки и дальнейшего отображения BMP файла удобно поступать так: - загрузить BMP файл с помощью LoadImage (вам уже знакомо) - преобразовать хэндл в класс CBitmap с помощью метода CBitmap::FromHandle() - запросить совместимый контекст дисплея CreateCompatibleDC() - выбрать объект CBitmap в качестве активного SelectObject() - использовать функцию StretchBlt для масштабирования CBitmap до нужных размеров вывода Кроме метода Load вам понадобиться изменить и метод Draw класса MyBMP. Сделайте это самостоятельно. Добейтесь эффекта автоматического масштабирования картинки под окно вывода Последнее, что необходимо – вызвать функцию подгрузки в нужном месте. Для этого существует метод Serialize. Нам нужна его часть, отвечающая за загрузку, а не запись. Добавим туда соответствующий код: ozbmp.Load(ar.GetFile()->GetFilePath());
Document/View модель позволяет добавлять любое количество просмотрщиков (View) к любому документу (Doc). Добавим дополнительный View класс для отображения технической информации о BMP файле (размер по X и по Y). Для этого легче всего скопировать cpp и h файлы уже существующего класса View, добавить их в проект и изменить там везде имя класса на новый, скажем View2. Того же эффекта можно добиться путем добавления класса с помощью ClassWizard, однако это может потребовать больше усилий. Выберите любой вариант и добавьте класс самостоятельно. Добейтесь компиляции проекта без ошибок. Не забудьте, что, если вы копируете вручную, то вы должны заменять имя класса не только к коде C++, но и в спец Макро и спес Комментариях. Теперь нам необходимо добавить еще одну константу в ресурсах. В строковых ресурсах скопируйте текущую строку с описание типа ресурса (IDR_…TYPE) под новым именем (IDR_…TYPE2). В тексте представлена спец. Последовательность, которая определяет тип документа, его расширение, его название и т.д. Подробную информацию о формате данной строки вы можете найти в Помощи по методу GetDocString класса CdocTemplate. Попробуйте варьировать значения строки, чтобы типы отображения были различны. В основном файле проекта найдите место, где формируется шаблон данного Document/View взаимодействия и добавьте туда еще один шаблон для того же документа: CMultiDocTemplate* pDocTemplate2; pDocTemplate2 = new CMultiDocTemplate( IDR_…TYPE2, RUNTIME_CLASS(C…Doc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(C…View2)); AddDocTemplate(pDocTemplate2); здесь многоточие означает часть имени классов, зависящее от имени вашего проекта. Теоретически теперь будут работать оба вьюера. Проверить это легко. При запуске программы она спросит у вас какой тип вьюера использовать для отображения файла. В дальнейшем нам понадобится получать доступ к зарегистрированным шаблонам. Для этого следует шаблонные переменные сделать не локальными, а членами класса приложения. Перенесите их описание в класс C…App: CMultiDocTemplate* pDocTemplate; CMultiDocTemplate* pDocTemplate2; Последний необязательный шаг – добавление иконки для нового вьюера. В ресурсах добавьте иконку с идентификатором, соответствующем нашему новому типу вьюера.
В новом классе-вьюере достаточно лишь сменить вызов функции в функции перерисовки с Draw на DrawText. Все остальное может оставаться в нем так же как и в первом вьюере (не зря же мы его писали). Понятно, что необходимо добавить эту функцию в MyBMP класс: BOOL DrawText(CDC *pDC, RECT *pRect); Здесь вам понадобиться вывести текст (форматированный). Для этого вам могут понадобиться: - CDC::GetTextMetrics() - wsprintf() - CDC::DrawText()
Запретим открытие пустого окна при старте и, напротив, будем открывать окно, если файл указан в командной строке. Найдите след. строку в главном файле проекта: if (!ProcessShellCommand(cmdInfo)) return FALSE; закомментируйте его и поместите туда другой код: if (m_lpCmdLine[0]!= '\0'){ // open an existing document OpenDocumentFile(m_lpCmdLine); } // Enable drag/drop open m_pMainWnd->DragAcceptFiles(); Попутно мы подключили поддержку Drag&Drop. Просто, верно?
Добавим поддержку в меню переключения с одного вьюера на другой. В редакторе ресурсов скопируйте меню под именем IDR_…TYPE и установите имя нового меню в IDR_…TYPE2. Как видите константа меню соответствует типу вьюера (см. параграф 6). Теперь в обоих этих меню добавьте по два элемента: Menu->View->Show Picture с константой ID_VIEW_PIC и Menu->View->Show Info с константой ID_VIEW_TEXT Теперь надо добавить функции – реакции на новые элементы меню. В ClassWizard выберите класс CMainFrame, в поле Object IDs найдите ID_VIEW_PIC, в поле Messages выберите COMMAND, нажмите Add Function и добавьте функцию OnViewPic. Аналогичные действия проведите для второго элемента и добавьте функцию OnViewText. Теперь несколько «нечеткая» последовательность. Заполните ваши обработчики новых команд меню так: void CMainFrame::OnViewPic(){ CreateOrActivateFrame(theApp.pDocTemplate,RUNTIME_CLASS(CTest2View)); } void CMainFrame::OnViewText(){ CreateOrActivateFrame(theApp.pDocTemplate2,RUNTIME_CLASS(CTextBView)); } Как видите – они только вызывают некую функцию, которую также необходимо вручную добавить в класс CMainFrame: void CMainFrame::CreateOrActivateFrame(CDocTemplate* pTemplate,CRuntimeClass* pViewClass) { CMDIChildWnd* pMDIActive = MDIGetActive(); ASSERT(pMDIActive!= NULL); CDocument* pDoc = pMDIActive->GetActiveDocument(); ASSERT(pDoc!= NULL); CView* pView; POSITION pos = pDoc->GetFirstViewPosition(); while (pos){ pView = pDoc->GetNextView(pos); if (pView->IsKindOf(pViewClass)) { pView->GetParentFrame()->ActivateFrame(); return; } } CMDIChildWnd* pNewFrame=(CMDIChildWnd*)(pTemplate->CreateNewFrame(pDoc, NULL)); if (pNewFrame == NULL) return; // not created ASSERT(pNewFrame->IsKindOf(RUNTIME_CLASS(CMDIChildWnd))); pTemplate->InitialUpdateFrame(pNewFrame, pDoc); } Если вы разберете текст функции, то увидите, что основное ее назначение – избежать повторного открытия окна для файла, который уже открыт в одном из окон. Разберитесь с этим самостоятельно. И последний штрих. Как видите здесь используется переменная theApp, однако она не видна от сюда. Сделаем ее видимой – добавим ее описание (она уже создается в главном файле проекта) прямо за описанием класса – в h файл: extern C…App theApp;
|