このドキュメントでは、DirectWrite と direct2D を使用して、1 つの形式を含む単純なテキストを作成し、複数の形式を含むテキストを作成する方法について説明します。
このチュートリアルには、次の部分が含まれています。
ソースコード
この概要に示されているソース コードは、 DirectWrite Hello World サンプルから取得します。 各パーツは個別のクラス (SimpleText と MultiformattedText) で実装され、個別の子ウィンドウに表示されます。 各クラスは、Microsoft Win32 ウィンドウを表します。 WndProc メソッドに加えて、各クラスには次のメソッドが含まれています。
機能 | 説明 |
---|---|
CreateDeviceIndependentResources | 任意の場所で再利用できるように、デバイスに依存しないリソースを作成します。 |
デバイス非依存リソースを破棄する | 不要になったデバイスに依存しないリソースを解放します。 |
CreateDeviceResources | 特定のデバイスに関連付けられているリソース (ブラシやレンダー ターゲットなど) を作成します。 |
DiscardDeviceResources | 不要になったデバイス依存リソースを解放します。 |
DrawD2DContent | Direct2D を使用して画面にレンダリングします。 |
DrawText | Direct2D を使用してテキスト文字列を描画します。 |
OnResize | ウィンドウ サイズが変更されたときに Direct2D レンダー ターゲットのサイズを変更します。 |
提供されているサンプルを使用することも、次の手順に従って DirectWrite と Direct2D を独自の Win32 アプリケーションに追加することもできます。 サンプルと関連するプロジェクト ファイルの詳細については、 DirectWrite HelloWorld を参照してください。
単純なテキストの描画
このセクションでは、 DirectWrite と Direct2D を使用して、次のスクリーン ショットに示すように、1 つの形式の単純なテキストをレンダリングする方法を示します。
画面に単純なテキストを描画するには、次の 4 つのコンポーネントが必要です。
- レンダリングする文字列。
- IDWriteTextFormat のインスタンス。
- テキストを格納する領域の寸法。
- テキストをレンダリングできるオブジェクト。 このチュートリアルでは、次の操作を行います。 Direct2D レンダー ターゲットを使用します。
IDWriteTextFormat インターフェイスは、テキストの書式設定に使用されるフォント ファミリ名、サイズ、重み、スタイル、およびストレッチを記述し、ロケール情報を記述します。 IDWriteTextFormat では、次のプロパティを設定および取得するためのメソッドも定義されています。
- 行間。
- レイアウト ボックスの左端と右端を基準としたテキストの配置。
- レイアウト ボックスの上下を基準とした段落の配置。
- 読み取り方向。
- レイアウトボックスからオーバーフローするテキストに対するトリミングの細かさ。
- 増分タブストップ。
- パラグラフの流れの方向。
このドキュメントで説明されている両方のプロセスを使用するテキストを描画するには、 IDWriteTextFormat インターフェイスが必要です。
IDWriteTextFormat オブジェクトまたはその他の DirectWrite オブジェクトを作成する前に、IDWriteFactory インスタンスが必要です。 IDWriteFactory を使用して、IDWriteTextFormat インスタンスとその他の DirectWrite オブジェクトを作成します。 ファクトリ インスタンスを取得するには、 DWriteCreateFactory 関数を 使用します。
パート 1: DirectWrite リソースと Direct2D リソースを宣言する。
このパートでは、後でクラスのプライベート データ メンバーとしてテキストを作成および表示するために使用するオブジェクトを宣言します。 DirectWrite のすべてのインターフェイス、関数、およびデータ型は dwrite.h ヘッダー ファイルで宣言され、Direct2D のインターフェイス、関数、およびデータ型は d2d1.h で宣言されます。まだ行っていない場合は、これらのヘッダーをプロジェクトに含めます。
クラス ヘッダー ファイル (SimpleText.h) で、 IDWriteFactory インターフェイスと IDWriteTextFormat インターフェイスへのポインターをプライベート メンバーとして宣言します。
IDWriteFactory* pDWriteFactory_; IDWriteTextFormat* pTextFormat_;
表示するテキスト文字列と文字列の長さを保持するメンバーを宣言します。
const wchar_t* wszText_; UINT32 cTextLength_;
Direct2D でテキストをレンダリングするための ID2D1Factory、ID2D1HwndRenderTarget、および ID2D1SolidColorBrush インターフェイスへのポインターを宣言します。
ID2D1Factory* pD2DFactory_; ID2D1HwndRenderTarget* pRT_; ID2D1SolidColorBrush* pBlackBrush_;
パート 2: デバイスに依存しないリソースを作成する。
Direct2D には、デバイス依存リソースとデバイスに依存しないリソースの 2 種類のリソースが用意されています。 デバイスに依存するリソースはレンダリング デバイスに関連付けられ、そのデバイスが削除された場合は機能しなくなります。 一方、デバイスに依存しないリソースは、アプリケーション全体のスコープで使用可能です。
DirectWrite リソースはデバイスに依存しません。
このセクションでは、アプリケーションで使用されるデバイスに依存しないリソースを作成します。 これらのリソースは、インターフェイスの Release メソッドを呼び出して解放する必要があります。
使用されるリソースの一部は、1 回だけ作成する必要があり、デバイスに関連付けられません。 これらのリソースの初期化は、クラスの初期化時に呼び出される SimpleText::CreateDeviceIndependentResources メソッドに格納されます。
クラス実装ファイル (SimpleText.cpp) の SimpleText::CreateDeviceIndependentResources メソッド内で、D2D1CreateFactory 関数を呼び出して、すべての Direct2D オブジェクトのルート ファクトリ インターフェイスである ID2D1Factory インターフェイスを作成します。 同じファクトリを使用して、他の Direct2D リソースをインスタンス化します。
hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory_ );
DWriteCreateFactory 関数を呼び出して、すべての DirectWrite オブジェクトのルート ファクトリ インターフェイスである IDWriteFactory インターフェイスを作成します。 同じファクトリを使用して、他の DirectWrite リソースをインスタンス化します。
if (SUCCEEDED(hr)) { hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDWriteFactory_) ); }
テキスト文字列を初期化し、その長さを格納します。
wszText_ = L"Hello World using DirectWrite!"; cTextLength_ = (UINT32) wcslen(wszText_);
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_ ); }
IDWriteTextFormat::SetTextAlignment メソッドと 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); }
このパートでは、アプリケーションで使用されるデバイスに依存しないリソースを初期化しました。 次のパートでは、デバイスに依存するリソースを初期化します。
パート 3: Device-Dependent リソースを作成する。
このパートでは、テキストをレンダリングするための ID2D1HwndRenderTarget と ID2D1SolidColorBrush を作成します。
レンダー ターゲットは、描画リソースを作成し、描画コマンドをレンダリング デバイスにレンダリングする Direct2D オブジェクトです。 ID2D1HwndRenderTarget は、HWND にレンダリングするレンダー ターゲットです。
レンダー ターゲットで作成できる描画リソースの 1 つは、アウトライン、塗りつぶし、テキストを描画するためのブラシです。 ID2D1SolidColorBrush は、単色の色で塗ります。
ID2D1HwndRenderTarget インターフェイスと ID2D1SolidColorBrush インターフェイスはどちらも作成時にレンダリング デバイスにバインドされ、デバイスが無効になった場合は解放して再作成する必要があります。
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_ ); } }
SimpleText::D iscardDeviceResources メソッドで、ブラシとレンダー ターゲットの両方を解放します。
SafeRelease(&pRT_); SafeRelease(&pBlackBrush_);
レンダー ターゲットとブラシを作成したら、それらを使用してテキストをレンダリングできます。
パート 4: Direct2D DrawText メソッドを使用してテキストを描画する。
クラスの 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_ );
ID2D1RenderTarget::D rawText メソッドと IDWriteTextFormat オブジェクトを使用して、テキストを画面にレンダリングします。 ID2D1RenderTarget::D rawText メソッドは、次のパラメーターを受け取ります。
- レンダリングする文字列。
- IDWriteTextFormat インターフェイスへのポインター。
- Direct2D レイアウトの四角形。
- ID2D1Brush を公開するインターフェイスへのポインター。
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 を使用してウィンドウの内容をレンダリングするには、次の操作を行います。
- パート 3 で実装されている SimpleText::CreateDeviceResources メソッドを呼び出して、デバイス依存リソースを作成します。
- レンダー ターゲットの ID2D1HwndRenderTarget::BeginDraw メソッドを呼び出します。
- ID2D1HwndRenderTarget::Clear メソッドを呼び出して、レンダー ターゲットをクリアします。
- パート 4 で実装されている SimpleText::DrawText メソッドを呼び出します。
- レンダー ターゲットの ID2D1HwndRenderTarget::EndDraw メソッドを呼び出します。
- 必要に応じて、ウィンドウの再描画時に再作成できるように、デバイス依存リソースを破棄します。
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 で実装されます。
複数の形式でテキストを描画します。
このセクションでは、次のスクリーン ショットに示すように、 DirectWrite と Direct2D を使用して複数の形式のテキストをレンダリングする方法を示します。
このセクションのコードは、DirectWrite HelloWorld の MultiformattedText クラスとして実装されています。 これは、前のセクションの手順に基づいています。
複数形式のテキストを作成するには、前のセクションで導入した IDWriteTextFormat インターフェイスに加えて 、IDWriteTextLayout インターフェイスを使用します。 IDWriteTextLayout インターフェイスは、テキスト ブロックの書式設定とレイアウトを記述します。 IDWriteTextFormat オブジェクトで指定された既定の書式設定に加えて、IDWriteTextLayout を使用して、特定のテキスト範囲の書式設定を変更できます。 これには、フォント ファミリ名、サイズ、太さ、スタイル、ストレッチ、取り消し線、下線が含まれます。
IDWriteTextLayout には、ヒット テスト メソッドも用意されています。 これらのメソッドによって返されるヒット テスト メトリックは、IDWriteTextLayout インターフェイス オブジェクトが IDWriteFactory インターフェイスの CreateTextLayout メソッドを使用して作成されるときに指定されたレイアウト ボックスに対して相対的です。
IDWriteTypography インターフェイスは、オプションの OpenType 文字体裁機能をテキスト レイアウト (スワッシュや代替スタイル テキスト セットなど) に追加するために使用されます。 IDWriteTypography インターフェイスの AddFontFeature メソッドを呼び出すことで、文字体裁機能をテキスト レイアウト内の特定のテキスト範囲に追加できます。 このメソッドは、DWRITE_FONT_FEATURE_TAG列挙定数と UINT32 実行パラメーターを含むパラメーターとしてDWRITE_FONT_FEATURE構造体を受け取ります。 登録されている OpenType 機能の一覧は、microsoft.com の OpenType レイアウト タグ レジストリ にあります。 同等の DirectWrite 列挙定数については、 DWRITE_FONT_FEATURE_TAGを参照してください。
パート 1: IDWriteTextLayout インターフェイスを作成します。
MULTIformattedText クラスのメンバーとして IDWriteTextLayout インターフェイスへのポインターを宣言します。
IDWriteTextLayout* pTextLayout_;
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 インターフェイスを使用して表示するテキストの部分文字列に適用できます。
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); }
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); }
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 を使用した文字体裁機能の追加。
IDWriteFactory::CreateTypography メソッドを呼び出して、IDWriteTypography インターフェイス オブジェクトを宣言して作成します。
// Declare a typography pointer. IDWriteTypography* pTypography = NULL; // Create a typography interface object. if (SUCCEEDED(hr)) { hr = pDWriteFactory_->CreateTypography(&pTypography); }
スタイル セット 7 が指定されている DWRITE_FONT_FEATURE オブジェクトを宣言し、 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); }
文字列全体で文字体裁を使用するようにテキスト レイアウトを設定するには、 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); }
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 を使用します。
D2D1_POINT_2F変数を宣言し、ウィンドウの左上のポイントに設定します。
D2D1_POINT_2F origin = D2D1::Point2F( static_cast<FLOAT>(rc.left / dpiScaleX_), static_cast<FLOAT>(rc.top / dpiScaleY_) );
Direct2D レンダー ターゲットの ID2D1RenderTarget::D rawTextLayout メソッドを呼び出し、IDWriteTextLayout ポインターを渡して、テキストを画面に描画します。
pRT_->DrawTextLayout( origin, pTextLayout_, pBlackBrush_ );
MultiformattedText クラスは MultiformattedText.h および MultiformattedText.cpp で実装されます。