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


Руководство. начало работы с помощью 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; если вы еще не сделали этого, включите эти заголовки в проект.

  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::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, сделайте следующее:

  1. Создайте зависимые от устройства ресурсы, вызвав метод SimpleText::CreateDeviceResources, реализованный в части 3.
  2. Вызовите метод ID2D1HwndRenderTarget::BeginDraw целевого объекта отрисовки.
  3. Очистите целевой объект отрисовки, вызвав метод ID2D1HwndRenderTarget::Clear .
  4. Вызовите метод SimpleText::D rawText, реализованный в части 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::D rawText, чтобы использовать IDWriteTextLayout::D rawTextLayout.

  1. Delcare D2D1_POINT_2F переменной и задать для нее верхнюю левую точку окна.

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

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

Класс MultiformattedText реализован в multiformattedText.h и MultiformattedText.cpp.