Delphi Component Disappears from Component Palette in new Data Module - delphi

The declaration of my component is:
MyComponentX = class(TActiveXComponent, IspdInterfaceX)
TActivexComponent:
TActiveXComponent = class(TActiveXControl, IOleControl)
When I open a new DataModule in any Delphi version, the component disappears from the Component Palette.
I try to change the ClassGroup in Delphi XE2, but this don't works.

Data modules can only host non-visual controls, and TActiveXControl is not a non-visual control.
You ask what is the definition of non-visual control. According to this article, the definition is that if the component is derived from TComponent and not derived from TControl, then it is a non-visual control.
That said, the inheritance hierarchy for TActiveXControl is: TObject, TComObject, TTypedComObject, TAutoObject, TActiveXControl. So I am at something of a loss at to why it ever appears on your component palette since it is not derived from TComponent. It would be interesting to know how you registered it. All the same, it's not a non-visual component in the meaning of the act.

In this case, you can create a class wrapper to use your ActiveX in this data module.
TWrapper = class(TComponent)
private
FYourActiveX: TYourActiveX;
public
procedure Method;
end;
procedure TWrapper.Method;
begin
FYourActiveX.Method;
end;

Related

Firemonkey Assign TPanel to TPanel doesnt work XE10.1 Berlin

I'm trying to use assign on a TPanel configured in the designer but it doesn't work.
var
LPanel : TPanel;
begin
LPanel := TPanel.Create(nil);
LPanel.Assign(Panel1); // Panel1 is a panel made in the form designer
end;
The error message is something like "TPanel cannot be assigned to TPanel." (I have the german version of RAD Studio... The exact error message on german is "TPanel kann nicht zu TPanel zugewiesen werden.")
I designed a TPanel with other components in it using the Form Designer. Now I want to add new TPanel instances to a TLayout which should be the same as the TPanel I want to assign from, including all child controls.
Most VCL and FMX components, including TPanel, DO NOT implement Assign() at all. Typically only utility classes that are used for component properties implement Assign() for use in their property setters.
For what you are attempting, you should use a Frame instead of TPanel. You can design a Frame at design-time, just like a Form or DataModule, and then create instances of it at run-time as needed.
See Embarcadero's documentation for more details:
Frames in FireMonkey
Unfortunately I don't currently have access to Delphi to confirm. But it seems Assigning TPanel is deliberately blocked by the framework.
That said, what you're trying to achieve seems more appropriately handled with TFrame
Once you've created your frame, you should be able to use the following code to create a new instance at run-time.
uses
...
frMyFrame;
...
var
LNewFrame : TFrame;
begin
LNewFrame := TMyFrame.Create(nil); //Are you sure you don't want to assign an owner?
LNewFrame.Parent := Self; //Assuming you want to position the frame directly on the form
//Otherwise you could place it on a simple panel.
//Set attributes for positioning
//Don't forget resource management (see ownership comment)
...
end;

Updated TWebBrowser now implements IDocUIHandler from the start, how can I keep using my custom implementation?

Beginning with Delphi 10.0 Seattle, Embarcadero has changed the implementation of the TWebBrowser control:
Pre-Seattle: TWebBrowser = class(TOleControl)
Seattle+: TWebBrowser = class(TOleControl, IDocHostUIHandler, IDocHostShowUI, IOleCommandTarget)
I have somewhat old code running where I had implemented a class that could register as a client site/host for a TWebBrowser where I provided my own implementation of the IDocHostUIHandler interface.
Since a TWebBrowser is now implementing these from the start (and keeping them private) and is hard to descend from for all I know - how do I go about to get the new TWebBrowser component to re-register where to find an implementation for IDocHostUIHandler?
You can descend from TWebBrowser and provide your own interface definitions as before, like this:
Type
TMyWebBrower = class( TWebBrowser, IDocHostUIHandler )
...
end;
This tells Delphi that you are reimplementing the IDocHostUIHandler interface. You must provide all functions for the interface, but you already have that.

How can I create an event handler for a non published but public event in delphi?

In RAD Studio 10.1 Berlin quite a few things has changed from previous version. In FMX there are a few previously published events that has now been changed to only be public.
I have a Multi Platform Project that uses a TStringGrid component and the OnDblClick event. When opening this project in Studio 10.1 I get warned that the Property OnDblClick does not exist.
The question is now how I can use the no longer published event?
(I must say that It's hard to understand why they haven't set mouse events to Published anymore. As far as I know most regular PCs and OSX machines doesn't have touch. A true Multi Target Project should be able to target these systems without hassle as they did in Studio 10 Seattle)
In case the event handlers already exist (which I imply by the error message), you can assign these handlers to their events in FormCreate.
procedure TForm1.FormCreate;
begin
StringGrid1.OnDblClick := StringGrid1DblClick;
end;
One solution is to make your own component where you extend the FMX.TStringGrid to have published event handlers again.
See here how to create a new FMX component: creating a firemonkey component
Here's the code to re-publish the mouse events.
unit MyStringGrid;
interface
uses FMX.Grids;
type
TMyStringGrid = class(TStringGrid)
published
property OnDblClick;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnMouseEnter;
property OnMouseLeave;
end;
procedure Register;
implementation
uses FMX.Types;
procedure Register;
begin
RegisterComponents('NewPage', [TMyStringGrid]);
end;
initialization
RegisterFmxClasses([TMyStringGrid]);
end.
This has been reported as a bug here.
Looking at the source code in Delphi 10.1 berlin the public OnDblClick event is actually inherited from TControl class.
Similar the OnDblClick event is also inherited from TControl class with the exception that it is made public, like many other events that are inherited from TControl˙ class.
Any way it seems that guys at Embarcadero have been doing some refactoring by cleaning the parent property redeclarations˙(not sure if this is the right term) like:
type
TParentClass = clas(Tobject)
public
property ParentPropery: Integer read GetParentProperty write SetParentProperty;
TExampleClass = class(TParentClass)
public
property ParentPropery;
end;
Redeclaring ParentProperty in the above case is not needed as it will be available in all child classes unless you want to change its visibility from public to published for instance.
If you look at Delphi 10 Seattle source code you see that property OnDblClick is redeclared in several TStringGrid parent classes being published in TCustomScrollBox for the first time.

'Property Align does not exist' when inheriting from TCustomControl

I have created a custom control inherited from TCustomControl and published the property Align of TControl. But, when I used this custom control in a C++Builder project, it raised the exception
Project Launcher.exe raised exception class EReadError with message 'Property Align does not exist'.
This is the code for the custom control.
unit GameListCtrl;
interface
uses
SysUtils, Classes, Controls;
type
TGameList = class(TCustomControl)
private
protected
procedure Paint; override;
public
{ Public declarations }
published
property Align default alLeft;
end;
implementation
{ TGameList }
procedure TGameList.Paint;
begin
inherited;
end;
end.
Often this kind of error occurs if the package was not properly rebuilt. Then you need to open the package project that includes the unit "GameListCtrl" an rebuild the package. Make sure to activate the option to let RAD Studio create the C++ Builder files.
If that doesn't help the linker maybe picks a wrong / old DCU or obj file. Search all your drives and delete all GameListCtrl.dcu and GameListCtrl.obj files that you can find. I use UltraSearch from JAM Software to quickly search my local drives, it is much faster than Windows Search as it works directly on the NTFS structures.
You may also try to switch to static linking for your project in the project options.

When a class implements a descendant interface, why doesn't it automatically count as implementing the base interface?

What's the reason this won't compile?
type
IInterfaceA = interface ['{44F93616-0161-4912-9D63-3E8AA140CA0D}']
procedure DoA;
end;
IInterfaceB = interface(IInterfaceA) ['{80CB6D35-E12F-462A-AAA9-E7C0F6FE0982}']
procedure DoB;
end;
TImplementsAB = class(TSingletonImplementation, IInterfaceB)
procedure DoA;
procedure DoB;
end;
var
ImplementsAB: TImplementsAB;
InterfaceA: IInterfaceA;
InterfaceB: IInterfaceB;
begin
ImplementsAB := TImplementsAB.Create;
InterfaceA := ImplementsAB; >> incompatible types
...
end
In contrast this is how I make it work:
InterfaceA := ImplementsAB as InterfaceB;
or
InterfaceA := InterfaceB;
I mean, if IInterfaceB inherits from IInterfaceA and TImplementsAB implements IInterfaceB, it wouldn't be logical to also implement IInterfaceA and be type compatible?
This so because early OLE/COM had a bug and Borland decided to be compatible with it. This is mentioned in this article: New Delphi language feature: Multiple inheritance for interfaces in Delphi for .NET. The solution is to list all ancestor interfaces explicitly in the class as Mikael wrote.
Some quotes from the linked article:
The problem was in COM itself. To load a module, COM would load the DLL, GetProcAddress on a well-known entry point that was supposed to be exported from the DLL, call the DLL function to obtain an IUnknown interface, and then QueryInterface for IClassFactory. The problem was, when Microsoft added support for IClassFactory2, they added the QueryInterface for IClassFactory2 after the existing code that queried for IClassFactory. IClassFactory2 would only be requested if the query for IClassFactory failed.
Thus, COM would never request IClassFactory2 on any COM server that implemented both IClassFactory2 and IClassFactory.
This bug existed in COM for a long time. Microsoft said that they couldn't fix the COM loader with an OS service pack because both Word and Excel (at the time) relied on the buggy behavior. Regardless of whether it's fixed in the latest releases of COM or not, Borland has to provide some way to preserve this behavior in Win32 Delphi for the forseeable future. Suddenly adding all ancestors into an implementing class that weren't there before is very likely to break existing code that unintentionally falls into the same pattern as the COM loader.
Another way to make it work is to include both interfaces in the class declaration.
TImplementsAB = class(TSingletonImplementation, IInterfaceA, IInterfaceB)
procedure DoA;
procedure DoB;
end;
I guess this is what is required for the compiler to realize that TImplementsAB implements both IInterfaceA and IInterfaceB.

Resources