Delen via


Zelfstudie: Aan de slag met DirectWrite

In dit document ziet u hoe u DirectWrite- en Direct2D- gebruikt om eenvoudige tekst te maken die één opmaak bevat en vervolgens tekst met meerdere indelingen.

Deze zelfstudie bevat de volgende onderdelen:

Broncode

De broncode die in dit overzicht wordt weergegeven, is afkomstig uit het DirectWrite Hello World-voorbeeld. Elk onderdeel wordt geïmplementeerd in een afzonderlijke klasse (SimpleText en MultiformattedText) en wordt weergegeven in een afzonderlijk onderliggend venster. Elke klasse vertegenwoordigt een Microsoft Win32-venster. Naast de methode WndProc bevat elke klasse de volgende methoden:

Functie Beschrijving
CreateDeviceIndependentResources Hiermee maakt u resources die onafhankelijk zijn van het apparaat, zodat ze overal opnieuw kunnen worden gebruikt.
VerwijderApparaatonafhankelijkeHulpbronnen Hiermee worden de apparaatonafhankelijke resources vrijgegeven nadat ze niet meer nodig zijn.
CreateDeviceResources Hiermee maakt u hulpmiddelen, zoals borstels en rendering-doelen, die zijn gekoppeld aan een bepaald apparaat.
DiscardDeviceResources Hiermee worden de apparaatafhankelijke resources vrijgegeven nadat ze niet meer nodig zijn.
DrawD2DContent Gebruikt Direct2D om op het scherm weer te geven.
DrawText Hiermee tekent u de tekenreeks met Direct2D-.
OnResize Hiermee wijzigt u het formaat van het Direct2D renderdoel wanneer de venstergrootte wordt gewijzigd.

 

U kunt het opgegeven voorbeeld gebruiken of de volgende instructies gebruiken om DirectWrite- en Direct2D- toe te voegen aan uw eigen Win32-toepassing. Zie de DirectWrite HelloWorldvoor meer informatie over het voorbeeld en de bijbehorende projectbestanden.

Eenvoudige tekst tekenen

In deze sectie ziet u hoe u DirectWrite en Direct2D- gebruikt om eenvoudige tekst met één indeling weer te geven, zoals wordt weergegeven in de volgende schermafbeelding.

schermafbeelding van 'hello world using directwrite!' in een enkel formaat

Voor het tekenen van eenvoudige tekst naar het scherm zijn vier onderdelen vereist:

  • Een tekenreeks die moet worden weergegeven.
  • Een exemplaar van IDWriteTextFormat.
  • De afmetingen van het gebied dat de tekst bevat.
  • Een object dat de tekst kan weergeven. In deze zelfstudie. u gebruikt een Direct2D renderdoel.

De IDWriteTextFormat interface beschrijft de lettertypefamilienaam, grootte, dikte, stijl en stretch die worden gebruikt om tekst op te maken en beschrijft de landinstellingen. IDWriteTextFormat definieert ook methoden voor het instellen en ophalen van de volgende eigenschappen:

  • De regelafstand.
  • De tekstuitlijning ten opzichte van de linker- en rechterrand van het indelingsvak.
  • De alinea-uitlijning ten opzichte van de boven- en onderkant van het indelingsvak.
  • De leesrichting.
  • De fijnheid van teksttrimming voor tekst die het indelingsvak overschrijdt.
  • De incrementele tabpositie.
  • De richting van de alinea-opmaak.

De interface IDWriteTextFormat is vereist voor het tekenen van tekst die gebruikmaakt van beide processen die in dit document worden beschreven.

Voordat u een IDWriteTextFormat-object of een ander DirectWrite-object kunt maken, hebt u een IDWriteFactory-exemplaar nodig. U gebruikt een IDWriteFactory- om IDWriteTextFormat-exemplaren en andere DirectWrite-objecten te maken. Als u een factory-exemplaar wilt verkrijgen, gebruikt u de functie DWriteCreateFactory.

Deel 1: DirectWrite en Direct2D-resources declareren.

In dit deel declareert u de objecten die u later gaat gebruiken voor het maken en weergeven van tekst als persoonlijke gegevensleden van uw klas. Alle interfaces, functies en gegevenstypen voor DirectWrite- worden gedeclareerd in het dwrite.h headerbestand en die voor Direct2D- worden gedeclareerd in de d2d1.h; Als u dit nog niet hebt gedaan, neemt u deze headers op in uw project.

  1. Declareer in het klasseheaderbestand (SimpleText.h) de aanwijzers naar IDWriteFactory en IDWriteTextFormat interfaces als privéleden.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. Declareer elementen om de tekststring weer te geven en de lengte van de string te bewaren.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Declareer pointers naar ID2D1Factory, ID2D1HwndRenderTarget, en ID2D1SolidColorBrush-interfaces voor het weergeven van de tekst met Direct2D.

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

Deel 2: Apparaatonafhankelijke resources maken.

Direct2D- biedt twee typen resources: apparaatafhankelijke resources en apparaatonafhankelijke resources. Apparaatafhankelijke resources zijn gekoppeld aan een renderingapparaat en werken niet meer als dat apparaat wordt verwijderd. Apparaatonafhankelijke resources kunnen daarentegen meegaan gedurende de levensduur van uw toepassing.

DirectWrite resources zijn apparaatonafhankelijk.

In deze sectie maakt u de apparaatonafhankelijke resources die door uw toepassing worden gebruikt. Deze resources moeten worden vrijgemaakt met een aanroep naar de Release methode van de interface.

Sommige resources die worden gebruikt, moeten slechts één keer worden gemaakt en zijn niet gekoppeld aan een apparaat. De initialisatie voor deze resources wordt in de SimpleText::CreateDeviceIndependentResources methode geplaatst, die wordt aangeroepen bij het initialiseren van de klasse.

  1. Roep in de SimpleText::CreateDeviceIndependentResources methode in het klasse-implementatiebestand (SimpleText.cpp) de D2D1CreateFactory--functie aan om een ID2D1Factory--interface te maken. Dit is de hoofdfactory-interface voor alle Direct2D--objecten. U gebruikt dezelfde fabriek om andere Direct2D-resources te instantiëren.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. Roep de DWriteCreateFactory--functie aan om een IDWriteFactory-interface te maken. Dit is de hoofdfactory-interface voor alle DirectWrite--objecten. U gebruikt dezelfde factory om andere DirectWrite-resources te instantiëren.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. Initialiseer de tekenreeks en sla de lengte op.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. Maak een IDWriteTextFormat interfaceobject met behulp van de methode IDWriteFactory::CreateTextFormat. De IDWriteTextFormat geeft het lettertype, gewicht, stretch, stijl en landinstellingen op die worden gebruikt om de tekenreeks weer te geven.

    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. Centreer de tekst horizontaal en verticaal door de IDWriteTextFormat::SetTextAlignment- en IDWriteTextFormat::SetParagraphAlignment-methoden aan te roepen.

    // 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 dit deel hebt u de apparaatonafhankelijke resources geïnitialiseerd die door uw toepassing worden gebruikt. In het volgende gedeelte initialiseert u de apparaatafhankelijke resources.

Deel 3: Device-Dependent Resources maken.

In dit deel maakt u een ID2D1HwndRenderTarget- en een ID2D1SolidColorBrush- voor het weergeven van uw tekst.

Een renderdoel is een Direct2D-object waarmee tekenbronnen worden gemaakt en tekenopdrachten worden weergegeven op een renderingapparaat. Een ID2D1HwndRenderTarget is een renderdoel dat wordt weergegeven op een HWND-.

Een van de tekenbronnen die een renderdoelobject kan maken, is een kwast voor het tekenen van contouren, opvullingen en tekst. Een ID2D1SolidColorBrush verft met een effen kleur.

Zowel de ID2D1HwndRenderTarget als de ID2D1SolidColorBrush interfaces zijn gebonden aan een renderingapparaat wanneer ze worden gemaakt en moeten worden vrijgegeven en opnieuw worden gemaakt als het apparaat ongeldig wordt.

  1. Controleer in de methode SimpleText::CreateDeviceResources of het renderdoelwit op de aanwijzer NULLstaat. Als dat zo is, haalt u de grootte van het rendergebied op en maakt u een ID2D1HwndRenderTarget van die grootte. Gebruik de ID2D1HwndRenderTarget om een ID2D1SolidColorBrushte maken.

    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. Laat in de methode SimpleText::DiscardDeviceResources zowel de penselen als het renderdoel vrij.

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

Nu u een renderdoel en een kwast hebt gemaakt, kunt u deze gebruiken om uw tekst weer te geven.

Deel 4: Tekst tekenen met behulp van de methode Direct2D DrawText.

  1. Definieer in de methode SimpleText::D rawText van uw klasse het gebied voor de tekstindeling door de afmetingen van het weergavegebied op te halen en een Direct2D- rechthoek met dezelfde afmetingen te maken.

    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. Gebruik de methode ID2D1RenderTarget::DrawText en het object IDWriteTextFormat om tekst weer te geven op het scherm. De methode ID2D1RenderTarget::DrawText gebruikt de volgende parameters:

    • Een tekenreeks die moet worden weergegeven.
    • Een aanwijzer naar een IDWriteTextFormat interface.
    • Een Direct2D lay-out rechthoek.
    • Een aanwijzer naar een interface die ID2D1Brush-beschikbaar maakt.
    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.
        );
    
    

Deel 5: De inhoud van het venster weergeven met Direct2D

Ga als volgt te werk om de inhoud van het venster weer te geven met behulp van Direct2D- wanneer een verfbericht wordt ontvangen:

  1. Maak de apparaatspecifieke resources aan door de methode SimpleText::CreateDeviceResources aan te roepen, die is geïmplementeerd in deel 3.
  2. Roep de ID2D1HwndRenderTarget::BeginDraw-methode van het renderdoel aan.
  3. Wis het renderdoel door de methode ID2D1HwndRenderTarget::Clear aan te roepen.
  4. Roep de methode SimpleText::DrawText aan, geïmplementeerd in Deel 4.
  5. Roep de ID2D1HwndRenderTarget::EndDraw-methode van het renderdoel aan.
  6. Als dat nodig is, verwijdert u de apparaatafhankelijke resources zodat ze opnieuw kunnen worden gemaakt wanneer het venster opnieuw wordt getekend.
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();
}

De klasse SimpleText is geïmplementeerd in SimpleText.h en SimpleText.cpp.

Tekst vormgeven met meerdere stijlen.

In deze sectie ziet u hoe u DirectWrite- en Direct2D- kunt gebruiken om tekst met meerdere indelingen weer te geven, zoals wordt weergegeven in de volgende schermafbeelding.

schermafbeelding van 'hallo wereld met directwrite!', met enkele onderdelen in verschillende stijlen, grootten en indelingen

De code voor deze sectie wordt geïmplementeerd als de klasse MultiformattedText in de DirectWrite HelloWorld-. Deze is gebaseerd op de stappen uit de vorige sectie.

Als u tekst met meerdere opmaak wilt maken, gebruikt u de interface IDWriteTextLayout naast de interface IDWriteTextFormat interface die in de vorige sectie is geïntroduceerd. De interface IDWriteTextLayout beschrijft de opmaak en indeling van een tekstblok. Naast de standaardopmaak die is opgegeven door een IDWriteTextFormat object, kan de opmaak voor specifieke tekstbereiken worden gewijzigd met behulp van IDWriteTextLayout-. Dit omvat de naam van de lettertypefamilie, grootte, gewicht, stijl, stretch, doorhalen en onderstrepen.

IDWriteTextLayout- biedt ook methoden voor hittests. De hit-testmetrische gegevens die door deze methoden worden geretourneerd, zijn relatief aan het indelingsvak dat wordt opgegeven wanneer het IDWriteTextLayout--interfaceobject wordt aangemaakt met behulp van de CreateTextLayout---methode van de IDWriteFactory---interface.

De interface IDWriteTypography wordt gebruikt om optionele OpenType- typografische kenmerken toe te voegen aan een tekstindeling, zoals swashes en alternatieve stijltekstsets. Typografische functies kunnen worden toegevoegd aan een bepaald tekstbereik binnen een tekstindeling door de AddFontFeature-methode aan te roepen methode van de IDWriteTypography interface. Deze methode ontvangt een DWRITE_FONT_FEATURE structuur als een parameter die een DWRITE_FONT_FEATURE_TAG opsommingsconstante en een UINT32-uitvoeringsparameter bevat. Een lijst met geregistreerde OpenType-functies vindt u in het OpenType Layout Tag Registry op microsoft.com. Zie DWRITE_FONT_FEATURE_TAGvoor de equivalente DirectWrite-opsommingsconstanten.

Deel 1: Een IDWriteTextLayout-interface maken.

  1. Declareer een aanwijzer naar een IDWriteTextLayout interface als lid van de klasse MultiformattedText.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. Maak aan het einde van de methode MultiformattedText::CreateDeviceIndependentResources een IDWriteTextLayout- interfaceobject door de methode CreateTextLayout aan te roepen. De interface IDWriteTextLayout biedt extra opmaakfuncties, zoals de mogelijkheid om verschillende indelingen toe te passen op geselecteerde delen van tekst.

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

Deel 2: Opmaak toepassen met IDWriteTextLayout.

Opmaak, zoals de tekengrootte, dikte en onderstreping, kan worden toegepast op subtekenreeksen van de tekst die moeten worden weergegeven met behulp van de interface IDWriteTextLayout.

  1. Stel de tekengrootte voor de subtekenreeks 'Di' van 'DirectWrite' in op 100 door een DWRITE_TEXT_RANGE te declareren en de methode IDWriteTextLayout::SetFontSize aan te roepen.

    // 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. Onderstreping van de subtekenreeks DirectWrite door de methode IDWriteTextLayout::SetUnderline aan te roepen.

    // 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. Stel het lettertypegewicht van de subtekenreeks 'DirectWrite' in op vet door de methode IDWriteTextLayout::SetFontWeight aan te roepen.

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

Deel 3: Typografische functies toevoegen met IDWriteTypography.

  1. Declareer en maak een IDWriteTypography interfaceobject door de methode IDWriteFactory::CreateTypography aan te roepen.

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. Voeg een lettertypefunctie toe door een DWRITE_FONT_FEATURE object te declareren waarbij stijlset 7 is opgegeven en de methode IDWriteTypography::AddFontFeature aan te roepen.

    // Set the stylistic set.
    DWRITE_FONT_FEATURE fontFeature = {DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7,
                                       1};
    if (SUCCEEDED(hr))
    {
        hr = pTypography->AddFontFeature(fontFeature);
    }
    
    
  3. Stel de tekstindeling in om de typografie over de hele tekenreeks te gebruiken door een DWRITE_TEXT_RANGE variabele te declareren en de IDWriteTextLayout::SetTypography methode aan te roepen en het tekstbereik door te geven.

    if (SUCCEEDED(hr))
    {
        // Set the typography for the entire string.
        DWRITE_TEXT_RANGE textRange = {0,
                                       cTextLength_};
        hr = pTextLayout_->SetTypography(pTypography, textRange);
    }
    
    
  4. Stel de nieuwe breedte en hoogte in voor het tekstindelingsobject in de methode MultiformattedText::OnResize.

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

Deel 4: Tekst tekenen met de methode Direct2D DrawTextLayout.

Als u de tekst wilt tekenen met de tekstindelingsinstellingen die zijn opgegeven door het IDWriteTextLayout-object, wijzigt u de code in de methode MultiformattedText::DrawText om IDWriteTextLayout::DrawTextLayoutte gebruiken.

  1. Declareer een D2D1_POINT_2F variabele en stel deze in op het linkerbovenhoek van het venster.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Teken de tekst naar het scherm door de methode ID2D1RenderTarget::D rawTextLayout methode van de Direct2D- renderdoel aan te roepen en de IDWriteTextLayout- aanwijzer door te geven.

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

De klasse MultiformattedText is geïmplementeerd in MultiformattedText.h en MultiformattedText.cpp.