2015-01-20 20 views
1

我渲染使用Direct2D的文本開頭的文本佈局的Direct2D CreateTextLayout() - 如何獲得插入符座標

HRESULT hr = m_spWriteFactory->CreateTextLayout(
     m_wsText.c_str(), 
     m_wsText.length(), 
     m_spWriteTextFormat.Get(), 
     m_rect.right - m_rect.left - m_spacing.right - m_spacing.left, 
     m_rect.bottom - m_rect.top - m_spacing.top - m_spacing.bottom, 
     &m_spTextLayout 
     ); 

,然後將其渲染爲位圖這是我後來與Direct3D的

m_sp2DDeviceContext->DrawTextLayout(
       D2D1::Point2F(m_spacing.left, m_spacing.top), 
       m_spTextLayout.Get(), 
       m_spTextBrush.Get() 
       ); 
使用

我想畫一條簡單的薄閃光線作爲插入符號。我知道如何繪製線條,以及如何使其出現/消失。

問題:如何獲得我的脫字符線的起點和終點座標?

簡化:如果它是很容易假定文本僅由一個線,那麼這就是確定。但是,當然更讚賞一個更通用的解決方案。

+0

什麼'm_spTextLayout.GetMetrics()'? [DWRITE_TEXT_METRICS結構](https://msdn.microsoft.com/en-us/library/windows/desktop/dd368135(v = vs.85).aspx) – 2015-01-21 07:42:08

回答

-1

您可以通過IDWriteTextLayout::GetMetrics獲取佈局的邊界矩形。

DWRITE_TEXT_METRICS textMetrics; 
    textLayout->GetMetrics(&textMetrics); 

你的矩形

D2D1::RectF(textMetrics.left, 
       textMetrics.top, 
       textMetrics.left + textMetrics.width, 
       textMetrics.top + textMetrics.height); 

然後你就可以繪製插入符號沿着右邊界線。

+0

如果我有一個文本「一些文本」,第二個指示我想將光標放在「some te」的位置,非單色間距字體的文本是否以相同的方式佈置,以便我可以使用第二個文本使用您建議的方法繪製光標? – NOhs 2015-01-22 15:09:08

+0

是的,等寬或不等,這會給你正確的方框。 – 2015-01-22 18:49:20

+1

這個答案是完全錯誤的,它根本不回答問題。問題是關於插入位置,而不是文本邊界。 – Andrew 2017-04-30 04:41:42

7

使用IDWriteTextLayout的命中測試函數來確定這些:HitTestTextPosition用於映射文本位置索引(相對於第一個字符)爲矩形,HitTestTextRange用於獲取矩形諸如用於選擇的整個範圍,並HitTestPoint爲將鼠標座標映射到文本位置索引。對於插入記號,這低於適用於所有水平方向的讀取方向和比例/寬字體:

... 
DWRITE_HIT_TEST_METRICS hitTestMetrics; 
float caretX, caretY; 
bool isTrailingHit = false; // Use the leading character edge for simplicity here. 

// Map text position index to caret coordinate and hit-test rectangle. 
textLayout->HitTestTextPosition(
    textPosition, 
    isTrailingHit, 
    OUT &caretX, 
    OUT &caretY, 
    OUT &hitTestMetrics 
    ); 

// Respect user settings. 
DWORD caretWidth = 1; 
SystemParametersInfo(SPI_GETCARETWIDTH, 0, OUT &caretWidth, 0); 
DWORD halfCaretWidth = caretWidth/2u; 

// Draw a thin rectangle. 
D2D1::RectF caretRect = { 
    layoutOriginX + caretX - halfCaretWidth, 
    layoutOriginY + hitTestMetrics.top, 
    layoutOriginX + caretX + (caretWidth - halfCaretWidth), 
    layoutOriginY + hitTestMetrics.top + hitTestMetrics.height 
}; 
solidColorBrush->SetColor(D2D1::ColorF::AliceBlue); 
d2dRenderTarget->FillRectangle(&caretRect, solidColorBrush); 

注:

  • 上面的代碼原樣不考慮垂直讀取方向,例如在日本報紙。當DWRITE_READING_DIRECTION是從上到下或從下到上時,您需要繪製一個寬廣的平面插頁而不是高大的薄紙。
  • IDWriteTextLayout::GetMetrics只給出你的整體邊框,而不是插入位置。
  • IDWriteTextLayout::HitTestPoint's isInside flag是真實的,如果它在文本本身,而不僅僅是佈局的邊界。

HitTestPoint's isInside flag

+0

非常感謝您提供這方面的信息!你認爲你可以解釋一下isTrailingHit和isInside參數嗎?我不明白他們。(例如https://msdn.microsoft.com/en-us/library/windows/desktop/dd371464(v=vs.85).aspx) – Andrew 2017-04-30 04:46:44

+1

@Andrew:isInside作爲HitTestPoint的輸出表示x,y會協調您通過了在文本的選擇範圍之內。如果x,y座標高於第一行,低於最後一行,在行最左邊的字符的左邊,或者超出最右邊的字符,則爲false。來自HitTestPoint的isTrailingHit輸出參數意味着您單擊文本羣集的邊界單元格的尾部(即從左到右文本的右側一半,或左側從右到左的文本)。 – 2017-05-02 01:02:36

+0

太棒了,謝謝!如果它在文本的矩形內但在文本之外呢? (在最後一行文本的右側,但在第一行水平內。)另外,文本集羣究竟是什麼?我也無法弄清楚。 – Andrew 2017-05-02 13:16:05