Partilhar via


Tutorial: Introdução ao DirectWrite

Este documento mostra como usar DirectWrite e Direct2D para criar texto simples que contém um único formato e, em seguida, texto que contém vários formatos.

Este tutorial contém as seguintes partes:

Código Fonte

O código-fonte mostrado nesta visão geral é retirado do exemplo de DirectWrite Hello World. Cada parte é implementada numa classe separada (SimpleText e MultiformattedText) e é exibida numa janela filha separada. Cada classe representa uma janela do Microsoft Win32. Além do WndProc método, cada classe contém os seguintes métodos:

Função Descrição
CriarRecursosIndependentesDoDispositivo Cria recursos que são independentes do dispositivo, para que possam ser reutilizados em qualquer lugar.
DescartarRecursosIndependentesDoDispositivo Libera os recursos independentes do dispositivo depois que eles não são mais necessários.
CriarRecursosDoDispositivo Cria recursos, como pincéis e destinos de renderização, que estão vinculados a um dispositivo específico.
DiscardDeviceResources Libera os recursos dependentes do dispositivo depois que eles não são mais necessários.
DrawD2DContent Usa Direct2D para renderizar na tela.
DesenharTexto Desenha a cadeia de caracteres de texto usando Direct2D.
OnResize Redimensiona o destino de renderização Direct2D quando o tamanho da janela é alterado.

 

Você pode usar o exemplo fornecido ou usar as instruções a seguir para adicionar DirectWrite e Direct2D ao seu próprio aplicativo Win32. Para obter mais informações sobre o exemplo e os arquivos de projeto associados, consulte o DirectWrite HelloWorld.

Desenho de texto simples

Esta seção mostra como usar DirectWrite e Direct2D para renderizar texto simples que tenha um único formato, conforme mostrado na captura de tela a seguir.

captura de tela de

Desenhar texto simples para a tela requer quatro componentes:

  • Uma cadeia de caracteres para renderizar.
  • Uma instância de IDWriteTextFormat.
  • As dimensões da área destinada a conter o texto.
  • Um objeto que pode renderizar o texto. Neste tutorial. você usa um Direct2D destino de renderização.

A interface IDWriteTextFormat descreve o nome da família de fontes, tamanho, peso, estilo e alongamento usados para formatar texto e descreve informações de localidade. IDWriteTextFormat também define métodos para definir e obter as seguintes propriedades:

  • O espaçamento entre linhas.
  • O alinhamento do texto em relação às bordas esquerda e direita da caixa de layout.
  • O alinhamento do parágrafo em relação à parte superior e inferior da caixa de layout.
  • A direção de leitura.
  • A granularidade do corte de texto para texto que transborda da caixa de layout.
  • A parada de tabulação incremental.
  • A direção do fluxo de parágrafo.

O IDWriteTextFormat interface é necessário para desenhar texto que usa ambos os processos descritos neste documento.

Antes de criar um objeto IDWriteTextFormat ou qualquer outro objeto DirectWrite, necessita de uma instância IDWriteFactory. Você usa um IDWriteFactory para criar instâncias de IDWriteTextFormat e outros objetos DirectWrite. Para obter uma instância de fábrica, use a função DWriteCreateFactory.

Parte 1: Declarar recursos DirectWrite e Direct2D.

Nesta parte, você declara os objetos que usará posteriormente para criar e exibir texto como membros de dados privados de sua classe. Todas as interfaces, funções e tipos de dados para DirectWrite são declarados no arquivo de cabeçalho dwrite.h, e aqueles para Direct2D são declarados no d2d1.h ; Se você ainda não fez isso, inclua esses cabeçalhos em seu projeto.

  1. No seu ficheiro de cabeçalho da classe (SimpleText.h), declare ponteiros para as interfaces IDWriteFactory e IDWriteTextFormat como membros privados.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. Declare os membros para armazenar a string de texto a ser renderizada e o comprimento da string.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Declare ponteiros para ID2D1Factory, ID2D1HwndRenderTargete ID2D1SolidColorBrush nas interfaces para renderizar o texto com Direct2D.

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

Parte 2: Criar recursos independentes do dispositivo.

Direct2D fornece dois tipos de recursos: recursos dependentes do dispositivo e recursos independentes do dispositivo. Os recursos dependentes do dispositivo são associados a um dispositivo de renderização e não funcionam mais se esse dispositivo for removido. Recursos independentes do dispositivo, por outro lado, podem permanecer disponíveis durante o alcance da sua aplicação.

recursos de DirectWrite são independentes do dispositivo.

Nesta seção, você cria os recursos independentes do dispositivo que são usados pelo seu aplicativo. Esses recursos devem ser liberados com uma chamada para o método Release da interface.

Alguns dos recursos que são usados têm de ser criados apenas uma vez e não estão vinculados a um dispositivo. A inicialização para esses recursos é colocada no SimpleText::CreateDeviceIndependentResources método, que é chamado ao inicializar a classe.

  1. Dentro do método SimpleText::CreateDeviceIndependentResources no ficheiro de implementação de classe (SimpleText.cpp), chame a funçãoD2D1CreateFactory, a qual cria uma interfaceID2D1Factory, que é a interface raiz de fábrica para todos os objetos Direct2D. Você usa a mesma fábrica para instanciar outros recursos Direct2D.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. Chame a função DWriteCreateFactory para criar uma interface IDWriteFactory, que é a interface de fábrica raiz para todos os objetos DirectWrite. Você usa a mesma fábrica para instanciar outros recursos DirectWrite.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. Inicialize a cadeia de caracteres de texto e armazene seu comprimento.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. Crie um IDWriteTextFormat objeto de interface usando o IDWriteFactory::CreateTextFormat método. O IDWriteTextFormat especifica a fonte, a espessura, a extensão, o estilo e a localidade que serão usados para renderizar a cadeia de caracteres de texto.

    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. Centralizar o texto horizontal e verticalmente chamando os métodos IDWriteTextFormat::SetTextAlignment e 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);
    }
    
    

Nesta parte, você inicializou os recursos independentes do dispositivo que são usados pelo seu aplicativo. Na próxima parte, você inicializa os recursos dependentes do dispositivo.

Parte 3: Criar Recursos Device-Dependent.

Nesta parte, você cria um ID2D1HwndRenderTarget e um ID2D1SolidColorBrush para renderizar seu texto.

Um destino de renderização é um objeto Direct2D que cria recursos de desenho e renderiza comandos de desenho para um dispositivo de renderização. Um ID2D1HwndRenderTargetdeé um render target que renderiza para um HWND .

Um dos recursos de desenho que um destino de renderização pode criar é um pincel para pintar contornos, preenchimentos e texto. Um ID2D1SolidColorBrush pinta com uma cor sólida.

As interfaces ID2D1HwndRenderTarget e ID2D1SolidColorBrush estão vinculadas a um dispositivo de renderização quando são criadas e devem ser liberadas e recriadas se o dispositivo se tornar inválido.

  1. Dentro do método SimpleText::CreateDeviceResources, verifique se o ponteiro de destino de renderização está NULL. Se estiver, recupere o tamanho da área de renderização e crie um ID2D1HwndRenderTarget desse tamanho. Use o ID2D1HwndRenderTarget para criar um 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. No método SimpleText::DiscardDeviceResources, liberte tanto o pincel como o alvo de renderização.

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

Agora que você criou um destino de renderização e um pincel, você pode usá-los para renderizar seu texto.

Parte 4: Desenhar texto usando o método Direct2D DrawText.

  1. No método SimpleText::D rawText da sua classe, defina a área para o layout de texto recuperando as dimensões da área de renderização e crie um retângulo de Direct2D que tenha as mesmas dimensões.

    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. Use o método ID2D1RenderTarget::DrawText e o objeto IDWriteTextFormat para renderizar texto no ecrã. O método ID2D1RenderTarget::DrawText aceita os seguintes parâmetros:

    • Uma cadeia de caracteres para renderizar.
    • Um ponteiro para uma interface IDWriteTextFormat .
    • Um retângulo de layout de Direct2D.
    • Um ponteiro para uma interface que expõe 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.
        );
    
    

Parte 5: Renderizar o conteúdo da janela usando Direct2D

Para renderizar o conteúdo da janela usando Direct2D quando uma mensagem de pintura for recebida, faça o seguinte:

  1. Crie os recursos dependentes do dispositivo chamando o método SimpleText::CreateDeviceResources implementado na Parte 3.
  2. Chame o método ID2D1HwndRenderTarget::BeginDraw do alvo de renderização.
  3. Limpe o destino de renderização chamando o ID2D1HwndRenderTarget::Clear método.
  4. Chame o método SimpleText::DrawText, implementado na Parte 4.
  5. Chame o método ID2D1HwndRenderTarget::EndDraw do destino de renderização.
  6. Se for necessário, descarte os recursos dependentes do dispositivo para que eles possam ser recriados quando a janela for redesenhada.
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();
}

A classe SimpleText é implementada em SimpleText.h e SimpleText.cpp.

Desenho de texto com vários formatos.

Esta seção mostra como usar DirectWrite e Direct2D para renderizar texto com vários formatos, conforme mostrado na captura de tela a seguir.

captura de tela de

O código para esta seção é implementado como o classe MultiformattedText no DirectWrite HelloWorld. Baseia-se nas etapas da seção anterior.

Para criar texto multiformatado, use a interface IDWriteTextLayout além da interface IDWriteTextFormat introduzida na seção anterior. O IDWriteTextLayout interface descreve a formatação e o layout de um bloco de texto. Além da formatação padrão especificada por um objeto IDWriteTextFormat, a formatação para intervalos específicos de texto pode ser alterada usando IDWriteTextLayout. Isso inclui o nome da família da fonte, tamanho, peso, estilo, extensão, riscado e sublinhado.

IDWriteTextLayout também fornece métodos de verificação de acertos. As métricas de teste de acerto retornadas por esses métodos são relativas à caixa de layout especificada quando o objeto de interface IDWriteTextLayout é criado usando o métodoCreateTextLayout da interfaceIDWriteFactory.

A interface IDWriteTypography é usada para adicionar recursos tipográficos OpenType opcionais a um layout de texto, como swashes e conjuntos estilísticos de texto alternativos. Os recursos tipográficos podem ser adicionados a um intervalo específico de texto dentro de um layout de texto, chamando o método AddFontFeature da interface IDWriteTypography. Este método recebe uma estrutura DWRITE_FONT_FEATURE como um parâmetro que contém uma constante de enumeração DWRITE_FONT_FEATURE_TAG e um parâmetro de execução UINT32. Uma lista de recursos OpenType registrados pode ser encontrada no OpenType Layout Tag Registry no microsoft.com. Para obter as constantes de enumeração DirectWrite equivalentes, consulte DWRITE_FONT_FEATURE_TAG.

Parte 1: Criar uma interface IDWriteTextLayout.

  1. Declare um ponteiro para a interface IDWriteTextLayout como um membro da classe MultiformattedText.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. No final do método MultiformattedText::CreateDeviceIndependentResources, crie um IDWriteTextLayout objeto de interface chamando o CreateTextLayout método. A interface IDWriteTextLayout fornece recursos de formatação adicionais, como a capacidade de aplicar diferentes formatos a partes selecionadas do texto.

    // 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.
            );
    }
    
    

Parte 2: Aplicando formatação com IDWriteTextLayout.

A formatação, como o tamanho da fonte, a espessura e o sublinhado, pode ser aplicada a substrings do texto a ser exibido usando o IDWriteTextLayout interface.

  1. Defina o tamanho da fonte para a substring "Di" de "DirectWrite" para 100, declarando um DWRITE_TEXT_RANGE e chamando o método 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. Sublinhe a substring "DirectWrite" chamando o método 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. Defina a espessura da fonte como negrito para a substring "DirectWrite" chamando o método 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);
    }
    

Parte 3: Adicionando recursos tipográficos com IDWriteTypography.

  1. Declare e crie um IDWriteTypography objeto de interface chamando o IDWriteFactory::CreateTypography método.

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. Adicione um recurso de fonte declarando um objeto DWRITE_FONT_FEATURE que tenha o conjunto estilístico 7 especificado e chamando o IDWriteTypography::AddFontFeature método.

    // Set the stylistic set.
    DWRITE_FONT_FEATURE fontFeature = {DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7,
                                       1};
    if (SUCCEEDED(hr))
    {
        hr = pTypography->AddFontFeature(fontFeature);
    }
    
    
  3. Defina o layout de texto para usar a tipografia em toda a cadeia de caracteres declarando uma variável DWRITE_TEXT_RANGE e chamando o IDWriteTextLayout::SetTypography método e passando o intervalo de texto.

    if (SUCCEEDED(hr))
    {
        // Set the typography for the entire string.
        DWRITE_TEXT_RANGE textRange = {0,
                                       cTextLength_};
        hr = pTextLayout_->SetTypography(pTypography, textRange);
    }
    
    
  4. Defina a nova largura e altura para o objeto de layout de texto no método MultiformattedText::OnResize.

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

Parte 4: Desenhar texto usando o método Direct2D DrawTextLayout.

Para desenhar o texto com as configurações de layout de texto especificadas pelo objeto IDWriteTextLayout, altere o código no método MultiformattedText::DrawText para usar IDWriteTextLayout::DrawTextLayout.

  1. Declare uma variável D2D1_POINT_2F e defina-a para o ponto superior esquerdo da janela.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Desenhe o texto para a tela chamando o ID2D1RenderTarget::D rawTextLayout método do destino de renderização Direct2D e passando o ponteiro IDWriteTextLayout.

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

A classe MultiformattedText é implementada em MultiformattedText.h e MultiformattedText.cpp.