Direct2D CreateTextLayout() - 如何获取插入符坐标

问题描述 投票:0回答:2

我正在使用 Direct2D 从文本布局开始渲染文本

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

我想画一条简单的细闪烁线作为插入符号。我知道如何画一条线以及如何让它出现/消失。

问题: 如何获取插入线的起点和终点坐标?

简化: 如果更容易假设文本仅由 one 行组成,那么就可以了。但当然,更通用的解决方案是值得赞赏的。

c++ directx direct2d
2个回答
11
投票

使用

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
    isInside
    标志位于任何边界框(包括文本和内联对象)内,而不仅仅是布局边界内,则为 true。


-2
投票

您可以通过 IDWriteTextLayout::GetMetrics 获取布局的边界矩形。

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

你的矩形是

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

然后您可以沿着右侧边界线绘制插入符号。

© www.soinside.com 2019 - 2024. All rights reserved.