Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Подготовка буфера для хранения данных




Как мы знаем, документ предназначен для хранения данных, отображаемых в объекте вида. Исходя из этого, мы сейчас выделим в документе буфер для хранения введенных символов.

Каждый новый символ, вводимый пользователем, добавляется к строке, хранящейся в объекте класса MFC CString. Эта строка отображается в объекте вида (с помощью метода OnDraw()). Мы назовем ее StringDataи объявим среди других переменных документа в заголовочном файле keystrokesDoc.h:

// keystrokesDoc.h: интерфейс класса CKeystrokesDoc

class CKeystrokesDoc: public CDocument

{

protected: // создание только при сериализации

        CKeystrokesDoc();

        DECLARE_DYNCREATE(CKeystrokesDoc)

         CString StringData;

}

Затем объект необходимо проинициализировать пустой строкой " ". Это делается в конструкторе объекта документа, расположенном в файлеkeystrokesDoc.cpp:

CKeystrokesDoc::CKeystrokesDoc()

{

//TODO: добавьте код конструктора

StringData = " ";

}

Буфер для хранения данных готов. Теперь нужно сделать так, чтобы каждый символ, вводимый пользователем, заносился в переменную StringData.

 Чтение нажатых клавиш

Мы подготовили место для хранения символов, вводимых пользователем, но как узнать, какая клавиша была нажата? При каждом нажатии клавиши Windows посылает сообщение WM_CHAR, которое мы свяжем с методом OnChar() объекта вида. Для этого мы воспользуемся услугамиVisual C++ ClassWizard.

ПРИМЕЧАНИЕ: Во время сеанса работы с Windows может быть открыто несколько окон, однако лишь одно из них будет реагировать на сообщения от клавиатуры. Если окно в данный момент активно и получает сообщения от клавиатуры, говорят, что оно имеет фокус.

Чтобы запустить мастер ClassWizard, выполните командуView \ClassWizard. На экране появляется окно ClassWizard. Проверьте, чтобы была выбрана вкладка Message Maps— на ней мастер связывает сообщения Windows с программой и использует для этого так называемуюсхему сообщений(message map).

Мы добавим новый обработчик сообщений, OnChar(), в класс вида CKeystrokesView,поэтому убедитесь, что в списке Class name выбран именно он. Нас интересует сообщение Windows WM_CHAR, которое посылается программе при нажатии клавиши пользователем. После того как метод OnChar() будет связан с сообщениемWM_CHAR, он будет вызываться каждый раз, когда пользователь введет символ. Найдитеэто сообщение в списке Messagesи дважды щелкните на нем. В спискеMember functionsнемедленно появляется метод OnChar().ClassWizard пo умолчанию присваивает имяOnChar() обработчику сообщения WM_CHAR.Обработчик сообщения WM_MOUSEMOVE по умолчанию получает имяОnMOUSEMOVE

 ПОДСКАЗКА:Кроме сообщения WM_CHAR Windows также посылает нашей программе сообщение WM_KEYDOWN при каждом нажатии клавиши и сообщение WM_KEYUP— приее отпускании.ClassWizard обрабатывает эти сообщения в методахOnKeyDown()и OnKeyUp().

Найдите метод OnChar() в файле keystrokesView.cpp:

        void CKeystrokesView::OnChar(UINT nChar. UINT nRepCnt,UINT nFlags)

{

// TODO: добавьте код обработки сообщения

// и/или вызовите обработчик по умолчанию

CView::OnChar(nChar, nRepCnt, nFlags);

}

ПОДСКАЗКА: Создав новый обработчик сообщения, можно быстро перейти к его коду — для этого дважды щелкните на его имени в спискеMember functions.

Созданный метод будет вызываться при вводе символа с клавиатуры. Обратите внимание: ClassWizard автоматически включил в него код для вызова метода OnChar() базового класса (для CKeystrokeView базовым является класс MFC с именем CView). Эта ситуация характерна для обработчиков сгенерированных ClassWizard, — в них присутствует вызов обработчика сообщения из базового класса на случай, если мы захотим возложить обработку сообщения на базовый класс вместо того, чтобы писать собственный код.

Фактическое значение символа передается в параметре nChar. Если пользователь не отпускает клавишу что приводит к автоматической генерации нажатий, то количество нажатий данной клавиши будет передано в параметре nRepCnt. Отдельные биты параметра nFlagsимеют следующие значения:

Бит состояния перехода равен 1, если клавиша была отпущена, и 0, если она была нажата. Бит предыдущего состояния равен 1, если клавиша была ранее нажата, и 0, если она была отпущена. Код контекста равен 1, если нажата клавиша Alt.

ПОДСКАЗКА: Если пользователь не отпускает клавишу и клавиатура посылает повторяющиеся нажатия, параметр предыдущего состояния в OnChar() будет равен 1.

Теперь нужно позаботиться о сохранении введенного символа.

Сохранение символа в документе

Введенный символ находится в параметре nChar, и его необходимо сохранить в строковом объекте StringData. Этот объект принадлежит документу, поэтому сначала мы должны получить указатель на объект документаpDoc. Это делается так:

void CKeystrokesView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

// TODO: добавьте код обработки сообщения   

 // и/или вызовите обработчик по умолчанию      

 CKeystrokesDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);  

}

Обратите внимание на макрос ASSERT_VALID. Как и прежде, он помогает Visual C++ проверить, что полученный указатель действительно ссылается на pDoc, в противном случае будет сгенерирована ошибка.

Далее мы добавляем к строке StrlngData символ nChar. Это проще простого: мы просто складываем символ со строкой (обратите внимание на использование оператора -> для обращения к объекту StringData документа, на который ссылается pDoc):

void CKeystrokesView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

// TOOO: добавьте код обработки сообщения

// и/или вызовите обработчик по умолчанию

   CKeystrokesDoc* pDoc = GetDocument();

        ASSERT_VALID(pDoc);

        pDoc->StringData += nChar;

}

Мы воспользовались сокращенным оператором C++ +=. На самом деле наша строка эквивалентна следующей:

pDoc->StringData = pDoc->StringData + nChar;

ПОДСКАЗКА: Помимо оператора +=, в C++ имеются и другие сокращенные операторы: *=, /= и т. д.

Введенный символ добавлен к текстовой строке. Теперь нужно позаботиться о выводе обновленной строки в клиентской области.

Отображение текста

Вывод данных в нашем приложении будет выполняться там же, где он выполняется и в других приложениях, сгенерированных AppWizard, — в методе OnDraw().

ПОДСКАЗКА: На самом деле текст можно было вывести прямо из метода OnChar(), но все же желательно сделать это в OnDraw(). Если наше окно будет перерисовано или появится из-под другого окна, то для перерисовки и восстановления изображения программа вызовет OnDraw(), а не OnChar().

Чтобы заставить программу вызвать OnDraw() и перерисовать обновленную строку (вскоре мы добавим в OnDraw() соответствующий код), мы вызовем метод Invalidate()объекта вида:

void CKeystrokesView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

// TODO: добавьте код обработки сообщения

// и/или вызовите обработчик по умолчанию

CKeystrokesDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

pDoc->StringData += nChar;

 Invalidate();

CView::OnChar(nChar, nRepCnt, nFlags);

}

Этот метод заставляет программу перерисовать объект вида методом OnDraw(), поэтому теперь перейдите к методу On0raw():

void CKeystrokesView::OnDraw(CDC* pDC)

{

CKeystrokesDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

// TODO: добавьте код для отображения данных

 }

ПОДСКАЗКА:Вы можете воспользоваться Invalidate() для того, чтобы объявить недействительной лишь некоторую часть вида — в этом случае программа перерисует только ее.

Все, что нам нужно, — вывести текстовую строку. Для этой цели мы воспользуемся методом TextOut():

void CKeystrokesView::OnDraw(CDC* pDC)

{

CKeystrokesDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

pDC->TextOut(0, 0, pDoc->StringData);

}

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

Мы научились получать символы и отображать их, но пока что делали это самым простым способом, начиная с левого верхнего угла клиентской области. Конечно, можно придумать что-нибудь поинтереснее: давайте посмотрим, как вывести текст в центре клиентской области.

Вывод текста в центре окна

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

Чтобы выровнять текст по центру клиентской области, нужно определить два размера: клиентской области и нашей текстовой строки на экране.

Для начала создайте новую однодокументную (SDI) программу и назовите ее centered. Мы будем получать символы с клавиатуры, как это делалось в прошлом примере. Создайте в документе строковый объект с именем StringData:

// centeredDoc.h : интерфейс класса CCenteredDoc

class CCenteredDoc: public CDocument

 {

protected: // создание только  при сериализации

 CCenteredDoc();

DECLARE_DYNCREATE(CCenteredDoc)

CString StringData;

Затем объект StringData необходимо инициализировать:

CCenteredDoc::CCenteredDoc()

 {

StringData = "";

// TODO: добавьте код конструктора

}

Воспользуйтесь ClassWizard и добавьте метод OnChar() в класс вида программы centered, CCenteredView:

void CCenteredView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

 {

// TODO: добавьте код обработки сообщения

// и/или вызовите обработчик по умолчанию

CCenteredDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

CView::OnChar(nChar, nRepCnt, nFlags);

}

Наконец, добавьте код для сохранения введенных символов:

void CCenteredView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {

// TODO: добавьте код обработки сообщения

// и/или вызовите обработчик по умолчанию

CCenteredDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

pDoc->StringData += nChar;

Invalidate();

CView::OnChar(nChar, nRepCnt, nFlags);  

}

Когда пользователь вводит символ и тот сохраняется программой, обновленную строку необходимо вывести на экран. Именно этим мы сейчасзаймемся.

 Определение размеров окна

Текст выводится в методе OnDraw(), который в данный момент выглядит так:

void CKeystrokesView::OnDraw(CDC* pDC)

{

CKeystrokesDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

// TODO: добавьте код для отображения данных

}

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

Цля получения размеров клиентской области можно воспользоваться методом GetWindowRect() класса CWnd(наш класс вида, CCenteredView, является производным от класса MFC CView, который, в свою очередь, порожден от базового класса окна MFC, CWnd). Чтобы получить размеры вида, нужно передать методу GetWindowRect() указатель на объект класса CRect, который используется для хранения размеров прямоугольника; в нашем случае этим прямоугольником будет клиентская область.

Мы создаем объект класса CRect с именем rectи передаем указатель на него методу GetWindowRect() с помощью оператора C++ &:

void CCenteredView::OnDraw(CDC* pDC)

 {

CCenteredDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

CRect rect;

GetWindowRect(&rect);

}

ПОДСКАЗКА: Если вам захочется определить размеры всего главного окна, включая заголовок, строку состояния и т. д., воспользуйтесь в объекте вида строкой GetParent() ->GetWindowRect().Это допустимо, поскольку главное окно является родительским по отношению к виду.

Тenepь объект rectсодержит размеры клиентской области. Мы воспользуемся методами Width() иHeight() класса CRect, чтобы определить, соответственно, ширину и высоту прямоугольника. Выравнивание текста по центру начинается с того, что мы узнаем, где находится центр клиентской области, и сохраняем координаты этой точки в двух переменных, х и у:

void CCenteredView::OnDraw(CDC* pDC)

{

CCenteredDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

CRect rect;

GetWindowRect(&rect);

int x =rect.Width()/2;

int у = rect.Height()/2;

}

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

Определение размера строки

Для определения размеров строки в клиентской области мы воспользуемся методом GetTextExtent()класса CDC (вспомните, что CDC — класс контекста устройства, и что наш текст должен выводиться в этом контексте).

Методу GetText Extent () необходимо передать текстовую строку, а он вернет размеры в виде объекта класса MFC CSize. Мы назовем этот объект size:

void CCenteredView::OnDraw(CDC* pDC)

{

CCenteredDoc* pDoc == GetDocument();

ASSERT_VALID(pDoc);

CRect rect;

GetWindowRect(&rect);

int x = rect.Width()/2;

int у == rect.HeightO/2;

CSize size == pDC->GetTextExtent(pDoc->StringData);

}       

Класс CSize содержит две важные переменные, сх и су, в которых хранятся размеры строки. Зная их значения, можно выровнять строку по центру клиентской области. Это делается так:

void CGenteredView::OnOraw(COC* pDC)

 {

        CCenteredDoc* pDoc = GetDocument();

        ASSERT_VALID(pDoc);

        CRect rect;

        GetWindowRect(&rect);

        int x = rect.Width()/2;

        int у == rect.Height()/2;

        CSize size = pDC->GetTextExtent(pDoc->StringData);

        x =x + size.cx/2;

        у = y + size.cy/2;

}

ПОДСКАЗКА: Зная, как определить высоту отображаемой на экране строки вы можете самостоятельно изменить программу чтения символов и предусмотреть в ней обработку клавиши Enter. Сравните полученный символ с символом перевода строки "\r" и в случае совпадения перейдите на следующую строку, добавив ее высоту к переменной у.

Остается лишь вывести текстовую строку по новым координатам (x, у). Для этого мы воспользуемся знакомым нам методом TextOut():

void CCenteredView::OnDraw(CDC* pDC)

{

        CCenteredDoc* pDoc = GetDocument();

        ASSERT_VALID(pDoc);

        CRect rect;

        GetWindowRect(&rect);

        int x = rect.Width()/2;

        int у = rect.Height()/2;

        CSize size = pDC->GetTextExtent(pDoc->StringData);

        x = x + size.cx/2;

        у = y+ size.cy/2;

        pDC->TextOut(x, y, pDoc->StringData);

 }

 Запустите программу и введите с клавиатуры какой-нибудь текст. Он автоматически выравнивается по центру клиентской области. Мы научились размещать текст в окне так, как нам хочется, и там, где нам хочется.

Создание курсора в окне

В предыдущем разделе мы познакомились с обработкой сообщений Windows и организовали в своей программе ввод символов с клавиатуры. В этом разделе мы продолжим изучение сообщений Windows, только на этот раз они будут поступать от другого источника — мыши. Мышь может порождать несколько видов сообщений, от WM_LBUTTONDOWN (при нажатии левой кнопки) до WM_МОUSEМОVЕ (при перемещении мыши).

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

С другой стороны, возникает вопрос: как пометить выбранную точку? чтобы пользователь знал, где появится текст? Для этого в Windows обычно используется курсор, также называемый кареткой, — мигающая вертикальная линия, обозначающая положение следующего вводимого символа. Так как мы собираемся разрешить пользователю самостоятельно выбирать расположение текста в окне, придется выделить немного времени на то, чтобы научиться создавать курсор и работать с ним.

Давайте посмотрим, как нарисовать курсор в объекте вида Visual C++ н организовать работу с ним в программе. Начнем с программы, которая будет создавать курсор в окне и перемещать его по мере ввода текста. Затем мы перейдем к работе с мышью и сделаем так, чтобы пользователь смог разместить свой текст в произвольном месте вида.

Первый пример покажет нам, как работать с курсором. Мы расположим курсор в левом верхнем углу клиентской области.

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

Посмотрим, как это делается. С помощью AppWizard создайте однодокументную (SDI) программу с именем carets. Сначала необходимо создать в заголовочном файле документа объект StringDataдля хранения вводимого текста:

class CCaretsDoc: public CDocument

{

protected: // создание только при сериализации

 CCaretsDoc();

DECLARE_DYNCREATE(CCaretsDoc)

// Реализация

virtual ~CCaretsDoc();

CString StringData;

}

В конструкторе документа присвоим этому объекту пустую строку:

CCaretsDoc::CCaretsDoc()

{

StringData = " ";

// TODO: добавьте код конструктора

}

Воспользуйтесь ClassWizard и свяжите сообщение Windows WM_CHAR с методом OnChar() объекта вида. Как и в предыдущем разделе, для сохранения введенных символов мы добавим в него следующий фрагмент кода:

void CCaretsView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

        CCaretsDoc* pDoc = GetDocument():

        ASSERT_VALID(pDoc);

        pDoc->StringData += nChar;

        Invalidate();

        CView::OnChar(nChar, nRepCnt. nFlags);

}

Теперь можно приступать к созданию курсора в объекте вида.

Чтобы создать курсор, необходимо выбрать его размер (курсоры не имеют стандартных размеров), а для этого нужно знать кое-что о тексте, с которым мы работаем. Обычно высота курсора совпадает с высотой символов текущего шрифта, а его ширина равна 1/8 средней ширины символов. Для определения высоты и ширины символов мы воспользуемся методом GetTextMetrics() класса CDC (вспомни те, что класс CDC предназначен для работы с контекстом устройства).










Последнее изменение этой страницы: 2018-04-12; просмотров: 372.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...