how to create a brush resource in firemonkey - delphi

I am new to firemonkey but am using dxscene since a year now. In dxscene brush resources could be added without a hastle in the resources object (style book in firemonkey). But firemonkey boggles me, the docwiki of embaracadero suggests to manually add it in the style book which i don't know how.
Can someone help me to add brush resources in the style book so they could be looked up? Preferably a way involving the GUI.

Style books can only contain descendants of TFMXObject, but TBrush descends directly from TPersistent so can't be added. The FMX.types unit contains a TBrushObject which is suitable but it doesn't appear to be registered anywhere so it's not available in the tool palette.
I suggest creating a package which registers it and therefore make sit selectable. You will need to add a unit to the package such as:
unit RegisterBrushObject;
interface
uses FMX.Types;
procedure Register;
implementation
uses Classes;
procedure Register;
begin
RegisterComponents('Custom', [TBrushObject]);
end;
initialization
RegisterFMXClasses([TBrushObject]);
end;
Once you've added that to a package, right click on the package in the project manager (top-right) and select Install.

Related

How to auto include files when Delphi VCL design time package is put onto the form

I built a wrapper around the TWebBrowser in Delphi. The wrapper aims at implementing multiple web browsers (edge chromium, chrome etc) into a single wrapper that auto detects which browser to use.
After I completed the class I turned said class into a VCL component and loaded it into a design time package. My component includes only two files, the wrapper itself and a utilities class. When I drag my component from the tools palette onto a VCL form the wrapper and the utilities class are not added automatically to the project. This means I have to manually include both the wrapper and the utility into the project.
I was hoping there was a way to automatically include these two files into the project when the wrapper is added to the form. I think I have seen this before with other third party components I have used but my memory may be failing me.
If this is a thing that can be done, my assumption is that it would be in the register section of the VCL component.
procedure Register;
begin
RegisterComponents('My Wrappers', [TWebBrowserWrapper]);
end;
As that is the code that I believe is run when in design time.
Have your design-time package implement a class that inherits from TSelectionEditor and overrides its virtual RequiresUnits() method, and then register that class for your component using RegisterSelectionEditor(). This way, whenever you place your component onto a Form/Frame/DataModule Designer at design-time, any additional units you report from RequiresUnits() will be added automatically to that unit's uses clause when the unit is saved.
For example:
uses
..., DesignIntf;
type
TWebBrowserWrapperSelectionEditor = class(TSelectionEditor)
public
procedure RequiresUnits(Proc: TGetStrProc); override;
end;
procedure TWebBrowserWrapperSelectionEditor.RequiresUnits(Proc: TGetStrProc);
begin
inherited RequiresUnits(Proc);
// call Proc() for each additional unit you want added...
Proc('MyWrapperUnit');
Proc('MyUtilityUnit');
end;
procedure Register;
begin
RegisterComponents('My Wrappers', [TWebBrowserWrapper]);
RegisterSelectionEditor(TWebBrowserWrapper, TWebBrowserWrapperSelectionEditor);
end;

Create Firemonkey form and populate by code

I am porting over a VCL component to FMX. 99% of of the code is pure object pascal, so that works just fine - but i have a method which creates a form, poulates it with buttons and a text-box, and this quite simply doesnt work under FMX.
The whole point to creating the form manually and then populating it from code was to make sure it compiled under both VCL, LCL and FMX; and that it also displays just fine under iOS, Android and whatever platform is used.
But i keep getting "Resource /classname/ not found", where /classname/ is whatever classname i give my temporary form class.
Something as simple as this produces the error:
type
TMyDialogForm = Class(TForm);
procedure TForm1.Button1Click(Sender: TObject);
var
LDialog: TMyDialogForm;
begin
LDialog := TMyDialogForm.Create(application.MainForm);
try
LDialog.Caption := 'Yahoo!';
finally
LDialog.Free;
end;
end;
Since the error involves resource, I suspect that it is looking for some type of layout data. I have just started playing around with FMX, and i did notice that different platforms allow for different layouts. But I must admit I expected it to fall-back to the default theme, no matter what platform you target.
So -- how exactly do i create a form by code, populate it and display ut using Firemonkey without running into this kind of bug? It works perfectly fine under VCL and LCL, but FMX keeps going on about resources.
Please dont tell me all forms MUST be designed?
As #RemyLebeau answered a similar question in the delphi forum (How to create a TForm at runtime?):
You are calling the TForm constructor that invokes DFM streaming. The reason
it does not fail in non-FMX apps is because TCustomForm.Create() filters
out TForm specifically so it won't try to stream. In FMX, TCommonCustomForm.Create()
filters out TCommonCustomForm instead of TForm, which is why your TForm in
FMX is trying to stream itself.
Since you know that there is no DFM, you should be using the non-DFM constructor
instead, in both VCL and FMX:
FRM := TForm.CreateNew(Application);

Delphi FMX Add GUI Elements in Host's Form from DLL

So basically here is what I did:
I made a new FMHD Application and dropped a TTabControl and a Button on it. Then I designed an interface IFoo. To keep it simple, let's just pretend it only has one procedure:
type
IFoo = interface
['{D035-N07-M4773R-...}']
procedure makeTab(tc : TTabControl);
End;
I implemented this interface in a DLL. The DLL is loaded via LoadLibrary and exports a
function getFoo : IFoo;
MakeTab basically creates a TTabItem and sets tc as it's parent:
procedure TFoo.makeTab(tc : TTabControl);
var
tab
: TTabItem;
begin
tab := TTabItem.Create(tc);
tab.text := 'Hi, I am Tab';
tab.Parent := tc;
// ...
end;
If I forgot something, I am very sorry. I do not have the exact source in front of me at the moment.
This method is invoked when the Button on the form is pressed.
But nothing happens.
So I put this method into my TForm1 class. If I call it now, a tab is created.
So how can I create this tab (and several child components) from within the DLL on the application's main form?
The fundamental issue here is that you cannot share Delphi class types between modules using DLLs. The reason is that there will be multiple versions of what needs to be a single type. One version in the executable, and one version in each DLL that uses it.
This is the same well known issue that exists with the VCL and is the reason why runtime packages were developed. And that's your solution for FMX also. If you need to share Delphi class types between modules you need there to be one single definition of a type. And runtime packages are the mechanism that makes that possible.
So, stop using DLLs, move the code into a runtime package, make sure that the RTL and FMX are linked using runtime packages, and that problem will be solved.

Delphi - unit segregation

My new component (TComponent) uses DsgnIntf since I use custom property editors. The problem is when using the component in a custom VCL application - DSGNINTF.DCU not found! One solution is to add a command line switch to a compiler (dont remember any more what is it), but I don't like that solution. The second solution is a unit segregation. I found this:
http://edn.embarcadero.com/article/27717
The problem is - I don't understand this article so well.. I don't know what exactly I need to do in my component unit to separate design-time from runtime code. Could someone please make the simplest example and explain it? I just want to avoid problems with "dsgnintf.dcu not found" when people using my component. Thank you.
EDIT:
I looked the article a bit more and I realize the second unit registers the first one. To avoid dsgnintf.dcu problem I presume the second unit must be in it's own .pas file?
Usually you create a single unit to register your package in IDE, something like that:
unit RegPackage;
interface
uses
Classes, MyUnit;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('MyPage', [TMyComponent]);
end;
end.
and include this unit into design-only package:
package MyPackD;
{$R *.res}
..
requires
rtl, MyPackR; // your runtime package
contains
RegPackage in 'RegPackage.pas';
end.
The article you link covers also property editors. All package code not related to IDE should be contained in run-only package:
package MyPackR;
{$R *.res}
..
requires
rtl,
vcl;
contains
MyUnit in 'MyUnit.pas';
end.
You must separate your run-time code and design-time code into separate packages. Create a runtime-only package that contains just your component code. Create a designtime-only package that specifies your runtime-only package and the IDE's DesignIDE package in its requires list, and contains just your property editor and registration code. Then you can install the designtime-only package into the IDE, and refer to the runtime-only package in your projects. The DesignIDE package resolves the DsgnInf reference, but it is NOT allowed to be linked into runtime executables! It is for the IDE's use only.

Overriding Component Create Constructor in Separate Design-Time package

Programming Environment: Delphi 6 and upwards
I am aware of the fact that since Delphi 6, custom components must have separate design- and run-time package. All run time features of the a component must therefore be in a separate unit and packaged separately to the component's design-time package.
My problem is the following: My component has code that needs to be run both when it is created on the form at run time and, additional code that needs to be run at design-time, when the component is placed on the form. I have managed to put the run time code into the separate run time unit, package it and deploy it successfully.
However, in the separate design-time module unit, how do I reference and add the design-time code that needs to be included into the component's create constructor during design-time, when the component gets placed onto the form?
You can separate design time behaviour from run time behaviour with
if [not] (csDesigning in ComponentState) then
But if your constructor code needs the DesignIDE design time package, e.g. from the units DesignEditors, DesignIntf, etc..., then I think you are stuck. Maybe some IOTA involvement can help. But since there does not seem to exist a notifier interface for the creation of components, that would require a custom IOTAFormEditor. Not that easy, if not impossible.
Why not use callbacks?
From your designtime package initialization code do this:
unit MyDsgnUnit;
interface
//TMyHook defined in AnImplUnit
TMyDesignHandlerObject = class
procedure MyMethod(Sender:TObject;ParentForm:TObject); { must match TMyHook }
end;
implementation
uses AnImplUnit, DesignUnitNamesHere;
procedure TMyDesignHandlerObject.MyMethod(Sender:TObject);
var
newObject:TMyComponent;
begin
newObject := TMyComponent(Sender);
DoSomethingThatneedsDesigntimeStuff(newObject);
end;
finalization
ADesignHandlerObject.Free;
initialization
ADesignHandlerObject := TMyDesignHandlerObject.Create;
AnImplUnit.AfterConstructionHook := TDesignHandlerObject.MyMethod;
and in your component do something like this:
unit AnImplUnit;
interface
type
TMyHook = procedure(Sender:TObject;ParentForm:TObject) of object;
var
AfterConstructionHook:TMyHook;
implementation
...
procedure TMyComponent.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
DOMyStuff;
if Assigned(AfterConstructionHook)
AfterConstructionHook(Sender,Parent);
end;
Update Flushed out example more. There is no reason you can't add more parameters to the AfterConstructionHook, but since your reference to Sender is already of type TMyComponent, I don't see the point, when you can access everything public or protected, in TMyComponent(Sender) from within your hook function, and if you inherit locally (known as a protected-access class), you can access the protected stuff too.
Make sure your DPK defines a symbol of your choice, for example DESIGNTIME. Then you'll be able to use something like this to only include design-time units when needed:
uses Windows, Whatever, Something
{$IFDEF DESIGNTIME}
,DesignIntf
{$ENDIF}
;
Then to the same in your constructor code:
constructor TMyClass.Create(aOwner:TComponent);override;
begin
inherited;
{$IFDEF DESIGNTIME}
// I'm at design time.
{$ENDIF}
end;
When using this technique you should either use a separate DCU directory for your pacakge and your normal executable, or do a build each time you switch from the design time package to other projects. That's because Delphi will only re-build a DCU if the PAS has changed, when in this case the PAS doesn't tell the whole story, defined symbols also matter. If you have a DCU on disk that was compiled by Delphi while you were building your design time project, you might see a ToolsApi.DCU not found when trying to compile a normal project. Rebuilding re-compiles the DCU and makes the message go away. Just as well, if you re-compile (not re-build) the design time project after you built a normal project, your DCU might be stuck in it's non-DESIGNTIME state, leaving you without your special design-time behavior.
As long as your code does not require the IDE tools, like design interface and so on, then all you need to do is check the component flag and you can use it anywhere within the component, as follows...
procedure TNewEdit.Loaded;
begin
inherited;
if (csDesigning in ComponentState) then
ShowMessage('Designing')
else
ShowMessage('Running');
end;
However without really knowing what you are attempting to do, there are several doors left open... for example, if you want to change a property value at design time, and a different value at run time, then there are streaming issues you have to deal with.

Resources