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

标签 c++ directx direct2d

我从文本布局开始使用 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( )
                );

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

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

简化:如果假定文本仅包含一个行会容易得多,那没关系。但当然,更通用的解决方案值得赞赏。

最佳答案

使用 IDWriteTextLayout 的 HitTest 函数来确定这些:

  • 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::HitTestPointisInside 标志在文本本身上方时为真,而不仅仅是布局边界。

HitTestPoint's isInside flag

关于c++ - Direct2D CreateTextLayout() - 如何获取插入符坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28057369/

相关文章:

directx - 如何快速更新动态顶点缓冲区?

c++ - 使用并行处理在 C++ 中制作游戏

c++ - 多个渲染目标

c++ - 我想了解 C++ 中的参数解包

c++ - 通过成对存储的 key 在 std::set 中查找 key

c++ - 是否有 Vim 插件可以帮助我像 Visual Studio 一样进行调试?

c++ - 将 ID2D1Effect 输出存储在 ID2D1Bitmap/Image 中以便稍后绘制?

C++ 获取 std::variant 当前帮助的类型的 std::typeindex

具有自定义渲染/绘图的 Python GUI

windows-8 - 使用 ID2D1RenderTarget::DrawText 时如何获取文本范围