Поделиться через


Руководство. Начало работы с DirectWrite

В этом документе показано, как использовать DirectWrite и Direct2D для создания простого текста, содержащего один формат, а затем текст, содержащий несколько форматов.

В этом руководстве содержатся следующие части:

Исходный код

Исходный код, показанный в этом обзоре, взят из примера DirectWrite Hello World. Каждая часть реализована в отдельном классе (SimpleText и MultiformattedText) и отображается в отдельном дочернем окне. Каждый класс представляет окно Microsoft Win32. Помимо метода WndProc, каждый класс содержит следующие методы:

Функция Описание
Создание ресурсов, не зависящих от устройства Создает ресурсы, независимые от устройства, чтобы их можно было повторно использовать в любом месте.
DiscardDeviceIndependentResources Освобождает независимые от устройства ресурсы после того, как они больше не нужны.
CreateDeviceResources Создает ресурсы, такие как кисти и целевые объекты отрисовки, привязанные к конкретному устройству.
Освобождение ресурсов устройства Освобождает ресурсы, зависящие от устройств, после того как они больше не нужны.
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; Если вы еще этого не сделали, включите эти заголовки в проект.

  1. В файле заголовка класса (SimpleText.h) объявите указатели на IDWriteFactory и IDWriteTextFormat интерфейсы в качестве закрытых элементов.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. Объявите переменные, чтобы сохранить текстовую строку для отрисовки и для длины строки.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Объявите указатели на интерфейсы ID2D1Factory, ID2D1HwndRenderTargetи ID2D1SolidColorBrush для отображения текста с помощью Direct2D.

    ID2D1Factory* pD2DFactory_;
    ID2D1HwndRenderTarget* pRT_;
    ID2D1SolidColorBrush* pBlackBrush_;
    
    

Часть 2. Создание независимых ресурсов устройства.

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

Ресурсы DirectWrite не зависят от устройств.

В этом разделе описано, как создать независимые от устройства ресурсы, используемые приложением. Эти ресурсы необходимо освободить с помощью вызова метода Release интерфейса.

Некоторые из ресурсов, которые используются, необходимо создать только один раз и не привязаны к устройству. Инициализация этих ресурсов помещается в метод SimpleText::CreateDeviceIndependentResources, который вызывается при инициализации класса.

  1. В методе SimpleText::CreateDeviceIndependentResources в файле реализации класса (SimpleText.cpp), вызовите функцию D2D1CreateFactory, чтобы создать интерфейс ID2D1Factory, который является интерфейсом корневой фабрики для всех объектов Direct2D. Вы используете ту же фабрику для создания экземпляров других ресурсов Direct2D.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. Вызовите функцию DWriteCreateFactory для создания интерфейса IDWriteFactory, который является корневым интерфейсом фабрики для всех объектов DirectWrite. Вы используете ту же фабрику для создания экземпляров других ресурсов DirectWrite.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. Инициализируйте текстовую строку и сохраните ее длину.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. Создайте объект интерфейса 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_
            );
    }
    
    
  5. Центрирование текста по горизонтали и вертикали путем вызова методов 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 привязаны к устройству отрисовки при их создании, и их необходимо освободить и повторно создать, если устройство станет недействительным.

  1. В методе 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_
                );
        }
    }
    
    
  2. В методе SimpleText::D iscardDeviceResources выпустите как кисть, так и целевой объект отрисовки.

    SafeRelease(&pRT_);
    SafeRelease(&pBlackBrush_);
    
    

Теперь, когда вы создали целевой объект отрисовки и кисть, их можно использовать для отрисовки текста.

Часть 4. Рисование текста с помощью метода Direct2D DrawText.

  1. В методе 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_
        );
    
    
  2. Используйте метод ID2D1RenderTarget::DrawText и объект IDWriteTextFormat для отображения текста на экране. Метод ID2D1RenderTarget::DrawText принимает следующие параметры:

    • Строка для отрисовки.
    • Указатель на интерфейс 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 при получении сообщения с краской, выполните следующие действия:

  1. Создайте зависимые от устройства ресурсы, вызвав метод SimpleText::CreateDeviceResources, реализованный в части 3.
  2. Вызовите метод ID2D1HwndRenderTarget::BeginDraw целевого объекта отрисовки.
  3. Очистите целевой объект отрисовки, вызвав метод ID2D1HwndRenderTarget::Clear.
  4. Вызовите метод SimpleText::DrawText, реализованный в Часть 4.
  5. Вызовите метод ID2D1HwndRenderTarget::EndDraw целевого объекта отрисовки.
  6. Если это необходимо, удалите ресурсы, зависящие от устройства, чтобы их можно было повторно создать при перерисовке окна.
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.

  1. Объявите указатель на интерфейс IDWriteTextLayout в качестве члена класса MultiformattedText.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. В конце метода 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.

  1. Задайте размер шрифта для подстроки "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);
    }
    
  2. Подчеркните подстроку 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);
    }
    
  3. Задайте вес шрифта полужирным для подстроки 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.

  1. Объявите и создайте объект интерфейса IDWriteTypography путем вызова метода IDWriteFactory::CreateTypography.

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. Добавьте функцию шрифта, объявив объект 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);
    }
    
    
  3. Задайте макет текста, чтобы использовать типографию по всей строке, объявив переменную 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);
    }
    
    
  4. Задайте новую ширину и высоту объекта текстового макета в методе MultiformattedText::OnResize.

    if (pTextLayout_)
    {
        pTextLayout_->SetMaxWidth(static_cast<FLOAT>(width / dpiScaleX_));
        pTextLayout_->SetMaxHeight(static_cast<FLOAT>(height / dpiScaleY_));
    }
    

Часть 4. Рисование текста с помощью метода Direct2D DrawTextLayout.

Чтобы нарисовать текст с параметрами макета текста, заданными объектом IDWriteTextLayout, измените код метода MultiformattedText::DrawText, чтобы использовать IDWriteTextLayout::DrawTextLayout.

  1. Объявите переменную D2D1_POINT_2F и установите её в верхнюю левую точку окна.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Выведите текст на экран, вызвав метод ID2D1RenderTarget::DrawTextLayout объекта назначения Direct2D рендеринга и передав в него указатель IDWriteTextLayout.

    pRT_->DrawTextLayout(
        origin,
        pTextLayout_,
        pBlackBrush_
        );
    
    

Класс MultiformattedText реализуется в MultiformattedText.h и MultiformattedText.cpp.