Partager via


Tutoriel : Prise en main avec DirectWrite

Ce document vous montre comment utiliser DirectWrite et Direct2D pour créer du texte simple contenant un format unique, puis du texte contenant plusieurs formats.

Ce didacticiel contient les éléments suivants :

Code source

Le code source présenté dans cette vue d’ensemble est extrait de l’exemple DirectWrite Hello World. Chaque partie est implémentée dans une classe distincte (SimpleText et MultiformattedText) et s’affiche dans une fenêtre enfant distincte. Chaque classe représente une fenêtre Microsoft Win32. En plus de la méthode WndProc , chaque classe contient les méthodes suivantes :

Fonction Description
CreateDeviceIndependentResources Crée des ressources indépendantes de l’appareil, afin qu’elles puissent être réutilisées n’importe où.
DiscardDeviceIndependentResources Libère les ressources indépendantes de l’appareil une fois qu’elles ne sont plus nécessaires.
CreateDeviceResources Crée des ressources, telles que des pinceaux et des cibles de rendu, qui sont liées à un appareil particulier.
DiscardDeviceResources Libère les ressources dépendantes de l’appareil une fois qu’elles ne sont plus nécessaires.
DrawD2DContent Utilise Direct2D pour le rendu à l’écran.
DrawText Dessine la chaîne de texte à l’aide de Direct2D.
OnResize Redimensionne la cible de rendu Direct2D lorsque la taille de la fenêtre est modifiée.

 

Vous pouvez utiliser l’exemple fourni ou utiliser les instructions ci-dessous pour ajouter DirectWrite et Direct2D à votre propre application Win32. Pour plus d’informations sur l’exemple et les fichiers projet associés, consultez la DirectWrite HelloWorld.

Dessin de texte simple

Cette section montre comment utiliser DirectWrite et Direct2D pour afficher du texte simple au format unique, comme illustré dans la capture d’écran suivante.

capture d’écran de « hello world using directwrite! » dans un format unique

Le dessin de texte simple à l’écran nécessite quatre composants :

  • Chaîne de caractères à afficher.
  • Instance d’IDWriteTextFormat.
  • Dimensions de la zone à contenir.
  • Objet qui peut restituer le texte. Dans ce tutoriel, vous utilisez une cible de rendu Direct2D .

L’interface IDWriteTextFormat décrit le nom de la famille de polices, la taille, le poids, le style et l’étirement utilisés pour mettre en forme le texte, et décrit les informations de paramètres régionaux. IDWriteTextFormat définit également des méthodes pour définir et obtenir les propriétés suivantes :

  • Interligne.
  • Alignement du texte par rapport aux bords gauche et droit de la zone de disposition.
  • Alignement du paragraphe par rapport au haut et au bas de la zone de disposition.
  • Sens de lecture.
  • Granularité du découpage de texte pour le texte qui dépasse la zone de disposition.
  • Taquet de tabulation incrémentiel.
  • Sens du flux du paragraphe.

L’interface IDWriteTextFormat est requise pour dessiner du texte qui utilise les deux processus décrits dans ce document .

Avant de pouvoir créer un objet IDWriteTextFormat ou tout autre objet DirectWrite, vous avez besoin d’un instance IDWriteFactory. Vous utilisez un IDWriteFactory pour créer des instances IDWriteTextFormat et d’autres objets DirectWrite. Pour obtenir un instance de fabrique, utilisez la fonction DWriteCreateFactory.

Partie 1 : Déclarer DirectWrite et les ressources Direct2D.

Dans cette partie, vous déclarez les objets que vous utiliserez ultérieurement pour créer et afficher du texte en tant que membres de données privés de votre classe. Toutes les interfaces, fonctions et types de données pour DirectWrite sont déclarées dans le fichier dwrite.h, et celles de Direct2D sont déclarées dans d2d1.h. Si vous ne l’avez pas déjà fait, incluez ces en-têtes dans votre projet.

  1. Dans votre fichier d’en-tête de classe (SimpleText.h), déclarez des pointeurs vers les interfaces IDWriteFactory et IDWriteTextFormat en tant que membres privés.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. Déclarez les membres pour qu’ils contiennent la chaîne de texte à afficher et la longueur de la chaîne.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Déclarez des pointeurs vers les interfaces ID2D1Factory, ID2D1HwndRenderTarget et ID2D1SolidColorBrush pour le rendu du texte avec Direct2D.

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

Partie 2 : Créer des ressources indépendantes de l’appareil.

Direct2D fournit deux types de ressources : les ressources dépendantes de l’appareil et les ressources indépendantes de l’appareil. Les ressources dépendantes de l’appareil sont associées à un appareil de rendu et ne fonctionnent plus si cet appareil est supprimé. En revanche, les ressources indépendantes de l’appareil peuvent durer pour l’étendue de votre application.

DirectWrite ressources sont indépendantes de l’appareil.

Dans cette section, vous allez créer les ressources indépendantes de l’appareil utilisées par votre application. Ces ressources doivent être libérées par un appel à la méthode Release de l’interface.

Certaines des ressources utilisées ne doivent être créées qu’une seule fois et ne sont pas liées à un appareil. L’initialisation de ces ressources est placée dans la méthode SimpleText::CreateDeviceIndependentResources , qui est appelée lors de l’initialisation de la classe .

  1. Dans la méthode SimpleText::CreateDeviceIndependentResources dans le fichier d’implémentation de classe (SimpleText.cpp), appelez la fonction D2D1CreateFactory pour créer une interface ID2D1Factory , qui est l’interface de fabrique racine pour tous les objets Direct2D . Vous utilisez la même fabrique pour instancier d’autres ressources Direct2D.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. Appelez la fonction DWriteCreateFactory pour créer une interface IDWriteFactory, qui est l’interface de fabrique racine pour tous les objets DirectWrite. Vous utilisez la même fabrique pour instancier d’autres ressources DirectWrite.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. Initialisez la chaîne de texte et stockez sa longueur.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. Créez un objet d’interface IDWriteTextFormat à l’aide de la méthode IDWriteFactory::CreateTextFormat . IDWriteTextFormat spécifie la police, le poids, l’étirement, le style et les paramètres régionaux qui seront utilisés pour afficher la chaîne de texte.

    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. Centrez le texte horizontalement et verticalement en appelant les méthodes IDWriteTextFormat::SetTextAlignment et 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);
    }
    
    

Dans cette partie, vous avez initialisé les ressources indépendantes de l’appareil utilisées par votre application. Dans la partie suivante, vous initialisez les ressources dépendantes de l’appareil.

Partie 3 : Créer des ressources Device-Dependent.

Dans cette partie, vous créez un ID2D1HwndRenderTarget et un ID2D1SolidColorBrush pour le rendu de votre texte.

Une cible de rendu est un objet Direct2D qui crée des ressources de dessin et restitue les commandes de dessin sur un périphérique de rendu. Id2D1HwndRenderTarget est une cible de rendu qui s’affiche sur un HWND.

Une des ressources de dessin qu’une cible de rendu peut créer est un pinceau pour peindre des contours, des remplissages et du texte. Un objet ID2D1SolidColorBrush peint avec une couleur unie.

Les interfaces ID2D1HwndRenderTarget et ID2D1SolidColorBrush sont liées à un appareil de rendu lors de leur création et doivent être libérées et recréées si l’appareil devient non valide.

  1. Dans la méthode SimpleText::CreateDeviceResources, case activée si le pointeur cible de rendu est NULL. Si c’est le cas, récupérez la taille de la zone de rendu et créez un ID2D1HwndRenderTarget de cette taille. Utilisez id2D1HwndRenderTarget pour créer un OBJET 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. Dans la méthode SimpleText::D iscardDeviceResources, relâchez le pinceau et la cible de rendu.

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

Maintenant que vous avez créé une cible de rendu et un pinceau, vous pouvez les utiliser pour restituer votre texte.

Partie 4 : Dessiner du texte à l’aide de la méthode DrawText Direct2D.

  1. Dans la méthode SimpleText::D rawText de votre classe, définissez la zone de la disposition de texte en récupérant les dimensions de la zone de rendu, puis créez un rectangle Direct2D qui a les mêmes dimensions.

    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. Utilisez la méthode ID2D1RenderTarget::D rawText et l’objet IDWriteTextFormat pour afficher le texte à l’écran. La méthode ID2D1RenderTarget::D rawText prend les paramètres suivants :

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

Partie 5 : Afficher le contenu de la fenêtre à l’aide de Direct2D

Pour afficher le contenu de la fenêtre à l’aide de Direct2D lorsqu’un message de peinture est reçu, procédez comme suit :

  1. Créez les ressources dépendantes de l’appareil en appelant la méthode SimpleText::CreateDeviceResources implémentée dans la partie 3.
  2. Appelez la méthode ID2D1HwndRenderTarget::BeginDraw de la cible de rendu.
  3. Effacez la cible de rendu en appelant la méthode ID2D1HwndRenderTarget::Clear .
  4. Appelez la méthode SimpleText::D rawText, implémentée dans la partie 4.
  5. Appelez la méthode ID2D1HwndRenderTarget::EndDraw de la cible de rendu.
  6. Si nécessaire, ignorez les ressources dépendantes de l’appareil afin qu’elles puissent être recréées lorsque la fenêtre est redessinée.
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 classe SimpleText est implémentée dans SimpleText.h et SimpleText.cpp.

Dessin de texte avec plusieurs formats.

Cette section montre comment utiliser DirectWrite et Direct2D pour afficher du texte avec plusieurs formats, comme illustré dans la capture d’écran suivante.

capture d’écran de « Hello World using directwrite! », avec certaines parties dans différents styles, tailles et formats

Le code de cette section est implémenté en tant que classe MultiformattedText dans le DirectWrite HelloWorld. Il est basé sur les étapes de la section précédente.

Pour créer du texte multiformaté, vous utilisez l’interface IDWriteTextLayout en plus de l’interface IDWriteTextFormat introduite dans la section précédente. L’interface IDWriteTextLayout décrit la mise en forme et la disposition d’un bloc de texte. En plus de la mise en forme par défaut spécifiée par un objet IDWriteTextFormat , la mise en forme de plages de texte spécifiques peut être modifiée à l’aide d’IDWriteTextLayout. Cela inclut le nom de la famille de polices, la taille, le poids, le style, l’étirement, le barré et le soulignement.

IDWriteTextLayout fournit également des méthodes de test d’accès. Les métriques de test d’accès retournées par ces méthodes sont relatives à la zone de disposition spécifiée lorsque l’objet d’interface IDWriteTextLayout est créé à l’aide de la méthode CreateTextLayout de l’interface IDWriteFactory .

L’interface IDWriteTypography permet d’ajouter des fonctionnalités typographiques OpenType facultatives à une disposition de texte, telles que des swashes et d’autres jeux de texte stylistiques. Vous pouvez ajouter des caractéristiques typographiques à une plage de texte spécifique dans une disposition de texte en appelant la méthode AddFontFeature de l’interface IDWriteTypography . Cette méthode reçoit une structure DWRITE_FONT_FEATURE en tant que paramètre qui contient une constante d’énumération DWRITE_FONT_FEATURE_TAG et un paramètre d’exécution UINT32 . Vous trouverez la liste des fonctionnalités OpenType inscrites dans le registre de balises de disposition OpenType sur microsoft.com. Pour obtenir les constantes d’énumération DirectWrite équivalentes, consultez DWRITE_FONT_FEATURE_TAG.

Partie 1 : Créer une interface IDWriteTextLayout.

  1. Déclarez un pointeur vers une interface IDWriteTextLayout en tant que membre de la classe MultiformattedText.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. À la fin de la méthode MultiformattedText::CreateDeviceIndependentResources, créez un objet d’interface IDWriteTextLayout en appelant la méthode CreateTextLayout . L’interface IDWriteTextLayout fournit des fonctionnalités de mise en forme supplémentaires, telles que la possibilité d’appliquer différents formats à des parties de texte sélectionnées.

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

Partie 2 : Application de la mise en forme avec IDWriteTextLayout.

La mise en forme, telle que la taille de police, le poids et le soulignement, peut être appliquée aux sous-chaînes du texte à afficher à l’aide de l’interface IDWriteTextLayout .

  1. Définissez la taille de police de la sous-chaîne « Di » de « DirectWrite » sur 100 en déclarant un DWRITE_TEXT_RANGE et en appelant la méthode 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. Soulignez la sous-chaîne « DirectWrite » en appelant la méthode 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. Définissez le poids de police sur gras pour la sous-chaîne « DirectWrite » en appelant la méthode 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);
    }
    

Partie 3 : Ajout de fonctionnalités typographiques avec IDWriteTypography.

  1. Déclarez et créez un objet d’interface IDWriteTypography en appelant la méthode IDWriteFactory::CreateTypography .

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. Ajoutez une fonctionnalité de police en déclarant un objet DWRITE_FONT_FEATURE pour lequel le jeu stylistique 7 est spécifié et en appelant la méthode 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. Définissez la disposition du texte de façon à utiliser la typographie sur l’ensemble de la chaîne en déclarant une variable DWRITE_TEXT_RANGE et en appelant la méthode IDWriteTextLayout::SetTypography et en transmettant la plage de texte.

    if (SUCCEEDED(hr))
    {
        // Set the typography for the entire string.
        DWRITE_TEXT_RANGE textRange = {0,
                                       cTextLength_};
        hr = pTextLayout_->SetTypography(pTypography, textRange);
    }
    
    
  4. Définissez la nouvelle largeur et la nouvelle hauteur de l’objet de disposition de texte dans la méthode MultiformattedText::OnResize.

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

Partie 4 : Dessiner du texte à l’aide de la méthode DrawTextLayout Direct2D.

Pour dessiner le texte avec les paramètres de disposition de texte spécifiés par l’objet IDWriteTextLayout , modifiez le code de la méthode MultiformattedText::D rawText pour utiliser IDWriteTextLayout::D rawTextLayout.

  1. Delcare une variable D2D1_POINT_2F et définissez-la sur le point supérieur gauche de la fenêtre.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Dessinez le texte à l’écran en appelant la méthode ID2D1RenderTarget::D rawTextLayout de la cible de rendu Direct2D et en transmettant le pointeur IDWriteTextLayout .

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

La classe MultiformattedText est implémentée dans MultiformattedText.h et MultiformattedText.cpp.