0

I'm trying to write text to my ID2D1HwndRenderTarget* renderTarget-window using Directwrite. That works good and text appears where it should. But i have the feeling i'm doing something wrong in Graphics::DrawMyText. I think I should create my IDWriteTextLayout* textLayout also in the Graphics::Initialisation but if I do that, i cannot alter the text const wchar_t* wszText anymore. At least, I did not find any helper function in IDWriteTextLayout interface

So is it correct to create and release my IDWriteTextLayout all the time, or is there a way I only have to create it once like the other interfaces?

#include<dwrite.h>

class Graphics
{
    IDWriteFactory* writeFactory;
    IDWriteTextLayout* textLayout;
    IDWriteTextFormat* textFormat; 
}

Graphics() // constructor
{
    writeFactory = NULL;
    textLayout = NULL;
    textFormat = NULL; 
}

Graphics::~Graphics() // destructor
{
    if (writeFactory) writeFactory->Release();
    if (textLayout) textLayout->Release();
    if (textFormat) textFormat->Release();
}

bool Graphics::Initialise(HWND windowsHandle)
{
    res = writeFactory->CreateTextFormat(
    L"Lucida Console",
    NULL,
    DWRITE_FONT_WEIGHT_REGULAR,
    DWRITE_FONT_STYLE_NORMAL,
    DWRITE_FONT_STRETCH_NORMAL,
    10.0f,
    L"en-us",
    &textFormat
    );
    if (res != S_OK) return false;

    return true;
}

void Graphics::DrawMyText(const wchar_t* wszText, float x, float y, float boxWidth,
                          float boxHeight, float r, float g, float b, float a)
{
    writeFactory->CreateTextLayout(wszText, (UINT32)wcslen(wszText), textFormat,
                                   boxWidth, boxHeight, &textLayout);
    brush->SetColor(D2D1::ColorF(r, g, b, a));
    renderTarget->DrawTextLayout(D2D1::Point2F(x, y), textLayout, brush);
    textLayout->Release(); // don't forget this one to prevent memory leaks
}
mca2
  • 63
  • 7
  • Where did that `renderTarget` come from? – Marius Bancila Jun 02 '20 at 22:47
  • 1
    If you change the text, you'll have to recreate the layout, but you can keep the format, which is what you do. You could also cache the layout until the parameters to CreateTextLayout change. https://learn.microsoft.com/en-us/windows/win32/directwrite/text-formatting-and-layout – Simon Mourier Jun 03 '20 at 07:32
  • @MariusBancila render target is initialised and defined elsewhere, but that's not relevant for this question but I listed its name and type. – mca2 Jun 03 '20 at 12:13
  • 1
    `CreateTextLayout` takes in a text string and produces an object that represents the fully analyzed and formatted result. If you want to change text string content you can call `CreateTextLayout` again with new text string. – Rita Han Jun 04 '20 at 09:41
  • @RitaHan-MSFT thanks for your suggestion. That is what I do in the code shown, but I was hoping i could create `IDWriteTextLayout` once and reuse it like the other `ID`-elements. – mca2 Jun 09 '20 at 15:11
  • *The text in an `IDWriteTextLayout` object cannot be changed once the object is created. To change the text you must delete the existing object and create a new `IDWriteTextLayout` object.* Refer to [Text Formatting and Layout](https://learn.microsoft.com/en-us/windows/win32/directwrite/text-formatting-and-layout#idwritetextlayout) – Rita Han Jun 10 '20 at 06:19

1 Answers1

2

The text of a DWrite layout is indeed fixed, your choices are either to create (and release) layout objects or go the much harder route of using IDWriteTextAnalyzer (along with IDWriteTextAnalysisSource/IDWriteTextAnalysisSink). It would have been nice if the text of a layout were mutable but MS simply didn't make that choice.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
  • Yeah, it would have been possible to add an `IDWriteTextLayout::SetText` and corresponding `IDWriteTextLayout::InsertRange/DeleteRange` function pretty easily (and hindsight says we should have), but we basically had two kinds of customers then (a) the simple app that wanted to draw mostly static text repeatedly (b) the low level customer that owned their own text backing store and had enough desire to call the low level text analysis API's directly. – Dwayne Robinson Jun 12 '20 at 02:53
  • I actually find uniscribe far easier to deal with than DWrite. Mostly because uniscribe can still honor the GDI SetTextAlignment setting and you can thus use baseline alignment and have the rendering engine deal with having text appear as if it's on a single line. (IDWriteTextLayout will do that but doing it with IDWriteTextFormat is a real pain). – SoronelHaetir Jun 12 '20 at 04:11