Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
227-256.doc
Скачиваний:
2
Добавлен:
11.11.2019
Размер:
339.46 Кб
Скачать

Задание 2. Реализация обработчика для команды выбора атрибутов шрифта

В предыдущем задании в класс документа мы добавили обработчик командного сообщения CTextDemoDoc::OnOptionsFont().Теперь в функцию CTextDemoDoc::OnOptionsFont() необходимо добавить соответствующий код, с помощью которого будут выполнены такие действия:

  • отображение стандартного диалогового окна Font.

  • передача в функцию CreateFontIndirect() класса CFont описания шрифта для инициализации объекта шрифта.

  • запись описания шрифта в массив строк.

  • создание объекта контекста устройства и выбор в нем объекта шрифта.

  • вызов функции CDC::GetTextMetrics() объекта контекста устройства для получения атрибутов активного шрифта устройства. Функция CDC::GetTextMetrics() копирует эту информацию в структуру ТEXTMETRIC.

  • запись информации об атрибутах активного шрифта в массив строк.

  • вызов функции CDocument::UpDateAllViews() для отображения функцией CTextDemoView::OnDraw()строк текста, содержащихся в массиве строк, с использованием нового шрифта.

Для решения поставленных задач выполните следующие действия.

  1. В класс документа добавьте переменную-член m_LineTable для сохранения массива объектов CString, который будет использоваться для хранения отображаемых в окне представления строк текста. Можно использовать мастер добавления переменных. Для этого в окне Class View вызовите контекстное меню для класса CTextDemoDoc, выполните команду AddAdd Variable…. В окне Add Member Variable Wizard в поле Access оставьте значение public, в поле Variable typе введите CString [NUMLINES], в поле Variable name — имя переменной m_LineTable. Нажмите кнопку Finish. Процесс добавления переменной с помощью диалогового окна показан на рис. 8.8.

Рис. 8.8. Окно Add Member Variable Wizard в процессе добавления переменной-члена m_LineTable

  1. В класс документа добавьте такие переменные-члены: m_Color типа COLORREF для выбора цвета шрифта, m_Font типа CFont для хранения свойств объекта шрифта. Придобавлении переменной m_Color в диалоговом окне Add Member Variable Wizard в поле Variable type укажите тип COLORREF, в поле Variable name введите имя переменной m_Color, в поле Access оставьте значение public. В файл TextDemoDoc.h в класс СTextDemoDoc будут добавлены объявления, показанные полужирным шрифтом во фрагменте кода. Обратите внимание: объявление переменной m_LineTable должно предшествовать объявлению переменной m_Font и размещаться после объявления переменной m_Color. В противном случае возможна ошибка, связвнная с нарушением правил доступа (Access violation reading location).

// TextDemoDoc.h : interface of the CTextDemoDoc class #pragma once #include "afxwin.h" const int NUMLINES = 42;//Число строк, сохраненных в документе и // отображаемых в окне представления class CTextDemoDoc : public CDocument { protected: // create from serialization only CTextDemoDoc(); DECLARE_DYNCREATE(CTextDemoDoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); // Implementation public: virtual ~CTextDemoDoc(); virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; // Generated message map functions protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnOptionsFont(); //обработчик команды Font COLORREF m_Color; //цвет шрифта CString m_LineTable[NUMLINES]; //массив строк, выводимых в окно CFont m_Font; //объект шрифта };

  1. В файл TextDemoDoc.cpp в функцию CTextDemoDoc::OnOptionsFont() добавьте код, определяющий объект стандартного диалогового окна Font, используя конструктор класса CFontDialog. Для отображения диалогового окна вызовите функцию CFontDialog::DoModal(). Укажите выход из функции CTextDemoDoc::OnOptionsFont() при случае возврата функцией DoModal() значения, не равного IDOK (т.е. при нажатии кнопки Cancel). В окне редактора кода введите код, представленный ниже полужирным шрифтом.

void CTextDemoDoc::OnOptionsFont() { // TODO: Add your command handler code here // отобразите диалоговое окно Font: CFontDialog FontDialog; if (FontDialog.DoModal() != IDOK) return; }

  1. Функция CTextDemoDoc::OnOptionsFont() обращается к переменным класса CFontDialog для получения информации о выбранном шрифте. Добавьте код определения значения переменной m_Color. Для этого функцию CFontDialog::GetColor(). При этом указанное значение сохраняется в переменной CTextDemoDoc::m_Color, используемой функцией CTextDemoView::OnDraw() для установки цвета текста. Добавьте также код инициализации объекта шрифта с помощью функций CGdiObject::DeleteObject() и CFont::CreateFontIndirect(). Напомним, что обращение к функции CGdiObject::DeleteObject() удаляет существующую информацию о шрифте из объекта шрифта. Передача указателя на структуру LOGFONT в функцию CFont::CreateFontIndirect() инициализирует объект шрифта описанием вновь выбранного шрифта. Добавленный код выделен полужирным шрифтом.

void CTextDemoDoc::OnOptionsFont() { // TODO: Add your command handler code here // отобразите диалоговое окно Font: CFontDialog FontDialog; if (FontDialog.DoModal() != IDOK) return; // установите значение m_Color: m_Color = FontDialog.GetColor(); // получите цвет, выбранный // пользователем // Инициализируйте объект шрифта: m_Font.DeleteObject(); m_Font.CreateFontIndirect(&FontDialog.m_lf); }

  1. В функции CTextDemoDoc::OnOptionsFont() сформируем массив m_LineTable объектов CString для хранения строк, выводимых в окне представления, которые содержат описание выбранного шрифта, например, имя гарнитуры, размер, высоту символов, толщину шрифта и пр. свойства. Для индексации элементов массива введите локальную переменную Num типа int. Инициализируйте эту переменную нулевым значением. Вызовите функцию CFontDialog::GetFaceName() для получения названия шрифта и функцию CFongDialog::GetSize() для получения размера шрифта в процессе выбора в списках Font и Size диалогового окна Font. Поскольку функция CFongDialog::GetSize() возвращает значение типа int, а в массив m_LineTable можно записать значения типа CString, то для преобразования данных из типа int в тип CString введите дополнительную локальную переменную str типа CString. Преобразование типов выполните функцией CString::Format(). Не забудьте, что размер шрифта возвращается в десятых частях пунктов. Добавленный код отображен в примере полужирным шрифтом.

void CTextDemoDoc::OnOptionsFont() { // TODO: Add your command handler code her CString str; //переменная для хранения преобразованных в тип //CString значений int Num = 0; //индекс строк текста // отобразите диалоговое окно Font: CFontDialog FontDialog; if (FontDialog.DoModal () != IDOK) return; // установите значение m_Color: m_Color = FontDialog.GetColor ();// получите цвет, выбранный // пользователем // Инициализируйте объект шрифта: m_Font.DeleteObject (); m_Font.CreateFontIndirect (&FontDialog.m_lf); // сохраните значения, выбранные пользователем: m_LineTable[Num++] = "Font Name: " + FontDialog.GetFaceName(); m_LineTable [Num] = "Font Size: "; str.Format("%d.%d points", //преобразование к типу CString FontDialog.GetSize () / 10, FontDialog.GetSize () % 10); m_LineTable [Num++] += str; //занесение в массив строк m_LineTable [Num++] = ""; //пустая строка }

  1. Атрибуты шрифта хранятся в структуре LOGFONT. Функция CTextDemoDoc::OnOptionsFont() записывает значение каждого поля структуры LOGFONT в строку массива m_LineTable, и они становятся доступными для отображения в окне представления. Для доступа к полям структуры LOGFONT используйте переменную-член FontDialog.m_lf, где FontDialog — объект класса CFontDialog. В функцию CTextDemoDoc::OnOptionsFont() добавьте операторы сохранения значений полей структуры LOGFONT. Добавленный фрагмент кода представлен полужирным шрифтом ниже.

void CTextDemoDoc::OnOptionsFont() { // TODO: Add your command handler code her CString str; //переменная для хранения значений, // преобразованных в тип CString int Num = 0; //индекс строк текста // отобразите диалоговое окно Font: CFontDialog FontDialog; if (FontDialog.DoModal () != IDOK) return; // установите значение m_Color: m_Color = FontDialog.GetColor(); //получите цвета, выбранные //пользователем // Инициализируйте объект шрифта: m_Font.DeleteObject (); m_Font.CreateFontIndirect (&FontDialog.m_lf); // сохраните значения, выбранные пользователем: m_LineTable[Num++] = "Font Name: " + FontDialog.GetFaceName(); m_LineTable [Num] = "Font Size: "; str.Format("%d.%d points", //преобразование к типу CString FontDialog.GetSize () / 10, FontDialog.GetSize () % 10); m_LineTable [Num++] += str;//занесение в массив строк m_LineTable [Num++] = ""; //пустая строка // сохраните значения полей структуры LOGFONT: m_LineTable [Num++] = "LOGFONT fields:"; m_LineTable [Num] = "lfHeight: "; str.Format("%d",FontDialog.m_lf.lfHeight); m_LineTable [Num++] +=str; m_LineTable [Num] = "lfWidth: "; str.Format("%d",FontDialog.m_lf.lfWidth); m_LineTable [Num++] += str; m_LineTable [Num] = "lfEscapement: "; str.Format("%d",FontDialog.m_lf.lfEscapement); m_LineTable [Num] += str; m_LineTable [Num++] += " (tenths of a degree)"; m_LineTable [Num] = "lfOrientation: "; str.Format("%d",FontDialog.m_lf.lfOrientation); m_LineTable [Num] += str; m_LineTable [Num++] += " (tenths of a degree)"; m_LineTable [Num] = "lfWeight: "; str.Format("%d",FontDialog.m_lf.lfWeight); m_LineTable [Num++] += str; m_LineTable [Num] = "lfItalic: "; str.Format("%d",FontDialog.m_lf.lfItalic); m_LineTable [Num++] += str; m_LineTable [Num] = "lfUnderline: "; str.Format("%d",FontDialog.m_lf.lfUnderline); m_LineTable [Num++] += str; m_LineTable [Num] = "lfStrikeOut: "; str.Format("%d",FontDialog.m_lf.lfStrikeOut); m_LineTable [Num++] += str; }

  1. При формировании выводимых на экран строк, содержащих данные о типе набора символов (поле lfCharSet структуры LOGFONT), степени соответствия выбранного шрифта реальному шрифту (поле lfOutPrecision структуры LOGFONT), способе усечения символов (поле lfClipPrecision структуры LOGFONT), качестве шрифта при печати (поле lfQuality структуры LOGFONT) и семействе шрифтов (поле lfPitchAndFamily структуры LOGFONT), необходимо использовать значения констант, приведенных в табл. 8.1 – 8.4. Ниже приводится код, в котором добавленные операторы выделены полужирным шрифтом, а рассмотренный выше фрагмент функции CTextDemoDoc::OnOptionsFont() не представлен в приводимом коде.

void CTextDemoDoc::OnOptionsFont() { // TODO: Add your command handler code her // код открытия диалогового окна, инициализации объекта шрифта // и пр. см. в п. 6 m_LineTable [Num] = "lfStrikeOut: "; str.Format("%d",FontDialog.m_lf.lfStrikeOut); m_LineTable [Num++] += str; m_LineTable [Num] = "lfCharSet: "; switch (FontDialog.m_lf.lfCharSet) { case ANSI_CHARSET: m_LineTable [Num++] += "ANSI_CHARSET"; break; case OEM_CHARSET: m_LineTable [Num++] += "OEM_CHARSET"; break; case SYMBOL_CHARSET: m_LineTable [Num++] += "SYMBOL_CHARSET"; break; default: m_LineTable [Num++] += "unspecified character set"; break; } m_LineTable [Num] = "lfOutPrecision: "; switch (FontDialog.m_lf.lfOutPrecision) { case OUT_CHARACTER_PRECIS: m_LineTable [Num++] += "OUT_CHARACTER_PRECIS"; break; case OUT_DEFAULT_PRECIS: m_LineTable [Num++] += "OUT_DEFAULT_PRECIS"; break; case OUT_STRING_PRECIS: m_LineTable [Num++] += "OUT_STRING_PRECIS"; break; case OUT_STROKE_PRECIS: m_LineTable [Num++] += "OUT_STROKE_PRECIS"; break; default: m_LineTable [Num++] += "unspecified output precision"; break; } m_LineTable [Num] = "lfClipPrecision: "; switch (FontDialog.m_lf.lfClipPrecision) { case CLIP_CHARACTER_PRECIS: m_LineTable [Num++] += "CLIP_CHARACTER_PRECIS"; break; case CLIP_DEFAULT_PRECIS: m_LineTable [Num++] += "CLIP_DEFAULT_PRECIS"; break; case CLIP_STROKE_PRECIS: m_LineTable [Num++] += "CLIP_STROKE_PRECIS"; break; default: m_LineTable [Num++]+="unspecified clipping precision"; break; } m_LineTable [Num] = "lfQuality: "; switch (FontDialog.m_lf.lfQuality) { case DEFAULT_QUALITY: m_LineTable [Num++] += "DEFAULT_QUALITY"; break; case DRAFT_QUALITY: m_LineTable [Num++] += "DRAFT_QUALITY"; break; case PROOF_QUALITY: m_LineTable [Num++] += "PROOF_QUALITY"; break; default: m_LineTable [Num++] += "unspecified output quality"; break; } m_LineTable [Num] = "lfPitchAndFamily: "; switch (FontDialog.m_lf.lfPitchAndFamily & 0x0003) { case DEFAULT_PITCH: m_LineTable [Num] += "DEFAULT_PITCH; "; break; case FIXED_PITCH: m_LineTable [Num] += "FIXED_PITCH; "; break; case VARIABLE_PITCH: m_LineTable [Num] += "VARIABLE_PITCH; "; break; default: m_LineTable [Num] += "unspecified pitch; "; break; } switch (FontDialog.m_lf.lfPitchAndFamily & 0x00F0) { case FF_DECORATIVE: m_LineTable [Num++] += "FF_DECORATIVE"; break; case FF_DONTCARE: m_LineTable [Num++] += "FF_DONTCARE"; break; case FF_MODERN: m_LineTable [Num++] += "FF_MODERN"; break; case FF_ROMAN: m_LineTable [Num++] += "FF_ROMAN"; break; case FF_SCRIPT: m_LineTable [Num++] += "FF_SCRIPT"; break; case FF_SWISS: m_LineTable [Num++] += "FF_SWISS"; break; default: m_LineTable [Num++] += "unspecified family"; break; } m_LineTable [Num] = "lfFaceName: "; m_LineTable [Num++] += FontDialog.m_lf.lfFaceName; m_LineTable [Num++] = ""; }

  1. Для получения информации о шрифте, который доступен для любого устройства вывода и более всего близок к описанию, функция CTextDemoDoc::OnOptionsFont() выбирает объект шрифта из объекта контекста устройства и вызывает функцию CDC::GetTextMetrics(). Затем функция OnOptionsFont() класса CTextDemoDoc записывает содержимое каждого поля структуры TEXTMETRIC в переменную m_LineTable. Структуры LOGFONT и TEXTMETRIC похожи и отображаются средствами программы TextDemo почти аналогично. Добавьте следующий код после операторов, сохраняющих значения полей структуры LOGFONT в переменной m_LineTable.

void CTextDemoDoc::OnOptionsFont() { // TODO: Add your command handler code her //операторы открытия диалогового окна, инициализации объекта //шрифта и пр. здесь не приводятся, см. в п. 6 m_LineTable [Num] = "lfFaceName: "; m_LineTable [Num++] += FontDialog.m_lf.lfFaceName; m_LineTable [Num++] = ""; // создайте объект контекста устройства, связанный с окном представления: POSITION Pos = GetFirstViewPosition (); CView *PView = GetNextView (Pos); CClientDC ClientDC (PView); // выберите новый шрифт в объект контекста устройства: ClientDC.SelectObject (&m_Font); TEXTMETRIC TM; ClientDC.GetTextMetrics (&TM); // сохраните значения полей структуры TEXTMETRIC: m_LineTable [Num++] = "TEXTMETRIC fields:"; m_LineTable [Num] = "tmHeight: "; str.Format("%d",TM.tmHeight); m_LineTable [Num++] += str; m_LineTable [Num] = "tmAscent: "; str.Format("%d",TM.tmAscent); m_LineTable [Num++] += str; m_LineTable [Num] = "tmDescent: "; str.Format("%d",TM.tmDescent); m_LineTable [Num++] += str; m_LineTable [Num] = "tmInternalLeading: "; str.Format("%d",TM.tmInternalLeading); m_LineTable [Num++] += str; m_LineTable [Num] = "tmExternalLeading: "; str.Format("%d",TM.tmExternalLeading); m_LineTable [Num++] += str; m_LineTable [Num] = "tmAveCharWidth: "; str.Format("%d",TM.tmAveCharWidth); m_LineTable [Num++] += str; m_LineTable [Num] = "tmMaxCharWidth: "; str.Format("%d",TM.tmMaxCharWidth); m_LineTable [Num++] += str; m_LineTable [Num] = "tmWeight: "; str.Format("%d",TM.tmWeight); m_LineTable [Num++] += str; m_LineTable [Num] = "tmOverhang: "; str.Format("%d",TM.tmOverhang); m_LineTable [Num++] += str; m_LineTable [Num] = "tmDigitizedAspectX: "; str.Format("%d",TM.tmDigitizedAspectX); m_LineTable [Num++] += str; m_LineTable [Num] = "tmDigitizedAspectY: "; str.Format("%d",TM.tmDigitizedAspectY); m_LineTable [Num++] += str; m_LineTable [Num] = "tmFirstChar: "; str.Format("%d",TM.tmFirstChar); m_LineTable [Num++] += str; m_LineTable [Num] = "tmLastChar: "; str.Format("%d",TM.tmLastChar); m_LineTable [Num++] += str; m_LineTable [Num] = "tmDefaultChar: "; str.Format("%d",TM.tmDefaultChar); m_LineTable [Num++] += str; m_LineTable [Num] = "tmBreakChar: "; str.Format("%d",TM.tmBreakChar); m_LineTable [Num++] += str; m_LineTable [Num] = "tmItalic: "; str.Format("%d",TM.tmItalic); m_LineTable [Num++] += str; m_LineTable [Num] = "tmUnderlined: "; str.Format("%d",TM.tmUnderlined); m_LineTable [Num++] += str; m_LineTable [Num] = "tmStruckOut: "; str.Format("%d",TM.tmStruckOut); m_LineTable [Num++] += str; m_LineTable [Num++] = "tmPitchAndFamily: "; m_LineTable [Num] = " Pitch Info: "; if (TM.tmPitchAndFamily & TMPF_FIXED_PITCH) m_LineTable [Num] += "variable pitch "; else m_LineTable [Num] += "fixed pitch "; if (TM.tmPitchAndFamily & TMPF_VECTOR) m_LineTable [Num] += "vector font "; if (TM.tmPitchAndFamily & TMPF_TRUETYPE) m_LineTable [Num] += "TrueType font "; if (TM.tmPitchAndFamily & TMPF_DEVICE) m_LineTable [Num] += "device font"; Num++; m_LineTable [Num] = " Family: "; switch (TM.tmPitchAndFamily & 0x00F0) { case FF_DECORATIVE: m_LineTable [Num++] += "FF_DECORATIVE"; break; case FF_DONTCARE: m_LineTable [Num++] += "FF_DONTCARE"; break; case FF_MODERN: m_LineTable [Num++] += "FF_MODERN"; break; case FF_ROMAN: m_LineTable [Num++] += "FF_ROMAN"; break; case FF_SCRIPT: m_LineTable [Num++] += "FF_SCRIPT"; break; case FF_SWISS: m_LineTable [Num++] += "FF_SWISS"; break; default: m_LineTable [Num++] += "unknown family"; break; } m_LineTable [Num] = "tmCharSet: "; switch (TM.tmCharSet) { case ANSI_CHARSET: m_LineTable [Num++] += "ANSI_CHARSET"; break; case OEM_CHARSET: m_LineTable [Num++] += "OEM_CHARSET"; break; case SYMBOL_CHARSET: m_LineTable [Num++] += "SYMBOL_CHARSET"; break; default: m_LineTable [Num++] += "unknown character set"; break; }

  1. Для обновления представлений в случае изменения документа вызывается функция CDocument::UpdateAllViews(). Добавьте в функцию CTextDemoDoc::OnOptionsFont() оператор вызова функции CDocument::UpdateAllViews() после окончания формирования массива m_LineTable. Вызов функции CDocument::UpdateAllViews(NULL) будет последним оператором в функции OnOptionsFont().

  2. Сохраните программу, постройте и запустите ее. Исправьте синтаксические ошибки в случае их наличия.

После запуска программы выполните команду OptionsFont…. Откроется диалоговое окно Font, однако выбор атрибутов шрифта после закрытия диалогового окна щелчком на кнопке OK не приведет к отображению текста, который вы формировали в массиве m_LineTable. Это связано с отсутствием кода для отображения текста в окне представления. Для выполнения действий, связанных с отображением текста выбранным шрифтом, вам необходимо разработать код функции CTextDemoView::OnDraw(), которая используется для вывода документа в окно представления. При создании кода этой функции необходимо использовать объекты контекста устройства и шрифта, метрики текста, определяющие размеры и другие характеристики шрифта, метод отображения текста и другие функции, обзор которых приводится в следующем параграфе.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]