Программирование для карманных компьютеров
Шрифт:
На третьем шаге настройки предстоит принять два решения. Если нужно, чтобы среда автоматически сгенерировала комментарии с указаниями, что нужно добавить в исходных кодах, необходимо выбрать пункт Yes, please. Если разработчик думает, что может обойтись без подсказок, то следует выбрать пункт No, thank you. Также нужно решить, будет ли библиотека MFC сгенерирована компилятором как динамически загружаемая библиотека. Для этого нужно выбрать пункт as a shared DLL. Если же нужно ввести эту библиотеку прямо в код приложения, следует выбрать пункт as a staticaly linked library.
? Наконец, четвертый шаг мастера просто выведет список файлов, которые будут созданы в приложении, и разработчику останется только нажать кнопку Finish.
? Каковы бы ни были действия программиста, в результате работы мастера всегда создается приложение, которое не обладает никакой функциональностью. Добавлять возможности к созданному шаблону программы – задача программиста.
Упражнение 5.2
В этом упражнении при помощи мастера будет создан шаблон приложения, которое затем будет превращено в простой текстовый редактор.
1. Создать новое приложение типа WCE Pocket PC 2003 с именем NotePad. Для него на первой странице мастера нужно задать тип Single Document with Doc List
2. Скомпилировать и запустить это приложение. На экран будет выведен документ в виде пустого чистого листа. Пункты меню редактирования не работают, команда меню сохранения файла срабатывает, но всегда сохраняет пустой файл. После закрытия окна документа на экран выводится список всех файлов, располагающихся в файловой системе устройства. В этом списке можно выбрать любой файл, но при попытке его открытия появится только чистый лист, в котором нельзя редактировать текст. Программист должен обеспечить отображение в списке файлов с расширением. txt, открытие выбранного файла для редактирования и сохранение измененного файла в текстовом формате.
3. Прежде всего необходимо изменить тип объекта CNotePadView. Поскольку разрабатывается текстовый редактор, следует использовать тип CEditView. Для этого нужно открыть в окне рабочего пространства вкладку ClassView, найти класс CNotePadView и изменить его объявление:class CNotePadView: public CEditView
4. В окне ClassView нужно раскрыть внутреннюю структуру класса CNotePadView и найти объявление метода PreCreateWindow(CREATESTRUCT& cs). Двойным щелчком на этом объявлении нужно открыть код реализации функции и изменить его, как показано в листинге 5.17. Листинг 5.17
BOOL CNotePadView::PreCreateWindow(CREATESTRUCT& cs)
{
if(!CEditView::PreCreateWindow(cs))
return FALSE;
cs.style &= ~WS_VSCROLL;
cs.style &= ~WS_HSCROLL;
cs.style &= ~ES_AUTOHSCROLL;
m_dwDefaultStyle &= ~WS_VSCROLL;
m_dwDefaultStyle &= ~WS_HSCROLL;
m_dwDefaultStyle &= ~ES_AUTOHSCROLL;
return TRUE;
}5. Запустив программу после внесения этих изменений, можно увидеть, что окно документа начинает себя вести как окно текстового редактора. В нем появился текстовый курсор, пользователь может набирать текст, появились полосы прокрутки. Однако если набрать в окне достаточно большой объем текста и прокрутить его горизонтально или вертикально, можно обнаружить проблемы с перерисовкой окна и выводом текста на экран. Даже при использовании технологии MFC многое разработчик должен делать самостоятельно.
6. Добавить к классу CNotePadView новый приватный метод. Для этого нужно щелкнуть правой клавишей мыши на имени класса в окне ClassView и выполнить команду Add Member Function. На экран будет выведено окно мастера. Его надо заполнить так, как это показано на рис. 5.6. Код этого метода приведен в листинге 5.18.
Рис. 5.6. Окно мастера создания метода класса.
Листинг 5.18void CNotepadView::UpdateViewWindow
{
CEdit& edit = GetEditCtrl;
TEXTMETRIC tm;
CDC* pDC = edit.GetDC;
pDC->GetTextMetrics(&tm);
edit.ReleaseDC(pDC);
CRect r;
edit.GetRect(&r);
int noOfVisibleLines = r.Height / tm.tmHeight;
if(edit.GetLineCount > noOfVisibleLines)
{
long lwStyle =::GetWindowLong(edit.GetSafeHwnd, GWL_STYLE);
if(!(lwStyle & WS_VSCROLL))
{
lwStyle |= WS_VSCROLL;
::SetWindowLong(edit.GetSafeHwnd, GWL_STYLE, lwStyle);
}
int nCaretLine = edit.LineFromChar;
int nFirstVisible = edit.GetFirstVisibleLine;
if(nFirstVisible + noOfVisibleLines <= nCaretLine)
{
HideCaret;
edit.LineScroll(nCaretLine – nFirstVisible – noOfVisibleLines + 1);
ShowCaret;
}
if(nFirstVisible > nCaretLine)
{
HideCaret;
edit.LineScroll(nCaretLine – nFirstVisible);
ShowCaret;
}
}
else
{
long lwStyle =::GetWindowLong(edit.GetSafeHwnd, GWL_STYLE);
if(!(lwStyle & WS_VSCROLL))
return;
int nFirstVisible = edit.GetFirstVisibleLine;
edit.LineScroll(-nFirstVisible, 0);
lwStyle &= ~WS_VSCROLL;
::SetWindowLong(edit.GetSafeHwnd, GWL_STYLE, lwStyle);
}
}7. Теперь необходимо связать этот метод со стандартным обработчиком события перерисовки измененного окна. Для этого надо добавить данное событие к классу CNotePadView и написать его обработчик. Нужно щелкнуть правой клавишей мыши на имени класса CNotePadView в окне ClassView и выполнить команду Add Virtual Function. На экран будет выведено окно мастера (рис. 5.7).
Этот мастер позволяет добавить к классу те функции, которые он наследует от базового класса. В данном случае добавляется существующее в базовом классе событие OnUpdate, которое вызывается после модификации документа для перерисовки его отображения в окне. В левом списке New Virtual Functions окна мастера нужно выбрать функцию OnUpdate, а затем нажать кнопку Add and Edit. Событие будет добавлено в класс, а в редакторе будет открыт код реализации этого события. Код нужно переписать, как показано в листинге 5.19. Листинг 5.19
void CNotePadView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CEditView::OnUpdate(pSender, lHint, pHint);
UpdateViewWindow;
}8. Несколько иначе добавляется событие OnKeyDown. Снова потребуется вызвать контекстное меню на имени класса CNotePadView в окне ClassView. Поскольку событие OnKeyDown является обернутым в метод MFC сообщением Windows, то на этот раз необходимо выбрать из контекстного меню команду Add Windows Message Handler. На экран будет выведено окно мастера (рис. 5.8).
9. В левом списке New Windows Messages/events нужно выбрать функцию WM_ KEYDOWN, двойным щелчком на ее имени нужно переместите ее в правый список и нажать кнопку OK.
void CNotePadView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CEditView::OnKeyDown(nChar, nRepCnt, nFlags);
if(nChar == VK_DELETE)
{
CEdit& edit = GetEditCtrl;
TEXTMETRIC tm;
CDC* pDC = edit.GetDC;
pDC->GetTextMetrics(&tm);
edit.ReleaseDC(pDC);
CRect r;
edit.GetRect(&r);
int noOfVisibleLines = r.Height / tm.tmHeight;
if(edit.GetLineCount <= noOfVisibleLines)
{
long lwStyle =::GetWindowLong(edit.GetSafeHwnd, GWL_STYLE);
if(!(lwStyle & WS_VSCROLL))
return;
int nFirstVisible = edit.GetFirstVisibleLine;
edit.LineScroll(-nFirstVisible, 0);
lwStyle &= ~WS_VSCROLL;
::SetWindowLong(edit.GetSafeHwnd, GWL_STYLE, lwStyle);
}
}
}В результате всех этих манипуляций будет создано нормально обновляемое окно редактирования.
10. Наконец, для того, чтобы при выходе за пределы видимой части окна, окно отображало полосы прокрутки, по алгоритму, описанному в пункте 8, нужно добавить к классу событие WM_CHAR и написать его обработчик, код которого приведен в листинге 5.21.
Листинг 5.21void CNotePadView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CEditView::OnChar(nChar, nRepCnt, nFlags);
UpdateViewWindow;
}11. Если запустить приложение, то будет видно, что функции редактирования при помощи сочетаний клавиш Ctrl+C, Ctrl+V, Ctrl+X и Ctrl+Z уже работают. Такое взаимодействие уже встроено в класс CEditView. Необходимо связать эти действия с соответствующими пунктами меню редактирования.
12. Из контекстного меню на имени класса CNotePadView в окне ClassView выбрать команду Add Windows Message Handler. В открывшемся окне мастера нужно найти список Class or Object to Handle и выбрать в нем строку ID_EDIT_COPY. В списке New Windows Message/Handler нужно найти строку COMMAND и дважды щелкнуть на ней мышью. На экран будет выведено окно с запросом имени функции, которое можно оставить без изменений. Эта строка будет добавлена в окно Existing Windows Message/Handler. После нажатия кнопки OK в общем окне, в коде будет создан обработчик события OnEditCopy, связанный с соответствующим пунктом меню.
13. Такие же действия нужно выполнить с идентификаторами ID_EDIT_CUT, ID_ EDIT_PASTE и ID_EDIT_UNDO.
14. Написать код обработчиков этих событий, который приведен в листинге 5.22.
Листинг 5.22void CNotePadView::OnEditCopy
{
CEditView::OnEditCopy;
UpdateViewWindow;
}
void CNotePadView::OnEditCut
{
CEditView::OnEditCut;
UpdateViewWindow;
}
void CNotePadView::OnEditPaste
{
CEditView::OnEditPaste;
UpdateViewWindow;
}
void CNotePadView::OnEditUndo
{
CEditView::OnEditUndo;
UpdateViewWindow;
}Теперь можно запустить приложение и убедиться, что соответствующие пункты меню работают нормально.
15. Теперь нужно в списке файлов отображать только файлы с определенным расширением (в нашем случае это файлы с расширением. txt). Для этого на имени класса CNotePadApp в окне ClassView надо сделать двойной щелчок, найти в раскрывшемся дереве членов класса метод OnInitInstance и двойным щелчком на нем открыть в редакторе реализацию этого метода. Затем нужно найти вызов конструктора шаблона документа pDocTemplate = new CCeDocList-DocTemplate и переписать так, как показано в листинге 5.23.
Листинг 5.23pDocTemplate = new CCeDocListDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CNotePadDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CNotePadView),
CString(_T(«Text Files|*.txt||»)));16. Но и это еще не все. Необходимо сделать так, чтобы отображаемые в списке файлы открывались в редакторе при двойном щелчке на их имени. Для этого нужно открыть в окне класс CNotePadDoc, найти метод Serialize(CArchive& ar) и заменить код его реализации следующей строкой:
((CEditView*)m_viewList.GetHead)->SerializeRaw(ar);
Больше ничего делать не нужно! Сериализация в MFC – страшная сила. Одна строка позволяет приложению сохранять и открывать нужный файл правильным образом.
Можно было бы еще многое сделать с этим приложением, но цель упражнения уже достигнута. Мы ознакомились с принципом работы мастеров, при помощи которых создаются методы, обработчики и другие элементы класса. Об MFC написано достаточно много толстых томов, и при всем желании я бы не смог уместить даже краткую справочную информацию в формат данной книги.
Развитие функциональности приложения NotePad можно увидеть в примере, размещенном в каталоге C: \Program Files\Windows CE Tools\wce420\POCKET PC 2003\ Samples\Mfc\Npp. Рассмотрев код примеров, можно достаточно быстро освоить эту странную технологию. Некоторые аспекты работы приложений с ее помощью делаются очень громоздко, а некоторые – очень легко. Часть структуры классов понятна интуитивно, а какие-то аспекты без долгого чтения справочной литературы никак не понять. Тем не менее, если бы пришлось создавать такое приложение без использования MFC, кода пришлось бы писать намного больше.
Следует помнить, что при использовании MFC не нужно игнорировать работу мастеров и менять структуру приложения вручную. Поскольку на каждом этапе своей работы мастер вносит изменения в несколько файлов сразу, такая попытка может привести к полной потере работоспособности приложения.Глава 6 NET Compact Framework и разработка программ для Pocket PC в Microsoft Visual Studio.NET 2003
Не покривлю душой, если скажу, что мы переходим к одной из самых интересных частей книги. На самом деле, еще совсем недавно технология. NET вызывала у меня вполне законные опасения. Уж очень это все было похоже на Java, только выглядело менее надежно и более громоздко. Все признаки были налицо. Язык C# оказался просто лингвистическим двойником Java, приложение компилировалось в промежуточный код, а исполнялось средой выполнения. Оказалось, что на самом деле все не так просто. Промежуточный код компилируется в исполняемый код того процессора, на котором запускается приложение, а среда исполнения не является виртуальной машиной, интерпретирующей промежуточный код, она, скорее, похожа на специфический отладчик. Зато средства разработки для. NET просты в использовании, язык C# сильно отличается от Microsoft Visual C++ в лучшую сторону, а программисты на Visual Basic могут перейти к программированию на Visual Basic.NET практически без усилий.