Dela via


Hur man lägger till infogade objekt i en textlayout

Innehåller en kort självstudiekurs om hur du lägger till infogade objekt i ett DirectWrite--program som visar text med hjälp av IDWriteTextLayout--gränssnittet.

Slutprodukten av den här handledningen är en applikation som visar text med en infogad bild, enligt följande skärmbild.

skärmbild av

Den här självstudien innehåller följande delar:

Steg 1: Skapa en textlayout.

Till att börja med behöver du ett program med ett IDWriteTextLayout--objekt. Om du redan har ett program som visar text med en textlayout går du vidare till Steg 2.

Om du vill lägga till en textlayout måste du göra följande:

  1. Deklarera en pekare till ett IDWriteTextLayout- gränssnitt som medlem av klassen.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. I slutet av metoden CreateDeviceIndependentResources skapar du ett IDWriteTextLayout- gränssnittsobjekt genom att anropa metoden CreateTextLayout.

    // 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.
            );
    }
    
    
  3. Sedan måste du ändra anropet till metoden ID2D1RenderTarget::DrawText till ID2D1RenderTarget::DrawTextLayout, som visas i följande kod.

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

Steg 2: Definiera en klass som härleds från gränssnittet IDWriteInlineObject.

Stöd för infogade objekt i DirectWrite- tillhandahålls av gränssnittet IDWriteInlineObject. Om du vill använda infogade objekt måste du implementera det här gränssnittet. Den hanterar ritningen av det infogade objektet, samt tillhandahåller mått och annan information till renderaren.

Skapa en ny rubrikfil och deklarera ett gränssnitt med namnet InlineImage, härlett från IDWriteInlineObject.

Förutom QueryInterface, AddRef och Release som ärvts från IUnknown måste den här klassen ha följande metoder:

Steg 3: Implementera den infogade objektklassen.

Skapa en ny C++-fil med namnet InlineImage.cpp för klassimplementeringen. Förutom metoden LoadBitmapFromFile och metoderna som ärvs från gränssnittet IUnknown består klassen InlineImage av följande metoder.

Konstruktorn.

InlineImage::InlineImage(
    ID2D1RenderTarget *pRenderTarget, 
    IWICImagingFactory *pIWICFactory,
    PCWSTR uri
    )
{
    // Save the render target for later.
    pRT_ = pRenderTarget;

    pRT_->AddRef();

    // Load the bitmap from a file.
    LoadBitmapFromFile(
        pRenderTarget,
        pIWICFactory,
        uri,
        &pBitmap_
        );
}

Det första argumentet för konstruktorn är ID2D1RenderTarget som den infogade avbildningen återges till. Detta lagras för användning senare vid ritning.

Återgivningsmålet IWICImagingFactory och filnamns-uri skickas alla till metoden LoadBitmapFromFile som läser in bitmappen och lagrar bitmappsstorleken (bredd och höjd) i rect_ medlemsvariabeln.

Metoden för dragning.

Metoden Draw är ett återanrop som anropas av objektet IDWriteTextRenderer när det infogade objektet måste ritas. Textlayouten anropar inte den här metoden direkt.

HRESULT STDMETHODCALLTYPE InlineImage::Draw(
    __maybenull void* clientDrawingContext,
    IDWriteTextRenderer* renderer,
    FLOAT originX,
    FLOAT originY,
    BOOL isSideways,
    BOOL isRightToLeft,
    IUnknown* clientDrawingEffect
    )
{
    float height    = rect_.bottom - rect_.top;
    float width     = rect_.right  - rect_.left;
    D2D1_RECT_F destRect  = {originX, originY, originX + width, originY + height};

    pRT_->DrawBitmap(pBitmap_, destRect);

    return S_OK;
}

I det här fallet ritas bitmappen med hjälp av metoden ID2D1RenderTarget::DrawBitmap; alla metoder för ritning kan dock användas.

GetMetrics-metoden.

HRESULT STDMETHODCALLTYPE InlineImage::GetMetrics(
    __out DWRITE_INLINE_OBJECT_METRICS* metrics
    )
{
    DWRITE_INLINE_OBJECT_METRICS inlineMetrics = {};
    inlineMetrics.width     = rect_.right  - rect_.left;
    inlineMetrics.height    = rect_.bottom - rect_.top;
    inlineMetrics.baseline  = baseline_;
    *metrics = inlineMetrics;
    return S_OK;
}

För metoden GetMetrics lagrar du bredd, höjd och baslinje i en DWRITE_INLINE_OBJECT_METRICS struktur. IDWriteTextLayout anropar den här återanropsfunktionen för att hämta mätningen av det infogade objektet.

Metoden GetOverhangMetrics.

HRESULT STDMETHODCALLTYPE InlineImage::GetOverhangMetrics(
    __out DWRITE_OVERHANG_METRICS* overhangs
    )
{
    overhangs->left      = 0;
    overhangs->top       = 0;
    overhangs->right     = 0;
    overhangs->bottom    = 0;
    return S_OK;
}

I det här fallet krävs inget överhäng, så metoden GetOverhangMetrics returnerar alla nollor.

Metoden GetBreakConditions.

HRESULT STDMETHODCALLTYPE InlineImage::GetBreakConditions(
    __out DWRITE_BREAK_CONDITION* breakConditionBefore,
    __out DWRITE_BREAK_CONDITION* breakConditionAfter
    )
{
    *breakConditionBefore = DWRITE_BREAK_CONDITION_NEUTRAL;
    *breakConditionAfter  = DWRITE_BREAK_CONDITION_NEUTRAL;
    return S_OK;
}

Steg 4: Skapa en instans av klassen InlineImage och lägg till den i textlayouten.

I metoden CreateDeviceDependentResources skapar du slutligen en instans av klassen InlineImage och lägger till den i textlayouten. Eftersom den innehåller en referens till ID2D1RenderTarget, som är en enhetsberoende resurs, och ID2D1Bitmap skapas med hjälp av återgivningsmålet, är InlineImage också enhetsberoende och måste återskapas om återgivningsmålet återskapas.

// Create an InlineObject.
pInlineImage_ = new InlineImage(pRT_, pWICFactory_, L"img1.jpg");

DWRITE_TEXT_RANGE textRange = {14, 1};

pTextLayout_->SetInlineObject(pInlineImage_, textRange);

Metoden IDWriteTextLayout::SetInlineObject tar en textområdesstruktur. Objektet gäller för det intervall som anges här, och all text i intervallet ignoreras. Om längden på textområdet är 0 ritas inte objektet.

I det här exemplet finns det en asterisk (*) som platshållare i den position där bilden visas.

// The string to display.  The '*' character will be suppressed by our image.
wszText_ = L"Inline Object * Example";
cTextLength_ = wcslen(wszText_);

Eftersom klassen InlineImage är beroende av ID2D1RenderTargetmåste du släppa den när du släpper återgivningsmålet.

SafeRelease(&pInlineImage_);