Search code examples
winapic++builderfiremonkeygdi

How to Get TCanvas DC in Firemonkey?


What I need

I need to get the DC of a Firemonkey component's TCanvas. I need this to use Win API drawing functions not accessible through Firemonkey, mainly 100% control over font rendering.

Obviously, this is a pure Windows Application, so any compatibilities with OSX isn't an issue.

What I did

I managed to get hold of the TForm's handle and convert it into a HWND, then getting the DC with GetDC(FmxHandleToHWND(Handle));

This is the OnPaint handler for the Character_PaintBox control.

HWND hWND = FmxHandleToHWND(Handle);
HDC hDC = GetDC(hWND);
int x = PreviewBack_Rectangle->Position->X + Character_PaintBox->Position->X;
int y = PreviewBack_Rectangle->Position->Y + Character_PaintBox->Position->Y;

TextOut(hDC,x,y,L"Test",4);

ReleaseDC(hWND,hDC);

How ever this is the Form's DC and anything I write is overwritten at next update.

This was an easy task in VCL and it can't be that complicated in Firemonkey, or?


Solution

  • The problem is that with Firemonkey, you only have a single device context for the form and not one for each component. When a component needs to be redrawn, it gets passed the forms canvas but with clipping and co-ordinates mapped to the components location. As you already found, in Windows, you can get that context and draw on it at any time but you are then competing with the normal firemonkey painting which happens in the paint methods.

    You can put a TImage on the form and do your custom drawing to that. Firemonkey will just keep redrawing the image when the form needs drawing.

    I know you said you don't want MAC but for anyone else reading this, you can't get a graphics context on OSX and draw to it because the context isn't valid outside the paint method. So the image method would be the only way. This presumably explains why Firemonkey works with the single context.