Condividi tramite


Guida Introduttiva a DirectWrite

Questo documento illustra come usare DirectWrite e Direct2D per creare testo semplice contenente un singolo formato e quindi testo che contiene più formati.

Questa esercitazione contiene le parti seguenti:

Codice sorgente

Il codice sorgente illustrato in questa panoramica è tratto dall'esempio DirectWrite Hello World. Ogni parte viene implementata in una classe separata (SimpleText e MultiformattedText) e viene visualizzata in una finestra figlio separata. Ogni classe rappresenta una finestra di Microsoft Win32. Oltre al metodo WndProc, ogni classe contiene i metodi seguenti:

Funzione Descrizione
CreateDeviceIndependentResources Crea risorse indipendenti dal dispositivo, in modo che possano essere riutilizzate ovunque.
DiscardDeviceIndependentResources Rilascia le risorse indipendenti dal dispositivo dopo che non sono più necessarie.
CreateDeviceResources Crea risorse, ad esempio pennelli e destinazioni di rendering, associate a un determinato dispositivo.
DiscardDeviceResources Rilascia le risorse dipendenti dal dispositivo dopo che non sono più necessarie.
DrawD2DContent Usa Direct2D per eseguire il rendering sullo schermo.
DrawText Disegna la stringa di testo usando Direct2D.
OnResize Ridimensiona la destinazione di rendering Direct2D quando viene modificata la dimensione della finestra.

 

Puoi usare l'esempio fornito o usare le istruzioni seguenti per aggiungere DirectWrite e Direct2D alla tua applicazione Win32. Per altre informazioni sull'esempio e sui file di progetto associati, vedere DirectWrite HelloWorld.

Disegno di testo semplice

Questa sezione illustra come usare DirectWrite e Direct2D per eseguire il rendering di testo semplice con un unico formato, come illustrato nella schermata seguente.

screenshot di

Il disegno di testo semplice sullo schermo richiede quattro componenti:

  • Stringa di caratteri di cui eseguire il rendering.
  • Istanza di IDWriteTextFormat.
  • Dimensioni dell'area in cui contenere il testo.
  • Oggetto che può eseguire il rendering del testo. In questa esercitazione. si usa una destinazione di rendering Direct2D.

L'interfaccia IDWriteTextFormat descrive il nome della famiglia di caratteri, le dimensioni, lo spessore, lo stile e l'estensione usati per formattare il testo e descrive le informazioni sulle impostazioni locali. IDWriteTextFormat definisce anche i metodi per l'impostazione e il recupero delle proprietà seguenti:

  • Spaziatura linea.
  • Allineamento del testo rispetto ai bordi sinistro e destro della casella di layout.
  • Allineamento del paragrafo rispetto alla parte superiore e inferiore della casella di layout.
  • Direzione di lettura.
  • Granularità del ritaglio del testo che eccede i limiti della casella di layout.
  • Tabulazione incrementale.
  • Direzione del flusso del paragrafo.

L'interfaccia IDWriteTextFormat è necessaria per il disegno di testo che utilizza entrambi i processi descritti in questo documento.

Prima di poter creare un oggettoIDWriteTextFormato qualsiasi altro oggetto DirectWrite, è necessaria un'istanza diIDWriteFactory. Si utilizza un IDWriteFactory per creare istanze di IDWriteTextFormat e altri oggetti DirectWrite. Per ottenere un'istanza factory, usare la funzione DWriteCreateFactory.

Parte 1: Dichiarare le risorse DirectWrite e Direct2D.

In questa parte si dichiarano gli oggetti che verranno usati in un secondo momento per creare e visualizzare testo come membri dati privati della classe. Tutte le interfacce, le funzioni e i tipi di dati per DirectWrite vengono dichiarate nel file di intestazione dwrite.h e quelle per Direct2D vengono dichiarate nel d2d1.h ; se non è già stato fatto, includere queste intestazioni nel progetto.

  1. Nel file di intestazione della classe (SimpleText.h), dichiarare i puntatori alle interfacce IDWriteFactory e IDWriteTextFormat come membri privati.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. Dichiara i membri per contenere la stringa di testo da visualizzare e la lunghezza della stringa.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Dichiarare i puntatori alle interfacce ID2D1Factory, ID2D1HwndRenderTargete ID2D1SolidColorBrush per il rendering del testo con Direct2D.

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

Parte 2: Creare risorse indipendenti dal dispositivo.

direct2D fornisce due tipi di risorse: risorse dipendenti dal dispositivo e risorse indipendenti dal dispositivo. Le risorse dipendenti dal dispositivo sono associate a un dispositivo di rendering e non funzionano più se il dispositivo viene rimosso. Le risorse indipendenti dal dispositivo, d'altra parte, possono durare per l'ambito dell'applicazione.

le risorse DirectWrite sono indipendenti dal dispositivo.

In questa sezione vengono create le risorse indipendenti dal dispositivo usate dall'applicazione. Queste risorse devono essere liberate con una chiamata al metodo Release dell'interfaccia.

Alcune delle risorse usate devono essere create una sola volta e non sono associate a un dispositivo. L'inizializzazione per queste risorse viene inserita nel metodo SimpleText::CreateDeviceIndependentResources, che viene chiamato durante l'inizializzazione della classe.

  1. All'interno del metodo SimpleText::CreateDeviceIndependentResources nel file di implementazione della classe (SimpleText.cpp), chiamare la funzione D2D1CreateFactory per creare un'interfaccia ID2D1Factory, che è l'interfaccia radice della factory per tutti gli oggetti Direct2D. Utilizzi la stessa factory per instanziare altre risorse Direct2D.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. Chiamare la funzione DWriteCreateFactory per creare un'interfaccia IDWriteFactory, ovvero l'interfaccia factory principale per tutti gli oggetti DirectWrite. Si utilizza la stessa factory per istanziare altre risorse DirectWrite.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. Inizializzare la stringa di testo e archiviarne la lunghezza.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. Creare un oggetto interfaccia IDWriteTextFormat utilizzando il metodo IDWriteFactory::CreateTextFormat. Il IDWriteTextFormat specifica il tipo di carattere, lo spessore, lo stile e le impostazioni locali che verranno utilizzate per eseguire il rendering della stringa di testo.

    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. Centrare il testo orizzontalmente e verticalmente chiamando i metodi 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);
    }
    
    

In questa parte sono state inizializzate le risorse indipendenti dal dispositivo usate dall'applicazione. Nella parte successiva si inizializzano le risorse dipendenti dal dispositivo.

Parte 3: Creare risorse Device-Dependent.

In questa parte viene creato un ID2D1HwndRenderTarget e un ID2D1SolidColorBrush per il rendering del testo.

Una destinazione di rendering è un oggetto Direct2D che crea risorse di disegno ed esegue il rendering dei comandi di disegno in un dispositivo di rendering. Un ID2D1HwndRenderTarget è una destinazione di rendering che esegue il rendering in un HWND.

Una delle risorse di disegno che una destinazione di rendering può creare è un pennello per disegnare contorni, riempimenti e testo. Oggetto ID2D1SolidColorBrush disegna con un colore a tinta unita.

Sia il ID2D1HwndRenderTarget che le interfacce ID2D1SolidColorBrush sono associate a un dispositivo di rendering quando vengono create e devono essere rilasciate e ricreate se il dispositivo non è valido.

  1. All'interno del metodo SimpleText::CreateDeviceResources, verificare se il puntatore del target di rendering è NULL. In caso affermativo, recuperare le dimensioni dell'area di rendering e creare un ID2D1HwndRenderTarget di tale dimensione. Usare il ID2D1HwndRenderTarget per creare 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. Nel metodo SimpleText::DiscardDeviceResources, rilasciate sia il pennello che la destinazione di rendering.

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

Dopo aver creato una destinazione di rendering e un pennello, è possibile usarle per eseguire il rendering del testo.

Parte 4: Disegnare testo utilizzando il metodo DrawText Direct2D.

  1. Nel metodo SimpleText::DrawText della tua classe, definire l'area per il layout del testo, recuperando le dimensioni dell'area di rendering, e creare un rettangolo Direct2D con le stesse dimensioni.

    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. Utilizzare il metodo ID2D1RenderTarget::DrawText e l'oggetto IDWriteTextFormat per eseguire il rendering del testo sullo schermo. Il metodo ID2D1RenderTarget::DrawText accetta i parametri seguenti:

    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: Eseguire il rendering del contenuto della finestra usando Direct2D

Per eseguire il rendering del contenuto della finestra utilizzando Direct2D quando viene ricevuto un messaggio di disegno, eseguire le operazioni seguenti:

  1. Creare le risorse dipendenti dal dispositivo chiamando il metodo SimpleText::CreateDeviceResources implementato nella parte 3.
  2. Chiamare il metodo ID2D1HwndRenderTarget::BeginDraw della destinazione di rendering.
  3. Cancellare la destinazione di rendering chiamando il metodo ID2D1HwndRenderTarget::Clear.
  4. Chiamare il metodo SimpleText::DrawText, implementato nella parte 4.
  5. Chiamare il metodo ID2D1HwndRenderTarget::EndDraw della destinazione di rendering.
  6. Se necessario, rimuovere le risorse dipendenti dal dispositivo in modo che possano essere ricreate quando la finestra viene ridisegnata.
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 viene implementata in SimpleText.h e SimpleText.cpp.

Disegno di testo con più formati.

Questa sezione illustra come usare DirectWrite e Direct2D per eseguire il rendering del testo con più formati, come illustrato nella schermata seguente.

schermata di

Il codice per questa sezione viene implementato come classe MultiformattedText nella DirectWrite HelloWorld. Si basa sui passaggi della sezione precedente.

Per creare testo in più formati, usare l'interfacciaIDWriteTextLayoutoltre all'interfaccia IDWriteTextFormat introdotta nella sezione precedente. L'interfaccia IDWriteTextLayout descrive la formattazione e il layout di un blocco di testo. Oltre alla formattazione predefinita specificata da un oggetto IDWriteTextFormat, la formattazione per intervalli di testo specifici può essere modificata usando IDWriteTextLayout. Sono inclusi il nome della famiglia di caratteri, le dimensioni, lo spessore, lo stile, l'estensione, il barrato e la sottolineatura.

IDWriteTextLayout fornisce anche metodi di hit testing. Le metriche di hit testing restituite da questi metodi sono relative alla casella di layout specificata quando l'oggetto interfaccia IDWriteTextLayout viene creato usando il metodocreateTextLayoutdell'interfacciaIDWriteFactory.

L'interfaccia IDWriteTypography viene usata per aggiungere OpenType caratteristiche tipografiche a un layout di testo, ad esempio lavaggi e set di testo stilistici alternativi. Le funzionalità tipografiche possono essere aggiunte a un intervallo specifico di testo all'interno di un layout di testo chiamando il metodoaddFontFeaturedell'interfaccia IDWriteTypography. Questo metodo riceve una struttura DWRITE_FONT_FEATURE come parametro che contiene una costante di enumerazione DWRITE_FONT_FEATURE_TAG e un parametro di esecuzione UINT32. Un elenco delle funzionalità OpenType registrate è disponibile nel OpenType Layout Tag Registry su microsoft.com. Per le costanti di enumerazione DirectWrite equivalenti, vedere DWRITE_FONT_FEATURE_TAG.

Parte 1: Creare un'interfaccia IDWriteTextLayout.

  1. Dichiarare un puntatore all'interfaccia IDWriteTextLayout come membro della classe MultiformattedText.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. Alla fine del metodo MultiformattedText::CreateDeviceIndependentResources creare un oggetto interfaccia IDWriteTextLayout chiamando il metodo CreateTextLayout. L'interfaccia IDWriteTextLayout fornisce funzionalità di formattazione aggiuntive, ad esempio la possibilità di applicare formati diversi alle parti selezionate del testo.

    // 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: Applicazione della formattazione con IDWriteTextLayout.

La formattazione, ad esempio la dimensione del carattere, lo spessore e la sottolineatura, può essere applicata alle sottostringhe del testo da visualizzare usando l'interfaccia IDWriteTextLayout.

  1. Impostare la dimensione del carattere per la sottostringa "Di" di "DirectWrite" su 100 dichiarando un DWRITE_TEXT_RANGE e chiamando il metodo 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. Sottolineare la sottostringa "DirectWrite" chiamando il metodo 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. Impostare lo spessore del carattere su grassetto per la sottostringa "DirectWrite" chiamando il metodo 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: Aggiunta di funzionalità tipografiche con IDWriteTypography.

  1. Dichiarare e creare un oggetto interfacciaIDWriteTypographychiamando il metodo IDWriteFactory::CreateTypography.

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. Aggiungere una funzionalità del tipo di carattere dichiarando un oggetto DWRITE_FONT_FEATURE con il set stilistico 7 specificato e chiamando il metodo 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. Impostare il layout di testo per usare la tipografia sull'intera stringa dichiarando una variabile DWRITE_TEXT_RANGE e chiamando il metodo IDWriteTextLayout::SetTypography e passando l'intervallo di testo.

    if (SUCCEEDED(hr))
    {
        // Set the typography for the entire string.
        DWRITE_TEXT_RANGE textRange = {0,
                                       cTextLength_};
        hr = pTextLayout_->SetTypography(pTypography, textRange);
    }
    
    
  4. Impostare la nuova larghezza e l'altezza per l'oggetto layout di testo nel metodo MultiformattedText::OnResize.

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

Parte 4: Disegnare testo usando il metodo DrawTextLayout Direct2D.

Per disegnare il testo con le impostazioni di layout del testo specificate dall'oggetto IDWriteTextLayout, modificare il codice nel metodo MultiformattedText::DrawText per usare IDWriteTextLayout::DrawTextLayout.

  1. Delcare una variabile D2D1_POINT_2F e impostarla sul punto superiore sinistro della finestra.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Disegnare il testo sullo schermo chiamando il metodo ID2D1RenderTarget::DrawTextLayout del Direct2D destinazione di render e passando il puntatore IDWriteTextLayout.

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

La classe MultiformattedText viene implementata in MultiformattedText.h e MultiformattedText.cpp.