Freigeben über


Tutorial: Erste Schritte mit DirectWrite

In diesem Dokument erfahren Sie, wie Sie mit DirectWrite und Direct2D einfachen Text erstellen, der ein einzelnes Format und dann Text mit mehreren Formaten enthält.

Dieses Tutorial enthält die folgenden Teile:

Quellcode

Der in dieser Übersicht gezeigte Quellcode stammt aus dem beispiel DirectWrite Hallo Welt. Jeder Teil wird in einer separaten Klasse (SimpleText und MultiformattedText) implementiert und in einem separaten untergeordneten Fenster angezeigt. Jede Klasse stellt ein Microsoft Win32-Fenster dar. Zusätzlich zur WndProc-Methode enthält jede Klasse die folgenden Methoden:

Funktion BESCHREIBUNG
CreateDeviceIndependentResources Erstellt Geräteunabhängige Ressourcen, sodass sie überall wiederverwendet werden können.
DiscardDeviceIndependentResources Gibt die geräteunabhängigen Ressourcen frei, nachdem sie nicht mehr benötigt werden.
CreateDeviceResources Erstellt Ressourcen wie Pinsel und Renderziele, die an ein bestimmtes Gerät gebunden sind.
DiscardDeviceResources Gibt die geräteabhängigen Ressourcen frei, nachdem sie nicht mehr benötigt werden.
DrawD2DContent Verwendet Direct2D zum Rendern auf dem Bildschirm.
Drawtext Zeichnet die Textzeichenfolge mithilfe von Direct2D.
Onresize Ändert die Größe des Direct2D-Renderziels , wenn die Fenstergröße geändert wird.

 

Sie können das bereitgestellte Beispiel verwenden oder die folgenden Anweisungen verwenden, um Ihrer eigenen Win32-Anwendung DirectWrite und Direct2D hinzuzufügen. Weitere Informationen zum Beispiel und den zugehörigen Projektdateien finden Sie im DirectWrite HelloWorld.

Zeichnen von einfachem Text

In diesem Abschnitt wird gezeigt, wie Sie DirectWrite und Direct2D verwenden, um einfachen Text mit einem einzelnen Format zu rendern, wie im folgenden Screenshot gezeigt.

Screenshot von

Für das Zeichnen von einfachem Text auf den Bildschirm sind vier Komponenten erforderlich:

  • Eine zu renderde Zeichenfolge.
  • Eine instance von IDWriteTextFormat.
  • Die Dimensionen des Bereichs, der den Text enthalten soll.
  • Ein -Objekt, das den Text rendern kann. In diesem Tutorial Sie verwenden ein Direct2D-Renderziel .

Die IDWriteTextFormat-Schnittstelle beschreibt den Namen, die Größe, die Gewichtung, die Formatvorlage und die Streckung, die zum Formatieren von Text verwendet werden, und beschreibt Gebietsschemainformationen. IDWriteTextFormat definiert auch Methoden zum Festlegen und Abrufen der folgenden Eigenschaften:

  • Der Zeilenabstand.
  • Die Textausrichtung relativ zum linken und rechten Rand des Layoutfelds.
  • Die Absatzausrichtung relativ zum oberen und unteren Rand des Layoutfelds.
  • Die Leserichtung.
  • Die Textkürzungsgranularität für Text, der das Layoutfeld überläuft.
  • Der inkrementelle Tabstopp.
  • Die Absatzflussrichtung.

Die IDWriteTextFormat-Schnittstelle ist zum Zeichnen von Text erforderlich, der beide der in diesem Dokument beschriebenen Prozesse verwendet.

Bevor Sie ein IDWriteTextFormat-Objekt oder ein anderes DirectWrite-Objekt erstellen können, benötigen Sie eine IDWriteFactory-instance. Sie verwenden eine IDWriteFactory, um IDWriteTextFormat-Instanzen und andere DirectWrite-Objekte zu erstellen. Verwenden Sie die Funktion DWriteCreateFactory, um eine Factory-instance zu erhalten.

Teil 1: Deklarieren von DirectWrite und Direct2D-Ressourcen.

In diesem Teil deklarieren Sie die Objekte, die Sie später zum Erstellen und Anzeigen von Text als private Datenmember Ihrer Klasse verwenden werden. Alle Schnittstellen, Funktionen und Datentypen für DirectWrite werden in der Dwrite.h-Headerdatei deklariert, und diejenigen für Direct2D werden in d2d1.h deklariert. Wenn Sie dies noch nicht getan haben, schließen Sie diese Header in Ihr Projekt ein.

  1. Deklarieren Sie in der Klassenheaderdatei (SimpleText.h) Zeiger auf die Schnittstellen IDWriteFactory und IDWriteTextFormat als private Member.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. Deklarieren Sie Member, um die zu rendernde Textzeichenfolge und die Länge der Zeichenfolge zu enthalten.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Deklarieren Sie Zeiger auf die Schnittstellen ID2D1Factory, ID2D1HwndRenderTarget und ID2D1SolidColorBrush zum Rendern des Texts mit Direct2D.

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

Teil 2: Erstellen geräteunabhängiger Ressourcen.

Direct2D bietet zwei Arten von Ressourcen: geräteabhängige Ressourcen und geräteunabhängige Ressourcen. Geräteabhängige Ressourcen sind einem Renderinggerät zugeordnet und funktionieren nicht mehr, wenn dieses Gerät entfernt wird. Geräteunabhängige Ressourcen hingegen können für den Bereich Ihrer Anwendung gültig sein.

DirectWrite Ressourcen sind geräteunabhängig.

In diesem Abschnitt erstellen Sie die geräteunabhängigen Ressourcen, die von Ihrer Anwendung verwendet werden. Diese Ressourcen müssen durch einen Aufruf der Release-Methode der -Schnittstelle freigegeben werden.

Einige der verwendeten Ressourcen müssen nur einmal erstellt werden und sind nicht an ein Gerät gebunden. Die Initialisierung für diese Ressourcen wird in die SimpleText::CreateDeviceIndependentResources-Methode eingefügt, die beim Initialisieren der Klasse aufgerufen wird.

  1. Rufen Sie in der SimpleText::CreateDeviceIndependentResources-Methode in der Klassenimplementierungsdatei (SimpleText.cpp) die Funktion D2D1CreateFactory auf, um eine ID2D1Factory-Schnittstelle zu erstellen, bei der es sich um die Stammfactoryschnittstelle für alle Direct2D-Objekte handelt. Sie verwenden dieselbe Factory, um andere Direct2D-Ressourcen zu instanziieren.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. Rufen Sie die DWriteCreateFactory-Funktion auf, um eine IDWriteFactory-Schnittstelle zu erstellen, bei der es sich um die Stammfactoryschnittstelle für alle DirectWrite-Objekte handelt. Sie verwenden dieselbe Factory, um andere DirectWrite Ressourcen zu instanziieren.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. Initialisieren Sie die Textzeichenfolge, und speichern Sie ihre Länge.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. Erstellen Sie mithilfe der IDWriteFactory::CreateTextFormat-Methode ein IDWriteTextFormat-Schnittstellenobjekt. IdWriteTextFormat gibt die Schriftart, die Gewichtung, die Streckung, das Format und das Gebietsschema an, die zum Rendern der Textzeichenfolge verwendet werden.

    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. Zentrieren Sie den Text horizontal und vertikal, indem Sie die Methoden IDWriteTextFormat::SetTextAlignment und IDWriteTextFormat::SetParagraphAlignment aufrufen.

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

In diesem Teil haben Sie die geräteunabhängigen Ressourcen initialisiert, die von Ihrer Anwendung verwendet werden. Im nächsten Teil initialisieren Sie die geräteabhängigen Ressourcen.

Teil 3: Erstellen Device-Dependent Ressourcen.

In diesem Teil erstellen Sie eine ID2D1HwndRenderTarget und eine ID2D1SolidColorBrush zum Rendern des Texts.

Ein Renderziel ist ein Direct2D-Objekt, das Zeichnungsressourcen erstellt und Zeichnungsbefehle auf einem Renderinggerät rendert. Ein ID2D1HwndRenderTarget ist ein Renderziel, das in einem HWND gerendert wird.

Eine der Zeichnungsressourcen, die ein Renderziel erstellen kann, ist ein Pinsel zum Zeichnen von Konturen, Füllungen und Text. Ein ID2D1SolidColorBrush zeichnet mit einer Volltonfarbe.

Sowohl die SCHNITTSTELLEN ID2D1HwndRenderTarget und ID2D1SolidColorBrush sind bei der Erstellung an ein Renderinggerät gebunden, müssen freigegeben und neu erstellt werden, wenn das Gerät ungültig wird.

  1. Überprüfen Sie in der SimpleText::CreateDeviceResources-Methode, ob der Renderzielzeiger NULL ist. Wenn dies der Grund ist, rufen Sie die Größe des Renderbereichs ab, und erstellen Sie ein ID2D1HwndRenderTarget dieser Größe. Verwenden Sie ID2D1HwndRenderTarget , um einen ID2D1SolidColorBrush zu erstellen.

    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. Geben Sie in der SimpleText::D iscardDeviceResources-Methode sowohl den Pinsel als auch das Renderziel frei.

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

Nachdem Sie nun ein Renderziel und einen Pinsel erstellt haben, können Sie sie verwenden, um Ihren Text zu rendern.

Teil 4: Zeichnen von Text mithilfe der Direct2D DrawText-Methode.

  1. Definieren Sie in der SimpleText::D rawText-Methode Ihrer -Klasse den Bereich für das Textlayout, indem Sie die Dimensionen des Renderingbereichs abrufen, und erstellen Sie ein Direct2D-Rechteck mit den gleichen Dimensionen.

    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. Verwenden Sie die ID2D1RenderTarget::D rawText-Methode und das IDWriteTextFormat-Objekt , um Text auf dem Bildschirm zu rendern. Die ID2D1RenderTarget::D rawText-Methode verwendet die folgenden Parameter:

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

Teil 5: Rendern des Fensterinhalts mithilfe von Direct2D

Gehen Sie wie folgt vor, um den Inhalt des Fensters mithilfe von Direct2D zu rendern, wenn eine Paint-Nachricht empfangen wird:

  1. Erstellen Sie die geräteabhängigen Ressourcen, indem Sie die in Teil 3 implementierte SimpleText::CreateDeviceResources-Methode aufrufen.
  2. Rufen Sie die ID2D1HwndRenderTarget::BeginDraw-Methode des Renderziels auf.
  3. Löschen Sie das Renderziel, indem Sie die ID2D1HwndRenderTarget::Clear-Methode aufrufen.
  4. Rufen Sie die in Teil 4 implementierte SimpleText::D rawText-Methode auf.
  5. Rufen Sie die ID2D1HwndRenderTarget::EndDraw-Methode des Renderziels auf.
  6. Verwerfen Sie bei Bedarf die geräteabhängigen Ressourcen, damit sie neu erstellt werden können, wenn das Fenster neu gezeichnet wird.
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();
}

Die SimpleText-Klasse ist in SimpleText.h und SimpleText.cpp implementiert.

Zeichnen von Text mit mehreren Formaten.

In diesem Abschnitt wird gezeigt, wie Sie DirectWrite und Direct2D verwenden, um Text mit mehreren Formaten zu rendern, wie im folgenden Screenshot gezeigt.

Screenshot von

Der Code für diesen Abschnitt wird als MultiformattedText-Klasse im DirectWrite HelloWorld implementiert. Sie basiert auf den Schritten aus dem vorherigen Abschnitt.

Um mehrformatierten Text zu erstellen, verwenden Sie die IDWriteTextLayout-Schnittstelle zusätzlich zur IDWriteTextFormat-Schnittstelle , die im vorherigen Abschnitt eingeführt wurde. Die IDWriteTextLayout-Schnittstelle beschreibt die Formatierung und das Layout eines Textblocks. Zusätzlich zur Standardformatierung, die von einem IDWriteTextFormat-Objekt angegeben wird, kann die Formatierung für bestimmte Textbereiche mithilfe von IDWriteTextLayout geändert werden. Dazu gehören Name der Schriftfamilie, Größe, Gewichtung, Stil, Strecken, Durchstreichen und Unterstreichen.

IDWriteTextLayout bietet auch Methoden zum Testen von Treffern. Die von diesen Methoden zurückgegebenen Treffertestmetriken sind relativ zum Layoutfeld, das angegeben wird, wenn das IDWriteTextLayout-Schnittstellenobjekt mithilfe der CreateTextLayout-Methode der IDWriteFactory-Schnittstelle erstellt wird.

Die IDWriteTypography-Schnittstelle wird verwendet, um einem Textlayout optionale typografische OpenType-Features hinzuzufügen, z. B. Swashes und alternative stilistische Textsätze. Typografische Features können einem bestimmten Textbereich innerhalb eines Textlayouts hinzugefügt werden, indem die AddFontFeature-Methode der IDWriteTypography-Schnittstelle aufgerufen wird. Diese Methode empfängt eine DWRITE_FONT_FEATURE-Struktur als Parameter, der eine DWRITE_FONT_FEATURE_TAG-Enumerationskonstante und einen UINT32-Ausführungsparameter enthält. Eine Liste der registrierten OpenType-Features finden Sie in der OpenType Layout Tag Registry auf microsoft.com. Die entsprechenden DirectWrite-Enumerationskonstanten finden Sie unter DWRITE_FONT_FEATURE_TAG.

Teil 1: Erstellen einer IDWriteTextLayout-Schnittstelle.

  1. Deklarieren Sie einen Zeiger auf eine IDWriteTextLayout-Schnittstelle als Member der MultiformattedText-Klasse.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. Erstellen Sie am Ende der MultiformattedText::CreateDeviceIndependentResources-Methode ein IDWriteTextLayout-Schnittstellenobjekt , indem Sie die CreateTextLayout-Methode aufrufen. Die IDWriteTextLayout-Schnittstelle bietet zusätzliche Formatierungsfeatures, z. B. die Möglichkeit, auf ausgewählte Textteile verschiedene Formate anzuwenden.

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

Teil 2: Anwenden der Formatierung mit IDWriteTextLayout.

Formatierungen wie Schriftgrad, Gewichtung und Unterstreichung können auf Teilzeichenfolgen des Texts angewendet werden, die mithilfe der IDWriteTextLayout-Schnittstelle angezeigt werden sollen.

  1. Legen Sie den Schriftgrad für die Teilzeichenfolge "Di" von "DirectWrite" auf 100 fest, indem Sie eine DWRITE_TEXT_RANGE deklarieren und die IDWriteTextLayout::SetFontSize-Methode aufrufen.

    // 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. Unterstreichen Sie die Teilzeichenfolge "DirectWrite", indem Sie die IDWriteTextLayout::SetUnderline-Methode aufrufen.

    // 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. Legen Sie die Schriftstärke für die Teilzeichenfolge "DirectWrite" auf fett fest, indem Sie die IDWriteTextLayout::SetFontWeight-Methode aufrufen.

    if (SUCCEEDED(hr))
    {
        // Format the word "DWrite" to be bold.
        DWRITE_TEXT_RANGE textRange = {20,
                                       11 };
        hr = pTextLayout_->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, textRange);
    }
    

Teil 3: Hinzufügen von typografischen Features mit IDWriteTypography.

  1. Deklarieren und erstellen Sie ein IDWriteTypography-Schnittstellenobjekt , indem Sie die IDWriteFactory::CreateTypography-Methode aufrufen.

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. Fügen Sie ein Schriftartfeature hinzu, indem Sie ein DWRITE_FONT_FEATURE-Objekt deklarieren, für das der Stilsatz 7 angegeben ist, und die IDWriteTypography::AddFontFeature-Methode aufrufen.

    // Set the stylistic set.
    DWRITE_FONT_FEATURE fontFeature = {DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7,
                                       1};
    if (SUCCEEDED(hr))
    {
        hr = pTypography->AddFontFeature(fontFeature);
    }
    
    
  3. Legen Sie das Textlayout so fest, dass die Typografie für die gesamte Zeichenfolge verwendet wird, indem Sie eine DWRITE_TEXT_RANGE Variable deklarieren und die IDWriteTextLayout::SetTypography-Methode aufrufen und den Textbereich übergeben.

    if (SUCCEEDED(hr))
    {
        // Set the typography for the entire string.
        DWRITE_TEXT_RANGE textRange = {0,
                                       cTextLength_};
        hr = pTextLayout_->SetTypography(pTypography, textRange);
    }
    
    
  4. Legen Sie die neue Breite und Höhe für das Textlayoutobjekt in der MultiformattedText::OnResize-Methode fest.

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

Teil 4: Zeichnen von Text mit der Direct2D DrawTextLayout-Methode.

Um den Text mit den textlayout-Einstellungen zu zeichnen, die vom IDWriteTextLayout-Objekt angegeben werden, ändern Sie den Code in der MultiformattedText::D rawText-Methode, um IDWriteTextLayout::D rawTextLayout zu verwenden.

  1. Entsorgen Sie eine D2D1_POINT_2F Variable, und legen Sie sie auf den oberen linken Punkt des Fensters fest.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Zeichnen Sie den Text auf den Bildschirm, indem Sie die ID2D1RenderTarget::D rawTextLayout-Methode des Direct2D-Renderziels aufrufen und den Zeiger IDWriteTextLayout übergeben.

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

Die MultiformattedText-Klasse ist in MultiformattedText.h und MultiformattedText.cpp implementiert.