代码之家  ›  专栏  ›  技术社区  ›  NOhs unutbu

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

  •  4
  • NOhs unutbu  · 技术社区  · 11 年前

    我正在使用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( )
                    );
    

    我想画一条简单的细线作为插入符号。我知道如何画一条线,如何使它出现/消失。

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

    简化: 如果假设文本由 只有一行,那就行了。但当然,我们希望有一个更通用的解决方案。

    2 回复  |  直到 11 年前
        1
  •  10
  •   Dwayne Robinson    6 年前

    使用 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 如果标志位于文本本身之上,而不仅仅是布局边界之上,则标志为真。

    HitTestPoint's isInside flag

        2
  •  -2
  •   vt.    11 年前

    您可以通过 IDWriteTextLayout::GetMetrics .

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

    您的矩形是

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

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