教學課程:使用 DirectWrite 進行消費者入門

本檔說明如何使用DirectWriteDirect2D來建立包含單一格式的簡單文字,以及包含多個格式的文字。

本教學課程包含下列部分:

原始程式碼

本概觀中顯示的原始程式碼取自DirectWrite Hello World範例。 每個元件都會在不同的類別中實作 (SimpleText 和 MultiformattedText) ,並顯示在個別的子視窗中。 每個類別都代表 Microsoft Win32 視窗。 除了 WndProc 方法之外,每個類別還包含下列方法:

函式 描述
CreateDeviceIndependentResources 建立與裝置無關的資源,使其可以在任何地方重複使用。
DiscardDeviceIndependentResources 不再需要裝置獨立資源之後釋出它們。
CreateDeviceResources 建立系結至特定裝置的資源,例如筆刷和轉譯目標。
DiscardDeviceResources 不再需要裝置相依資源之後釋放它們。
DrawD2DContent 使用 Direct2D 轉譯至畫面。
DrawText 使用 Direct2D繪製文字字串。
OnResize 變更視窗大小時,調整 Direct2D 轉譯目標的大小。

 

您可以使用提供的範例,或使用下列指示,將DirectWriteDirect2D新增至您自己的 Win32 應用程式。 如需範例和相關專案檔的詳細資訊,請參閱DirectWrite HelloWorld

繪製簡單文字

本節說明如何使用DirectWriteDirect2D來轉譯具有單一格式的簡單文字,如下列螢幕擷取畫面所示。

以單一格式使用 directwrite!「 的 」hello world「 螢幕擷取畫面

將簡單的文字繪製到畫面需要四個元件:

  • 要呈現的字元字串。
  • IDWriteTextFormat的實例。
  • 要包含文字的區域維度。
  • 可以轉譯文字的物件。 在本教學課程中。 您使用 Direct2D 轉譯目標。

IDWriteTextFormat介面描述用來格式化文字的字型系列名稱、大小、粗細、樣式和延展,並描述地區設定資訊。 IDWriteTextFormat 也會定義設定和取得下列屬性的方法:

  • 行距。
  • 相對於版面配置方塊左邊緣和右邊緣的文字對齊方式。
  • 相對於版面配置方塊頂端和底部的段落對齊方式。
  • 閱讀方向。
  • 超出版面配置方塊之文字的文字修剪細微性。
  • 累加定位停駐點。
  • 段落流程方向。

需要 IDWriteTextFormat 介面,才能使用本檔中所述的兩個處理常式來繪製文字。

您必須先有IDWriteFactory實例,才能建立IDWriteTextFormat物件或任何其他DirectWrite物件。 您可以使用IDWriteFactory來建立IDWriteTextFormat實例和其他DirectWrite物件。 若要取得 Factory 實例,請使用 DWriteCreateFactory 函式

第 1 部分:宣告DirectWrite和 Direct2D 資源。

在此部分中,您會宣告稍後將用來建立及顯示文字作為類別私人資料成員的物件。 DirectWrite的所有介面、函式和資料類型都會在dwrite.h標頭檔中宣告,而Direct2D的介面、函式和資料類型都會在d2d1.h中宣告;如果您尚未這麼做,請將這些標頭包含在專案中。

  1. 在類別標頭檔中 (SimpleText.h) ,將 IDWriteFactoryIDWriteTextFormat 介面的指標宣告為私用成員。

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. 宣告成員以保存要呈現的文字字串,以及字串的長度。

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. 宣告 ID2D1FactoryID2D1HwndRenderTargetID2D1SolidColorBrush 介面的指標,以 使用 Direct2D轉譯文字。

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

第 2 部分:建立裝置獨立資源。

Direct2D 提供兩種類型的資源:裝置相依資源和裝置獨立資源。 裝置相依資源與轉譯裝置相關聯,如果移除該裝置,則不再運作。 另一方面,裝置獨立資源可以持續用於應用程式的範圍。

DirectWrite資源與裝置無關。

在本節中,您會建立應用程式所使用的裝置獨立資源。 這些資源必須透過呼叫 介面的 Release 方法釋放。

某些所使用的資源只需要建立一次,且不會系結至裝置。 這些資源的初始化會放在 SimpleText::CreateDeviceIndependentResources 方法中,這個方法會在初始化類別時呼叫。

  1. 在類別實作檔案中的 SimpleText::CreateDeviceIndependentResources 方法內, (SimpleText.cpp) ,呼叫 D2D1CreateFactory 函式來建立 ID2D1Factory 介面,這是所有 Direct2D 物件的根處理站介面。 您可以使用相同的處理站來具現化其他 Direct2D 資源。

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. 呼叫DWriteCreateFactory函式來建立IDWriteFactory介面,這是所有DirectWrite物件的根處理站介面。 您可以使用相同的處理站來具現化其他DirectWrite資源。

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. 初始化文字字串,並儲存其長度。

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. 使用IDWriteFactory::CreateTextFormat方法建立IDWriteTextFormat介面物件。 IDWriteTextFormat會指定將用來呈現文字字串的字型、粗細、延展、樣式和地區設定。

    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. 呼叫 IDWriteTextFormat::SetTextAlignmentIDWriteTextFormat::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);
    }
    
    

在此部分中,您已初始化應用程式所使用的裝置獨立資源。 在下一個部分中,您會初始化裝置相依資源。

第 3 部分:建立 Device-Dependent 資源。

在此部分中,您會建立 ID2D1HwndRenderTargetID2D1SolidColorBrush 來轉譯文字。

轉譯目標是 Direct2D 物件,可建立繪圖資源,並將繪圖命令轉譯至轉譯裝置。 ID2D1HwndRenderTarget是轉譯成HWND的轉譯目標。

轉譯目標可以建立的其中一個繪圖資源是繪製外框、填滿和文字的筆刷。 ID2D1SolidColorBrush會以純色繪製。

ID2D1HwndRenderTargetID2D1SolidColorBrush介面都會在建立時系結至轉譯裝置,而且如果裝置無效,則必須釋出並重新建立。

  1. 在 SimpleText::CreateDeviceResources 方法內,檢查轉譯目標指標是否為 Null。 如果是,請擷取轉譯區域的大小,並建立該大小的 ID2D1HwndRenderTarget 。 使用 ID2D1HwndRenderTarget 來建立 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. 在 SimpleText::D iscardDeviceResources 方法中,釋放筆刷和轉譯目標。

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

現在您已建立轉譯目標和筆刷,您可以使用它們來轉譯文字。

第 4 部分:使用 Direct2D DrawText 方法繪製文字。

  1. 在 類別的 SimpleText::D rawText 方法中,擷取轉譯區域的維度,並建立具有相同維度的 Direct2D 矩形,以定義文字版面配置的區域。

    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. 使用 ID2D1RenderTarget::D rawText 方法和 IDWriteTextFormat 物件將文字轉譯到畫面。 ID2D1RenderTarget::D rawText方法會採用下列參數:

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

第 5 部分:使用 Direct2D 轉譯視窗內容

若要在收到繪製訊息時使用 Direct2D 來轉譯視窗的內容,請執行下列動作:

  1. 呼叫第 3 部分中實作的 SimpleText::CreateDeviceResources 方法來建立裝置相依資源。
  2. 呼叫轉譯目標的 ID2D1HwndRenderTarget::BeginDraw 方法。
  3. 呼叫 ID2D1HwndRenderTarget::Clear 方法來清除轉譯目標。
  4. 呼叫第 4 部分中實作的 SimpleText::D rawText 方法。
  5. 呼叫轉譯目標的 ID2D1HwndRenderTarget::EndDraw 方法。
  6. 如有必要,請捨棄裝置相依資源,以便在重新繪製視窗時重新建立它們。
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();
}

SimpleText 類別是在 SimpleText.h 和 SimpleText.cpp 中實作。

使用多種格式繪製文字。

本節說明如何使用DirectWriteDirect2D來轉譯具有多種格式的文字,如下列螢幕擷取畫面所示。

「hello world using directwrite!」的螢幕擷取畫面,具有不同樣式、大小和格式的某些部分

本節的程式碼會實作為DirectWrite HelloWorld中的MultiformattedText類別。 其以上一節中的步驟為基礎。

若要建立多格式文字,除了上一節中引進的IDWriteTextFormat介面之外,您還可以使用IDWriteTextLayout介面。 IDWriteTextLayout介面描述文字區塊的格式和配置。 除了 IDWriteTextFormat 物件所指定的預設格式設定之外,可以使用 IDWriteTextLayout來變更特定文字範圍的格式設定。 這包括字型系列名稱、大小、粗細、樣式、延展、刪除線和底線。

IDWriteTextLayout 也提供點擊測試方法。 這些方法所傳回的點擊測試計量會相對於使用IDWriteFactory介面的CreateTextLayout方法建立IDWriteTextLayout介面物件時所指定的配置方塊。

IDWriteTypography介面可用來將選擇性的 OpenType印刷樣式功能新增至文字版面配置,例如 swashes 和替代文體文字集。 您可以藉由呼叫IDWriteTypography介面的AddFontFeature方法,將印刷樣式功能新增至文字版面配置內的特定文字範圍。 這個方法會接收 DWRITE_FONT_FEATURE 結構做為參數,其中包含 DWRITE_FONT_FEATURE_TAG 列舉常數和 UINT32 執行參數。 您可以在 microsoft.com 上的 OpenType 版面配置標籤登錄 中找到已註冊的 OpenType 功能清單。 如需對等DirectWrite列舉常數,請參閱DWRITE_FONT_FEATURE_TAG

第 1 部分:建立 IDWriteTextLayout 介面。

  1. IDWriteTextLayout 介面的指標宣告為 MultiformattedText 類別的成員。

    IDWriteTextLayout* pTextLayout_;
    
    
  2. 在 MultiformattedText::CreateDeviceIndependentResources 方法的結尾,呼叫CreateTextLayout方法建立IDWriteTextLayout介面物件。 IDWriteTextLayout介面會提供額外的格式功能,例如能夠將不同格式套用至選取的文字部分。

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

第 2 部分:使用 IDWriteTextLayout 套用格式設定。

格式設定,例如字型大小、粗細和底線,可以套用至使用 IDWriteTextLayout 介面顯示之文字的子字串。

  1. 藉由宣告DWRITE_TEXT_RANGE並呼叫IDWriteTextLayout::SetFontSize方法,將 「DirectWrite」 的子字串 「Di」 字型大小設定為 100。

    // 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. 呼叫IDWriteTextLayout::SetUnderline方法,在子字串 「DirectWrite」 加上底線。

    // 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. 呼叫IDWriteTextLayout::SetFontWeight方法,將子字串 「DirectWrite」 的字型粗細設定為粗體。

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

第 3 部分:使用 IDWriteTypography 新增印刷樣式功能。

  1. 呼叫IDWriteFactory::CreateTypography方法,宣告並建立IDWriteTypography介面物件。

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. 宣告已指定樣式集 7 並呼叫IDWriteTypography::AddFontFeature方法的DWRITE_FONT_FEATURE物件,以新增字型功能。

    // Set the stylistic set.
    DWRITE_FONT_FEATURE fontFeature = {DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7,
                                       1};
    if (SUCCEEDED(hr))
    {
        hr = pTypography->AddFontFeature(fontFeature);
    }
    
    
  3. 藉由宣告 DWRITE_TEXT_RANGE 變數並呼叫 IDWriteTextLayout::SetTypography 方法並傳入文字範圍,將文字配置設定為使用整個字串的印刷樣式。

    if (SUCCEEDED(hr))
    {
        // Set the typography for the entire string.
        DWRITE_TEXT_RANGE textRange = {0,
                                       cTextLength_};
        hr = pTextLayout_->SetTypography(pTypography, textRange);
    }
    
    
  4. 在 MultiformattedText::OnResize 方法中設定文字設定物件的新寬度和高度。

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

第 4 部分:使用 Direct2D DrawTextLayout 方法繪製文字。

若要使用 IDWriteTextLayout 物件所指定的文字版面配置設定繪製文字,請將 MultiformattedText::D rawText 方法中的程式碼變更為使用 IDWriteTextLayout::D rawTextLayout

  1. Delcare D2D1_POINT_2F變數 並將它設定為視窗的左上角點。

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. 呼叫Direct2D轉譯目標的ID2D1RenderTarget::D rawTextLayout方法並傳遞IDWriteTextLayout指標,將文字繪製到畫面。

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

MultiformattedText 類別是在 MultiformattedText.h 和 MultiformattedText.cpp 中實作。