Руководство. начало работы с помощью DirectWrite
В этом документе показано, как использовать DirectWrite и Direct2D для создания простого текста, содержащего один формат, а затем текста, содержащего несколько форматов.
Это руководство содержит следующие части:
Исходный код
Исходный код, показанный в этом обзоре, взят из примера DirectWrite Hello World. Каждая часть реализуется в отдельном классе (SimpleText и MultiformattedText) и отображается в отдельном дочернем окне. Каждый класс представляет окно Microsoft Win32. В дополнение к методу WndProc каждый класс содержит следующие методы:
Функция | Описание |
---|---|
CreateDeviceIndependentResources | Создает ресурсы, независимые от устройств, чтобы их можно было повторно использовать в любом месте. |
DiscardDeviceIndependentResources | Освобождает независимые от устройства ресурсы после того, как они больше не нужны. |
CreateDeviceResources | Создает ресурсы, такие как кисти и целевые объекты отрисовки, привязанные к определенному устройству. |
DiscardDeviceResources | Освобождает зависимые от устройства ресурсы после того, как они больше не нужны. |
DrawD2DContent | Использует Direct2D для отрисовки на экране. |
Drawtext | Рисует текстовую строку с помощью Direct2D. |
Onresize | Изменяет размер целевого объекта отрисовки Direct2D при изменении размера окна. |
Вы можете использовать предоставленный пример или следовать инструкциям, чтобы добавить DirectWrite и Direct2D в собственное приложение Win32. Дополнительные сведения о примере и связанных файлах проекта см. в DirectWrite HelloWorld.
Рисование простого текста
В этом разделе показано, как использовать DirectWrite и Direct2D для отрисовки простого текста в одном формате, как показано на следующем снимке экрана.
Для рисования простого текста на экране требуется четыре компонента:
- Символьная строка для отрисовки.
- Экземпляр IDWriteTextFormat.
- Размеры области, содержащей текст.
- Объект, который может отрисовыть текст. При работе с этим учебником вы используете целевой объект отрисовки Direct2D .
Интерфейс IDWriteTextFormat описывает имя семейства шрифтов, размер, вес, стиль и растяжение, используемые для форматирования текста, а также сведения о языковом стандарте. IDWriteTextFormat также определяет методы для задания и получения следующих свойств:
- Междустрочный интервал.
- Выравнивание текста относительно левого и правого краев поля макета.
- Выравнивание абзаца относительно верхней и нижней части поля макета.
- Направление чтения.
- Детализация обрезки текста для текста, который переполняет поле макета.
- Остановка добавочной вкладки.
- Направление потока абзаца.
Интерфейс IDWriteTextFormat необходим для рисования текста, в котором используются оба процесса, описанные в этом документе .
Перед созданием объекта IDWriteTextFormat или любого другого объекта DirectWrite требуется экземпляр IDWriteFactory. IdWriteFactory используется для создания экземпляров IDWriteTextFormat и других объектов DirectWrite. Чтобы получить экземпляр фабрики, используйте функцию DWriteCreateFactory .
Часть 1. Объявление ресурсов DirectWrite и Direct2D.
В этой части вы объявите объекты, которые будут использоваться позже для создания и отображения текста в качестве членов закрытых данных класса. Все интерфейсы, функции и типы данных для DirectWrite объявляются в файле заголовка dwrite.h, а интерфейсы для Direct2D — в d2d1.h; если вы еще не сделали этого, включите эти заголовки в проект.
В файле заголовка класса (SimpleText.h) объявите указатели на интерфейсы IDWriteFactory и IDWriteTextFormat в качестве закрытых элементов.
IDWriteFactory* pDWriteFactory_; IDWriteTextFormat* pTextFormat_;
Объявите элементы для хранения текстовой строки для отрисовки и длины строки.
const wchar_t* wszText_; UINT32 cTextLength_;
Объявите указатели на интерфейсы ID2D1Factory, ID2D1HwndRenderTarget и ID2D1SolidColorBrush для отрисовки текста с помощью Direct2D.
ID2D1Factory* pD2DFactory_; ID2D1HwndRenderTarget* pRT_; ID2D1SolidColorBrush* pBlackBrush_;
Часть 2. Создание независимых от устройств ресурсов.
Direct2D предоставляет два типа ресурсов: зависимые от устройства ресурсы и независимые от устройства ресурсы. Ресурсы, зависящие от устройства, связаны с устройством отрисовки и больше не работают при удалении этого устройства. Ресурсы, независимые от устройства, с другой стороны, могут длиться область приложения.
DirectWrite ресурсы не зависят от устройств.
В этом разделе вы создадите независимые от устройства ресурсы, которые используются приложением. Эти ресурсы должны быть освобождены с помощью вызова метода Release интерфейса .
Некоторые используемые ресурсы должны быть созданы только один раз и не привязаны к устройству. Инициализация этих ресурсов помещается в метод SimpleText::CreateDeviceIndependentResources , который вызывается при инициализации класса .
В методе SimpleText::CreateDeviceIndependentResources в файле реализации класса (SimpleText.cpp) вызовите функцию D2D1CreateFactory , чтобы создать интерфейс ID2D1Factory , который является интерфейсом корневой фабрики для всех объектов Direct2D . Вы используете ту же фабрику для создания экземпляров других ресурсов Direct2D.
hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory_ );
Вызовите функцию DWriteCreateFactory, чтобы создать интерфейс IDWriteFactory, который является интерфейсом корневой фабрики для всех объектов DirectWrite. Для создания экземпляров других ресурсов DirectWrite используется та же фабрика.
if (SUCCEEDED(hr)) { hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDWriteFactory_) ); }
Инициализируйте текстовую строку и сохраните ее длину.
wszText_ = L"Hello World using DirectWrite!"; cTextLength_ = (UINT32) wcslen(wszText_);
Создайте объект интерфейса IDWriteTextFormat с помощью метода IDWriteFactory::CreateTextFormat . IdWriteTextFormat указывает шрифт, вес, растяжение, стиль и языковой стандарт, которые будут использоваться для отрисовки текстовой строки.
if (SUCCEEDED(hr)) { hr = pDWriteFactory_->CreateTextFormat( L"Gabriola", // Font family name. NULL, // Font collection (NULL sets it to use the system font collection). DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 72.0f, L"en-us", &pTextFormat_ ); }
Выравнивание текста по горизонтали и вертикали путем вызова методов IDWriteTextFormat::SetTextAlignment и IDWriteTextFormat::SetParagraphAlignment .
// Center align (horizontally) the text. if (SUCCEEDED(hr)) { hr = pTextFormat_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); } if (SUCCEEDED(hr)) { hr = pTextFormat_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); }
В этой части вы инициализировали независимые от устройства ресурсы, используемые приложением. В следующей части вы инициализируете ресурсы, зависящие от устройства.
Часть 3. Создание ресурсов Device-Dependent.
В этой части вы создадите ID2D1HwndRenderTarget и ID2D1SolidColorBrush для отрисовки текста.
Целевой объект отрисовки — это объект Direct2D, который создает ресурсы рисования и отрисовывает команды рисования на устройстве отрисовки. ID2D1HwndRenderTarget — это целевой объект отрисовки, который отрисовывается в HWND.
Одним из ресурсов рисования, которые может создать целевой объект отрисовки, является кисть для рисования контуров, заливок и текста. ID2D1SolidColorBrush окрашен сплошным цветом.
Интерфейсы ID2D1HwndRenderTarget и ID2D1SolidColorBrush привязываются к устройству отрисовки при создании и должны быть освобождены и повторно созданы, если устройство становится недействительным.
В методе SimpleText::CreateDeviceResources проверка, имеет ли целевой указатель отрисовки значение NULL. Если это так, получите размер области отрисовки и создайте ID2D1HwndRenderTarget этого размера. Используйте ID2D1HwndRenderTarget для создания ID2D1SolidColorBrush.
RECT rc; GetClientRect(hwnd_, &rc); D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); if (!pRT_) { // Create a Direct2D render target. hr = pD2DFactory_->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties( hwnd_, size ), &pRT_ ); // Create a black brush. if (SUCCEEDED(hr)) { hr = pRT_->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::Black), &pBlackBrush_ ); } }
В методе SimpleText::D iscardDeviceResources отпустите кисть и целевой объект отрисовки.
SafeRelease(&pRT_); SafeRelease(&pBlackBrush_);
Теперь, когда вы создали целевой объект отрисовки и кисть, вы можете использовать их для отрисовки текста.
Часть 4. Рисование текста с помощью метода Direct2D DrawText.
В методе SimpleText::D rawText класса определите область для макета текста, извлекая размеры области отрисовки, и создайте прямоугольник Direct2D с теми же размерами.
D2D1_RECT_F layoutRect = D2D1::RectF( static_cast<FLOAT>(rc.left) / dpiScaleX_, static_cast<FLOAT>(rc.top) / dpiScaleY_, static_cast<FLOAT>(rc.right - rc.left) / dpiScaleX_, static_cast<FLOAT>(rc.bottom - rc.top) / dpiScaleY_ );
Используйте метод ID2D1RenderTarget::D rawText и объект IDWriteTextFormat для отрисовки текста на экране. Метод ID2D1RenderTarget::D rawText принимает следующие параметры:
- Строка для отрисовки.
- Указатель на интерфейс IDWriteTextFormat .
- Прямоугольник макета Direct2D .
- Указатель на интерфейс, предоставляющий id2D1Brush.
pRT_->DrawText( wszText_, // The string to render. cTextLength_, // The string's length. pTextFormat_, // The text format. layoutRect, // The region of the window where the text will be rendered. pBlackBrush_ // The brush used to draw the text. );
Часть 5. Отрисовка содержимого окна с помощью Direct2D
Чтобы отобразить содержимое окна с помощью Direct2D при получении сообщения paint, сделайте следующее:
- Создайте зависимые от устройства ресурсы, вызвав метод SimpleText::CreateDeviceResources, реализованный в части 3.
- Вызовите метод ID2D1HwndRenderTarget::BeginDraw целевого объекта отрисовки.
- Очистите целевой объект отрисовки, вызвав метод ID2D1HwndRenderTarget::Clear .
- Вызовите метод SimpleText::D rawText, реализованный в части 4.
- Вызовите метод ID2D1HwndRenderTarget::EndDraw целевого объекта отрисовки.
- При необходимости удалите зависимые от устройства ресурсы, чтобы их можно было воссоздать при перерисовки окна.
hr = CreateDeviceResources();
if (SUCCEEDED(hr))
{
pRT_->BeginDraw();
pRT_->SetTransform(D2D1::IdentityMatrix());
pRT_->Clear(D2D1::ColorF(D2D1::ColorF::White));
// Call the DrawText method of this class.
hr = DrawText();
if (SUCCEEDED(hr))
{
hr = pRT_->EndDraw(
);
}
}
if (FAILED(hr))
{
DiscardDeviceResources();
}
Класс SimpleText реализован в SimpleText.h и SimpleText.cpp.
Рисование текста в нескольких форматах.
В этом разделе показано, как использовать DirectWrite и Direct2D для отрисовки текста в нескольких форматах, как показано на следующем снимке экрана.
Код для этого раздела реализуется как класс MultiformattedText в DirectWrite HelloWorld. Он основан на шагах из предыдущего раздела.
Для создания многоформатного текста используйте интерфейс IDWriteTextLayout в дополнение к интерфейсу IDWriteTextFormat , представленному в предыдущем разделе. Интерфейс IDWriteTextLayout описывает форматирование и макет блока текста. Помимо форматирования по умолчанию, заданного объектом IDWriteTextFormat , форматирование для определенных диапазонов текста можно изменить с помощью IDWriteTextLayout. Сюда входят имя семейства шрифтов, размер, вес, стиль, растяжение, зачеркивание и подчеркивание.
IDWriteTextLayout также предоставляет методы проверки попадания. Метрики проверки попадания, возвращаемые этими методами, связаны с полем макета, указанным при создании объекта интерфейса IDWriteTextLayout с помощью метода CreateTextLayout интерфейса IDWriteFactory .
Интерфейс IDWriteTypography используется для добавления дополнительных типографических функций OpenType в текстовый макет, таких как swashes и альтернативные стилистические наборы текста. Типографические функции можно добавить в определенный диапазон текста в текстовом макете, вызвав метод AddFontFeature интерфейса IDWriteTypography . Этот метод получает структуру DWRITE_FONT_FEATURE в качестве параметра, содержащего константу перечисления DWRITE_FONT_FEATURE_TAG и параметр выполнения UINT32 . Список зарегистрированных функций OpenType можно найти в реестре тегов макета OpenType на microsoft.com. Эквивалентные константы перечисления DirectWrite см. в разделе DWRITE_FONT_FEATURE_TAG.
Часть 1. Создание интерфейса IDWriteTextLayout.
Объявите указатель на интерфейс IDWriteTextLayout в качестве члена класса MultiformattedText.
IDWriteTextLayout* pTextLayout_;
В конце метода MultiformattedText::CreateDeviceIndependentResources создайте объект интерфейса IDWriteTextLayout , вызвав метод CreateTextLayout . Интерфейс IDWriteTextLayout предоставляет дополнительные функции форматирования, такие как возможность применения различных форматов к выделенным фрагментам текста.
// Create a text layout using the text format. if (SUCCEEDED(hr)) { RECT rect; GetClientRect(hwnd_, &rect); float width = rect.right / dpiScaleX_; float height = rect.bottom / dpiScaleY_; hr = pDWriteFactory_->CreateTextLayout( wszText_, // The string to be laid out and formatted. cTextLength_, // The length of the string. pTextFormat_, // The text format to apply to the string (contains font information, etc). width, // The width of the layout box. height, // The height of the layout box. &pTextLayout_ // The IDWriteTextLayout interface pointer. ); }
Часть 2. Применение форматирования с помощью IDWriteTextLayout.
Форматирование, например размер шрифта, вес и подчеркивание, можно применять к подстрокам текста, отображаемого с помощью интерфейса IDWriteTextLayout .
Задайте размер шрифта для подстроки "Di" элемента "DirectWrite" равным 100, объявив DWRITE_TEXT_RANGE и вызвав метод IDWriteTextLayout::SetFontSize.
// Format the "DirectWrite" substring to be of font size 100. if (SUCCEEDED(hr)) { DWRITE_TEXT_RANGE textRange = {20, // Start index where "DirectWrite" appears. 6 }; // Length of the substring "Direct" in "DirectWrite". hr = pTextLayout_->SetFontSize(100.0f, textRange); }
Подчеркнуте подстроку "DirectWrite", вызвав метод IDWriteTextLayout::SetUnderline.
// Format the word "DWrite" to be underlined. if (SUCCEEDED(hr)) { DWRITE_TEXT_RANGE textRange = {20, // Start index where "DirectWrite" appears. 11 }; // Length of the substring "DirectWrite". hr = pTextLayout_->SetUnderline(TRUE, textRange); }
Задайте полужирный шрифт для подстроки "DirectWrite", вызвав метод IDWriteTextLayout::SetFontWeight.
if (SUCCEEDED(hr)) { // Format the word "DWrite" to be bold. DWRITE_TEXT_RANGE textRange = {20, 11 }; hr = pTextLayout_->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, textRange); }
Часть 3. Добавление типографических функций с помощью IDWriteTypography.
Объявите и создайте объект интерфейса IDWriteTypography , вызвав метод IDWriteFactory::CreateTypography .
// Declare a typography pointer. IDWriteTypography* pTypography = NULL; // Create a typography interface object. if (SUCCEEDED(hr)) { hr = pDWriteFactory_->CreateTypography(&pTypography); }
Добавьте функцию шрифта, объявив объект DWRITE_FONT_FEATURE с заданным стилистическим набором 7 и вызвав метод IDWriteTypography::AddFontFeature .
// Set the stylistic set. DWRITE_FONT_FEATURE fontFeature = {DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7, 1}; if (SUCCEEDED(hr)) { hr = pTypography->AddFontFeature(fontFeature); }
Задайте макет текста для использования шрифта по всей строке, объявив переменную DWRITE_TEXT_RANGE и вызвав метод IDWriteTextLayout::SetTypography и передав диапазон текста.
if (SUCCEEDED(hr)) { // Set the typography for the entire string. DWRITE_TEXT_RANGE textRange = {0, cTextLength_}; hr = pTextLayout_->SetTypography(pTypography, textRange); }
Задайте новую ширину и высоту для объекта макета текста в методе MultiformattedText::OnResize.
if (pTextLayout_) { pTextLayout_->SetMaxWidth(static_cast<FLOAT>(width / dpiScaleX_)); pTextLayout_->SetMaxHeight(static_cast<FLOAT>(height / dpiScaleY_)); }
Часть 4. Рисование текста с помощью метода Direct2D DrawTextLayout.
Чтобы нарисовать текст с параметрами макета текста, заданными объектом IDWriteTextLayout , измените код в методе MultiformattedText::D rawText, чтобы использовать IDWriteTextLayout::D rawTextLayout.
Delcare D2D1_POINT_2F переменной и задать для нее верхнюю левую точку окна.
D2D1_POINT_2F origin = D2D1::Point2F( static_cast<FLOAT>(rc.left / dpiScaleX_), static_cast<FLOAT>(rc.top / dpiScaleY_) );
Нарисуйте текст на экране, вызвав метод ID2D1RenderTarget::D rawTextLayout целевого объекта отрисовки Direct2D и передав указатель IDWriteTextLayout .
pRT_->DrawTextLayout( origin, pTextLayout_, pBlackBrush_ );
Класс MultiformattedText реализован в multiformattedText.h и MultiformattedText.cpp.