Compartir a través de


Tutorial: Introducción a DirectWrite

En este documento se muestra cómo usar directWrite y direct2D para crear texto simple que contenga un solo formato y, a continuación, texto que contenga varios formatos.

Este tutorial contiene las siguientes partes:

Código fuente

El código fuente que se muestra en esta información general se toma del ejemplo DirectWrite Hello World. Cada elemento se implementa en una clase independiente (SimpleText y MultiformattedText) y se muestra en una ventana secundaria independiente. Cada clase representa una ventana de Microsoft Win32. Además del método WndProc , cada clase contiene los métodos siguientes:

Función Descripción
CreateDeviceIndependentResources Crea recursos independientes del dispositivo, por lo que se pueden reutilizar en cualquier lugar.
DescartarRecursosIndependientesDelDispositivo Libera los recursos independientes del dispositivo después de que ya no se necesiten.
CreateDeviceResources Crea recursos, como pinceles y destinos de representación, que están vinculados a un dispositivo determinado.
DiscardDeviceResources Libera los recursos dependientes del dispositivo después de que ya no sean necesarios.
DrawD2DContent Usa Direct2D para representar en la pantalla.
DrawText Dibuja la cadena de texto mediante Direct2D.
OnResize Cambia el tamaño del destino de representación de Direct2D cuando se cambia el tamaño de la ventana.

 

Puedes usar el ejemplo proporcionado o usar las instrucciones siguientes para agregar DirectWrite y Direct2D a tu propia aplicación Win32. Para obtener más información sobre el ejemplo y los archivos de proyecto asociados, vea DirectWrite HelloWorld.

Dibujar texto simple

En esta sección se muestra cómo usar DirectWrite y Direct2D para representar texto simple con un solo formato, como se muestra en la captura de pantalla siguiente.

captura de pantalla de

Dibujar texto simple en la pantalla requiere cuatro componentes:

La interfaz IDWriteTextFormat describe el nombre de familia de fuentes, el tamaño, el peso, el estilo y la extensión usados para dar formato al texto y describe la información de configuración regional. IDWriteTextFormat también define métodos para establecer y obtener las siguientes propiedades:

  • Espaciado de líneas.
  • Alineación de texto relativa a los bordes izquierdo y derecho del cuadro de diseño.
  • Alineación del párrafo con respecto a la parte superior e inferior del cuadro de diseño.
  • La dirección de lectura.
  • La granularidad del recorte de texto para texto que desborda el cuadro de diseño.
  • Parada incremental de tabulador.
  • Dirección del flujo de párrafo.

La interfaz IDWriteTextFormat es necesaria para dibujar texto que use ambos procesos descritos en este documento .

Para poder crear un objeto IDWriteTextFormat o cualquier otro objeto DirectWrite , necesita una instancia IDWriteFactory . Se usa un IDWriteFactory para crear instancias IDWriteTextFormat y otros objetos DirectWrite. Para obtener una instancia de generador, use la función DWriteCreateFactory .

Parte 1: Declarar recursos directWrite y Direct2D.

En esta parte, declaras los objetos que utilizarás más adelante para crear y mostrar texto como miembros de datos privados de tu clase. Todas las interfaces, funciones y tipos de datos para DirectWrite se declaran en el archivo de encabezado dwrite.h y los de Direct2D se declaran en d2d1.h; Si aún no lo ha hecho, incluya estos encabezados en el proyecto.

  1. En el archivo de encabezado de clase (SimpleText.h), declare punteros a las interfaces IDWriteFactory e IDWriteTextFormat como miembros privados.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. Declare los miembros para contener la cadena de texto que se va a representar y la longitud de la cadena.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Declare punteros a ID2D1Factory, ID2D1HwndRenderTarget e ID2D1SolidColorBrush para representar el texto con Direct2D.

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

Parte 2: Crear recursos independientes del dispositivo.

Direct2D proporciona dos tipos de recursos: recursos dependientes del dispositivo y recursos independientes del dispositivo. Los recursos dependientes del dispositivo están asociados a un dispositivo de representación y ya no funcionan si se quita ese dispositivo. Por otro lado, los recursos independientes del dispositivo pueden durar en el ámbito de la aplicación.

Los recursos de DirectWrite son independientes del dispositivo.

En esta sección, crea los recursos independientes del dispositivo que son utilizados por tu aplicación. Estos recursos deben liberarse con una llamada al método Release de la interfaz.

Algunos de los recursos que se usan tienen que crearse solo una vez y no están vinculados a un dispositivo. La inicialización de estos recursos se coloca en el método SimpleText::CreateDeviceIndependentResources , al que se llama al inicializar la clase.

  1. Dentro del método SimpleText::CreateDeviceIndependentResources en el archivo de implementación de clase (SimpleText.cpp), llame a la función D2D1CreateFactory para crear una interfaz ID2D1Factory , que es la interfaz de fábrica raíz para todos los objetos Direct2D . Use la misma factoría para crear instancias de otros recursos de Direct2D.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. Llame a la función DWriteCreateFactory para crear una interfaz IDWriteFactory , que es la interfaz de fábrica raíz para todos los objetos DirectWrite . Usted utiliza la misma fábrica para crear instancias de otros recursos de DirectWrite.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. Inicialice la cadena de texto y almacene su longitud.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. Cree un objeto de interfaz IDWriteTextFormat mediante el método IDWriteFactory::CreateTextFormat . IdWriteTextFormat especifica la fuente, el peso, el ajuste, el estilo y la configuración regional que se usarán para representar la cadena 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. Centre el texto horizontal y verticalmente llamando a los 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);
    }
    
    

En esta parte, inicializas los recursos independientes del dispositivo que utiliza tu aplicación. En la siguiente parte, inicializa los recursos dependientes del dispositivo.

Parte 3: Crear recursos Device-Dependent.

En esta parte, creará un ID2D1HwndRenderTarget y un ID2D1SolidColorBrush para representar el texto.

Un destino de representación es un objeto Direct2D que crea recursos de dibujo y representa comandos de dibujo en un dispositivo de representación. Id2D1HwndRenderTarget es un destino de representación que se representa en un HWND.

Uno de los recursos de dibujo que un objetivo de representación puede crear es un pincel para pintar contornos, rellenos y texto. Un ID2D1SolidColorBrush pinta con un color sólido.

Las interfaces ID2D1HwndRenderTarget y ID2D1SolidColorBrush están enlazadas a un dispositivo de representación cuando se crean y deben liberarse y volver a crearse si el dispositivo deja de ser válido.

  1. Dentro del método SimpleText::CreateDeviceResources, compruebe si el puntero de destino de representación es NULL. Si es así, recupere el tamaño del área de representación y cree un ID2D1HwndRenderTarget de ese tamaño. Utiliza ID2D1HwndRenderTarget para crear un 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. En el método SimpleText::DiscardDeviceResources, libere tanto el pincel como el objetivo de renderizado.

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

Ahora que ha creado un destino de representación y un pincel, puede usarlos para representar el texto.

Parte 4: Dibujar texto mediante el método DrawText direct2D.

  1. En el método SimpleText::DrawText de su clase, defina el área para el diseño de texto recuperando las dimensiones del área de representación y cree un rectángulo Direct2D que tenga las mismas dimensiones.

    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 el método ID2D1RenderTarget::D rawText y el objeto IDWriteTextFormat para representar texto en la pantalla. El método ID2D1RenderTarget::DrawText toma los siguientes parámetros:

    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: Representar el contenido de la ventana mediante Direct2D

Para representar el contenido de la ventana mediante Direct2D cuando se recibe un mensaje de pintura, haga lo siguiente:

  1. Cree los recursos dependientes del dispositivo llamando al método SimpleText::CreateDeviceResources implementado en la parte 3.
  2. Llame al método ID2D1HwndRenderTarget::BeginDraw del destino de representación.
  3. Borre el destino de representación llamando al método ID2D1HwndRenderTarget::Clear .
  4. Llame al método SimpleText::DrawText, implementado en la parte 4.
  5. Llame al método ID2D1HwndRenderTarget::EndDraw del destino de representación.
  6. Si es necesario, descarte los recursos dependientes del dispositivo para que se puedan volver a crear cuando se vuelva a dibujar la ventana.
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();
}

La clase SimpleText se implementa en SimpleText.h y SimpleText.cpp.

Dibujar texto con varios formatos.

En esta sección se muestra cómo usar DirectWrite y Direct2D para representar texto con varios formatos, como se muestra en la captura de pantalla siguiente.

captura de pantalla de

El código de esta sección se implementa como la clase MultiformattedText en DirectWrite HelloWorld. Se basa en los pasos de la sección anterior.

Para crear texto con varios formatos, use la interfaz IDWriteTextLayout además de la interfaz IDWriteTextFormat introducida en la sección anterior. La interfaz IDWriteTextLayout describe el formato y el diseño de un bloque de texto. Además del formato predeterminado especificado por un objeto IDWriteTextFormat , el formato de intervalos de texto específicos se puede cambiar mediante IDWriteTextLayout. Esto incluye el nombre de la familia tipográfica, el tamaño, el grosor, el estilo, el ancho, el tachado y el subrayado.

IDWriteTextLayout también proporciona métodos de detección de impacto. Las métricas de pruebas de posicionamiento devueltas por estos métodos son relativas al cuadro de diseño especificado cuando se crea el objeto de interfaz IDWriteTextLayout mediante el método CreateTextLayout de la interfaz IDWriteFactory .

La interfaz IDWriteTypography se usa para agregar características tipográficas OpenType opcionales a un diseño de texto, como floreos y conjuntos estilísticos alternativos. Las características tipográficas se pueden agregar a un intervalo específico de texto dentro de un diseño de texto llamando al método AddFontFeature de la interfaz IDWriteTypography . Este método recibe una estructura DWRITE_FONT_FEATURE como parámetro que contiene una constante de enumeración DWRITE_FONT_FEATURE_TAG y un parámetro de ejecución UINT32 . Puede encontrar una lista de las características de OpenType registradas en el Registro de etiquetas de diseño openType en microsoft.com. Para ver las constantes de enumeración de DirectWrite equivalentes, consulte DWRITE_FONT_FEATURE_TAG.

Parte 1: Crear una interfaz IDWriteTextLayout.

  1. Declare un puntero a una interfaz IDWriteTextLayout como miembro de la clase MultiformattedText.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. Al final del método MultiformattedText::CreateDeviceIndependentResources, cree un objeto de interfaz IDWriteTextLayout llamando al método CreateTextLayout . La interfaz IDWriteTextLayout proporciona características de formato adicionales, como la capacidad de aplicar diferentes formatos a partes seleccionadas del 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: Aplicar formato con IDWriteTextLayout.

El formato, como el tamaño de fuente, el peso y la subrayado, se puede aplicar a las subcadenas del texto que se van a mostrar mediante la interfaz IDWriteTextLayout .

  1. Establezca el tamaño de fuente de la subcadena "Di" de "DirectWrite" en 100 declarando un DWRITE_TEXT_RANGE y llamando al 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. Subraya la subcadena "DirectWrite" llamando al 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. Establezca el peso de fuente en negrita para la subcadena "DirectWrite" llamando al 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: Agregar características tipográficas con IDWriteTypography.

  1. Declare y cree un objeto de interfaz IDWriteTypography llamando al método IDWriteFactory::CreateTypography .

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. Agregue una característica de fuente declarando un objeto DWRITE_FONT_FEATURE que tenga el conjunto estilístico 7 especificado y llamando al método 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. Establezca el diseño de texto para usar la tipografía en toda la cadena declarando una variable DWRITE_TEXT_RANGE y llamando al método IDWriteTextLayout::SetTypography y pasando el 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. Establezca el nuevo ancho y alto del objeto de diseño de texto en el método MultiformattedText::OnResize.

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

Parte 4: Dibujar texto con el método DrawTextLayout de Direct2D.

Para dibujar el texto con la configuración de diseño de texto especificada por el objeto IDWriteTextLayout, cambie el código del método MultiformattedText::DrawText para usar IDWriteTextLayout::DrawTextLayout.

  1. Declare una variable D2D1_POINT_2F y establézcala en el punto superior izquierdo de la ventana.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Dibuje el texto en la pantalla llamando al método ID2D1RenderTarget::DrawTextLayout del destino de renderizado Direct2D y pasando el puntero IDWriteTextLayout.

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

La clase MultiformattedText se implementa en MultiformattedText.h y MultiformattedText.cpp.