Why are canvas operations not relative to containing object? - delphi

In a Windows Firemonkey application, when I issue the following for a rectangle, in the middle of a form:
rect.Canvas.BeginScene;
rect.Canvas.Clear(TAlphaColorRec.White);
rect.Canvas.EndScene
the entire form is painted white.
Was not the case in XE2. Is the case in Delphi 10.
What's the new paradigm I have overlooked?

The canvas of the primitive (e.g TPaintBox and all TShape descendants) controls, is the canvas of the form. The controls draw directly on this canvas. Therefore a call to Control.Canvas.Clear() clears the whole form. Instead of calling Clear you should use the Fill property of the TRectangle, like so:
Rectangle1.Fill.Color := TAlphaColorRec.White;
I can't comment on how it was in Delphi XE2, but there has been many changes to the FMX library, since then. Maybe this is one of them.
Also refer to FireMonkey Component Rendering

Related

In Delphi 7, get a bitmap from a form when the form is higher than the screen

I have a form that is higher than the screen, and when I try to simulate the printscreen key with
keybd_event(VK_SNAPSHOT, 1, 0, 0);
of course, the form gets cropped.
So I tried to do the following on the active form:
Clipboard.Assign(GetFormImage);
but still, even in this case, the bitmap gets cropped too.
There was an old Delphi component, BDPrint, that was available here:
http://www.efg2.com/Lab/Library/Delphi/Printing/
but it's not available anymore, that was able to print a form creating a temporary tImage and then printing it, even the off screen portion, but I do not have the source code of it anymore.
How can I generate a bitmap of the active form, with the off screen portion too, and store it in the clipboard? Thank you
Off the top of my head, I could search around some more if I had the time:
fist get the handle of the window (with FindWindow or somesuch)
GetwindowDC
BitBlt onto a TBitmap's Canvas.Handle of your own (or StretchBlt or a personal favorite PlgBlt)
You don't need to involve the clipboard, or otherwise capture the screen. Try passing the form's Handle property to PrintWindow(), or send a WM_PRINT message directly to the Form. Either one will let you specify an HDC (such as the one from the TBitmap.Canvas.Handle property) for the window to draw itself onto.

Need help to find FireMonkey equivalent of the VCL TpaintBox.Canvas.Handle in the context of building graph

Preambule:
I'm working with Black Magic Design (BMD) Decklink input card to acquire HD video signal. They provide C++ Sample with their SDK. I've successfully translated the c++ sample into Delphi (VCL). I've also isolated the API call in a TDecklink witch I want it to be available to the Delphi community. It work very well in VCL (I can provide the TDecklnk with a demo app to use it if requested).
Now I need to acquire the signal in a FMX form (but not crosscompile to other platform than Windows). I've tried to modify the TDecklink to be usable in FMX without success.
Core Question:
In my VCL version, I pass a TPaintBox refference to my TDecklink. The TPaintBox is used by the GraphBuilder as area to display the live video.
Here is some line of code I use in the VCL version to assign the TPaintBox to the GraphBuilder:
pWnd := WindowFromDC(FpboxPreview.Canvas.Handle); //WindowFromDC retreive HWND from HDC
hr:= pIVMRWindowlessCtrl.SetVideoClippingWindow(pWnd); // set the bounds of the video to the preview window
if hr = S_OK then
begin
previewRect.Left := FpboxPreview.Left;
previewRect.Right := FpboxPreview.Width;
previewRect.Top := FpboxPreview.Top;
previewRect.Bottom := FpboxPreview.Height;
hr:= pIVMRWindowlessCtrl.SetVideoPosition(nil, #previewRect); // show the whole of the source frame in the whole of the client area of the control
hr:= pIVMRWindowlessCtrl.SetAspectRatioMode(VMR_ARMODE_LETTER_BOX); // maintain the aspect ratio of the video
hr:= pIVMRWindowlessCtrl.SetBorderColor(GetSysColor(COLOR_BTNFACE)); // set the colour of the letter or pillar boxed area
Where PWnd is a HWND
In FMX, what is the best component and parameter to use to provide what the GraphBuilder expect to receive ?
In VCL, TPaintBox is a TGraphicControl descendant that draws onto the HDC of its Parent control's HWND. When the Parent control receives a WM_PAINT message, it draws itself onto the provided HDC as needed, and then temporarily gives that same HDC to each child TGraphicControl when drawing them, clipping the HDC to each child's coordinates and rectangle accordingly. If you try to draw onto a TGraphicControl.Canvas from outside of its Parent control's WM_PAINT handler (which you should never do), TCanvas will temporarily grab the Parent control's HDC using the Win32 API GetDC() function.
Thus, this statement:
pWnd := WindowFromDC(FpboxPreview.Canvas.Handle);
Is effectively the same as this:
pWnd := FpboxPreview.Parent.Handle;
So, you are actually putting your video on the window of the TPaintBox.Parent control, not on the TPaintBox itself. If you want the video associated with its own control, consider using TPanel instead, as it is a TWinControl descendant with its own HWND.
FireMonkey, on the other hand, has no concept of TGraphicControl and TWinControl. Every control is a TControl descendant with an overridden Paint() method to handle any custom drawing onto a TCanvas that is provided by either the parent TForm or the caller of the TControl.PaintTo() method. FireMonkey does not even create an HWND for each control. Only the parent TForm has its own HWND (so it can interact with the OS). Child controls are drawn directly onto that window, adjusting the drawing coordinates and clipping rectangle accordingly as they go along (under the hood, FireMonkey uses DirectX (Windows) or OpenGL (other platforms) for all of its drawing).
So, if you really need an HWND for your video class to display on, you will have to either:
use the HWND of a TForm, which you can get by either passing its Handle property to the
FMX.Platform.Win.WindowHandleToPlatform() function (or the FMX.Platform.Win.FmxHandleToHWND() function on older FireMonkey versions):
uses
..., FMX.Platform.Win;
pWnd := WindowHandleToPlatform(Form1.Handle);
Or passing the TForm itself to the FMX.Platform.Win.FormToHWND() function:
uses
..., FMX.Platform.Win;
pWnd := FormToHWND(Form1);
use the Win32 API directly to create your own HWND as needed and then embed it inside the HWND of a TForm.
Otherwise, you will have to re-think your video UI in FireMonkey. For instance, assuming the video class can provide you with images of the video frames, you can draw them onto the TPaintBox.Canvas from within the TPaintBox.OnPaint event (which is how TPaintBox is meant to be used in the first place, in both VCL and FireMonkey). Or maybe derive your own custom TControl that pulls images from the video class in its own overridden Paint() method. I don't know what your GraphBuilder class is capable of, but BMD provides an SDK for controlling video recording/playback hardware and accessing video data (see this PDF).

form:Transparent, Control on form:non Transparent?

How can change alphablend of a form without affect on control in form?
Delphi XE7
One solution to this problem is to use Multi-Device Application (if using VCL is not possible).
If you need to leave a transparent TForm just changing a property Transparency = True.
If you need to leave a semi-transparent component, all components have the Opacity property that can be assigned a more transparent value between 0 and 1, where 0 is closer to that component.
For example you could put the controls within a TLayout and change the Opacity of it as you see fit, and have no effect on the other components, or vice versa.
Actually the answer to this might be pretty simple...(for windows only)
The JEDI VCL library has a component (TJvTransparentForm) that allows you to take an Alpha blended PNG image (ie the gray background shown in your picture above) and use it to make a form control. The picture is actually stored in a TImage and you would need to place your "Icons" on the image itself. Then just respond to the mouse clicks on the TImage.
You have what your asking for (maybe?).
If you were tricky enough you could probably even track the mouse movement and change the Image to glow the correct "button" that the mouse was over.

What is equivalent of Canvas.Pixels[X,Y] in Firemonkey?

In VCL we can get the color of specific pixel from Canvas or bitmap like this:
Canvas.Pixels[X,Y]
but we have not such a thing for canvas and bitmap in firemonkey components. how can we read or write a specific point on a canvas in FMX?
I presume that you are working with a bitmap, if you wish to operate on pixel data. In which case you use the Map method of the TBitmap class. More details here:
http://www.fmxexpress.com/get-direct-pixel-access-to-bitmaps-in-delphi-xe5-firemonkey-on-android-and-ios/
http://members.adug.org.au/2012/10/05/read-write-image-bitmap-pixels-in-delphi-xe3/
http://docwiki.embarcadero.com/CodeExamples/en/FMX.AlphaColorToPixel_(Delphi)

Component Messages in Delphi (CM_) and Custom Graphical DesignTime Component

I want to create a graphical component in Delphi that is editable to some extent
inside the designtime editor.
I would like to know
What component I should inherit from (for example TWinControl or whatever)
How to handle component messages (CM_xxx) to be able to move around my component in the editor
If it's possible to use native windows components in the designtime editor, but then switch to other component in runtime.
The reason I want to be able (if even necessary) to switch to other type of component in runtime is because the component I intend to use is TBitmap32 from the Graphics32 library which is many times faster than standard windows graphics, but TBitmap32 is not inherited from TWinControl to begin with.
Maybe if possible, I could maybe do something like using standard VCL in designtime and then just take its properties and apply them to TBitmap32.
Example:
In designtime I use a TImage which I can move around, and when I run the application it takes the X and Y values, and the bitmap from TImage and apply them to the TBitmap32 component and draw the TBitmap32 component to wherever it needs to be drawn.
Code could look something like this:
TMyBMP= class(TImage)
private
fResultBMP: TBitmap32;
.....
I hope you understand, thank you!
I would not use different components at design-time and run-time. That will just over-complicate your component design. What you use at run-time should be the same thing you use at design-time.
What I would do is have your component contain a TBitmap32 member, override the Paint() method to draw the bitmap at both run-time and design-time, and then respond to the CM_DESIGNHITTEST message so that your component can react to mouse activity at design-time while the mouse is over the bitmap. You can then override the standard MouseDown/Move/Up() methods to manipulate your bitmap positioning/sizing as needed (inside those methods, you can differentiate between run-time and design-time by checking your component's ComponentState property for the csDesigning flag).
To save the bitmap to the DFM, you can either expose the TBitmap32 as a published property (which offers an alternative way of manipulating the bitmap at design-time), or override your component's DefineProperties() method to stream the bitmap manually.
You can create a component inherited from TGraphicControl or TWinControl. The latter is needed if you want your control be able to receive focus and Windows messages.
Your component should use TBitmap32 as a buffer - you do all paint there, in memory. In the Paint method (which you override) you copy contents from the buffer to screen using BitBlt or similar function.

Resources