Resource not found when creating overridden version of Tform [duplicate] - delphi

I am writing a component and want to change the base type to a TForm however at run time I get the error "Resource TMyComp not found". I guess that this is because there is no dfm but I am not sure what to do about it.
Thanks
unit Unit65;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TMyComp = class(TForm);
TForm65 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
Mc: TMyComp;
{ Private declarations }
public
{ Public declarations }
end;
var
Form65: TForm65;
implementation
{$R *.dfm}
procedure TForm65.Button1Click(Sender: TObject);
begin
Mc := TMyComp.Create(Self);
Mc.Parent := nil;
Mc.ShowModal;
end;
end.

There is no .dfm file for TMyComp. You can avoid attempting to load the .dfm by calling the CreateNew constructor rather than Create.
Mc := TMyComp.CreateNew(Self);
From the documentation:
Use CreateNew instead of Create to create a form without using the
associated .DFM file to initialize it. Always use CreateNew if the
TCustomForm descendant is not a TForm object or a descendant of TForm.
CreateNew bypasses the streaming in of the previously-associated .DFM
file. If the form contains visual components, therefore, you must
stream in an external .DFM to bind the visual components with their
classes. If the newly created form has an external .DFM file, then you
can follow the call to CreateNew with a call to
InitInheritedComponent. If you need to create the .dfm file for the
new form instance, bracket the call to CreateNew with calls to
WriteComponentResFile and ReadComponentResFile.

Related

How to use FocusEffect color in VCL Styles

FocusEffect is displayed as a color in the bitmap style designer however it is not defined in TStyleColor.
I can see from the source that FocusEffect relates to TseStyleColor.ktcFocusEffect and should be able to fetch it with TSeStyle(FSource).Colors[ktcFocusEffect] however to do this requires getting the style source which is not accessible from the style and to make it more difficult all of the Tse* definitions are in the implementation section of vcl.styles and therefore not accessible.
Due to this being a seemingly over complicated attack on the problem I presume I am going about it all wrong and there must be a way to access the custom style stuff without hacking around because if you were to create your own custom style with lots of newly defined colors etc. you would have to hack for each new entry.
I have a solution below but it seems excessive for what should be a trivial task.
unit StyleDirect;
interface
uses
Winapi.Windows, Vcl.Graphics;
type
TStyleDirect = class
public
class function FocusEffectColor: TColor;
end;
implementation
uses
System.Classes, System.SysUtils, Vcl.Direct2D, Winapi.D2D1, System.Types, Vcl.ImgList, Vcl.Consts, ZLib, StrUtils, Vcl.GraphUtil,
Winapi.Messages, Vcl.Controls, Vcl.Styles, Vcl.Forms, Vcl.Themes;
{$I StyleUtils.inc}
{$I StyleAPI.inc}
type
TStyleHelper = class helper for TCustomStyle
public
function GetSource: TObject;
end;
function TStyleHelper.GetSource: TObject;
begin
Result := Self.FSource;
end;
{ TStyleDirect }
class function TStyleDirect.FocusEffectColor: TColor;
begin
if not TStyleManager.IsCustomStyleActive then
Exit(GetSysColor(clHighlight));
var Style := TCustomStyle(TStyleManager.ActiveStyle);
var Source := Style.GetSource;
Result:=TSeStyle(Source).Colors[ktcFocusEffect];
end;
end.

Setting Form Parent causes controls to be inactive [duplicate]

I have a child form 'frmTest' and a main form 'TfrmMain'. I set the main form as parent for frmTest like this:
unit Main;
INTERFACE
USES
System.SysUtils, System.Classes, Vcl.Forms, Test, Vcl.StdCtrls, Vcl.Controls;
type
TfrmMain = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
end;
IMPLEMENTATION {$R *.dfm}
procedure TfrmMain.Button1Click(Sender: TObject);
VAR frmTest: TChildForm;
begin
Application.CreateForm(TChildForm, frmTest);
//frmTest:= TForm1.Create(Self);
frmTest.Parent:= Self;
frmTest.Show;
frmTest.SetFocus;
end;
unit test; { THIS IS THE CHILD }
INTERFACE
USES
System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin;
TYPE
TChildForm = class(TForm)
Edit1: TEdit;
SpinEdit1: TSpinEdit;
private
public
end;
IMPLEMENTATION {$R *.dfm}
end.
Code as ZIP
But controls (edit box, spin edit, etc) in frmInsertImg will not accept focus from mouse but can be focused with Tab.
What am I doing wrong?
I suggest that you set BorderStyle to bsNone for the child form. I'm not sure of the exact reasons why this works, but it has the desired effect.
If you need to add a visual frame for your child form then that is best done with explicit UI for the contained of your child form.
Forms aren't really intended to be used in this way, in my opinion. You can make things mostly work, but it's not terribly robust. Putting the UI into a frame and then hosting that should lead to better behaviour.

How to 'parent' a form? (Controls won't accept focus)

I have a child form 'frmTest' and a main form 'TfrmMain'. I set the main form as parent for frmTest like this:
unit Main;
INTERFACE
USES
System.SysUtils, System.Classes, Vcl.Forms, Test, Vcl.StdCtrls, Vcl.Controls;
type
TfrmMain = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
end;
IMPLEMENTATION {$R *.dfm}
procedure TfrmMain.Button1Click(Sender: TObject);
VAR frmTest: TChildForm;
begin
Application.CreateForm(TChildForm, frmTest);
//frmTest:= TForm1.Create(Self);
frmTest.Parent:= Self;
frmTest.Show;
frmTest.SetFocus;
end;
unit test; { THIS IS THE CHILD }
INTERFACE
USES
System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin;
TYPE
TChildForm = class(TForm)
Edit1: TEdit;
SpinEdit1: TSpinEdit;
private
public
end;
IMPLEMENTATION {$R *.dfm}
end.
Code as ZIP
But controls (edit box, spin edit, etc) in frmInsertImg will not accept focus from mouse but can be focused with Tab.
What am I doing wrong?
I suggest that you set BorderStyle to bsNone for the child form. I'm not sure of the exact reasons why this works, but it has the desired effect.
If you need to add a visual frame for your child form then that is best done with explicit UI for the contained of your child form.
Forms aren't really intended to be used in this way, in my opinion. You can make things mostly work, but it's not terribly robust. Putting the UI into a frame and then hosting that should lead to better behaviour.

Resource not found error when using TForm as base for a component

I am writing a component and want to change the base type to a TForm however at run time I get the error "Resource TMyComp not found". I guess that this is because there is no dfm but I am not sure what to do about it.
Thanks
unit Unit65;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TMyComp = class(TForm);
TForm65 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
Mc: TMyComp;
{ Private declarations }
public
{ Public declarations }
end;
var
Form65: TForm65;
implementation
{$R *.dfm}
procedure TForm65.Button1Click(Sender: TObject);
begin
Mc := TMyComp.Create(Self);
Mc.Parent := nil;
Mc.ShowModal;
end;
end.
There is no .dfm file for TMyComp. You can avoid attempting to load the .dfm by calling the CreateNew constructor rather than Create.
Mc := TMyComp.CreateNew(Self);
From the documentation:
Use CreateNew instead of Create to create a form without using the
associated .DFM file to initialize it. Always use CreateNew if the
TCustomForm descendant is not a TForm object or a descendant of TForm.
CreateNew bypasses the streaming in of the previously-associated .DFM
file. If the form contains visual components, therefore, you must
stream in an external .DFM to bind the visual components with their
classes. If the newly created form has an external .DFM file, then you
can follow the call to CreateNew with a call to
InitInheritedComponent. If you need to create the .dfm file for the
new form instance, bracket the call to CreateNew with calls to
WriteComponentResFile and ReadComponentResFile.

How to assign procedure from custom unit to event handler control on main form

Is it real?
For example, I have form1 and button1. I can assign to button1.onClick in design time onlyButton26Click.
TForm1 = class(TForm)
procedure Button26Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
I also have unit 2 like :
unit ProcAndFunc;
interface
uses sysutils,forms;
procedure createArrTable(Sender: TObject);
Can I assign createArrTable to button1.onClick in design time?
Thanks.
Ok. Unit1
TForm1 = class(TForm)
myButton1 : TButton;
procedure Button26Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
Unit2
TForm2 = class(TForm)
myButton2 : TButton;
procedure ButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
Just to know how it works. What should I change in unit2 that I can assign ButtonClick to myButton1.OnClick
How to make a separate unit for event methods, which IDE allows me to assign to component events at design time? It seems that I duplicate question. But that answer does not suit me. Is there the other way?
EDIT3 (08.08.2016):
I created this TDataModule;
unit Unit3;
interface
uses
System.SysUtils, System.Classes,dialogs;
type
TDataModule3 = class(TDataModule)
procedure Click2(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
DataModule3: TDataModule3;
implementation
{%CLASSGROUP 'Vcl.Controls.TControl'}
{$R *.dfm}
procedure TDataModule3.Click2(Sender: TObject);
begin
ShowMessage('hello world');
end;
end.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, unit3;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('hello world');
end;
end.
And I still cant assign DataModule3.Click2 to button1.onclick in design-time. (screenshot). What do I also need to do?
Can I assign createArrTable to button1.onClick in design time?
Not at design-time, no. createArrTable() is not a member of a class, and thus is not accessible via an object pointer at run-time. So it does not satisfy the signature that is normally required for an OnClick event handler. The IDE will not allow you to assign it at design-time.
However, you can assign createArrTable() at run-time, with some minor tweaking.
The OnClick event (and most RTL/VCL events in general) is implemented using a closure, which consists of 2 pointers - a pointer to the procedure code itself, and a pointer to an object.
When the event is fired at runtime, the compiled code extracts the object pointer from the closure and calls the procedure with that object passed to the procedure's Self parameter. It is the lack of a Self parameter that prevents your current createArrTable() implementation from being used as an OnClick event handler. If you were to somehow assign it as-is, the parameter list will get corrupted at runtime.
However, if you add an explicit Self parameter to createArrTable(), you can avoid that issue, and skip the class object requirement:
procedure createArrTable(Self: Pointer; Sender: TObject);
The button will still try to pass an object pointer from the closure to Self when calling the procedue, but now you have made space for an object pointer to be passed correctly and not corrupt other parameters. The object pointer itself becomes irrelevant and can be set to anything you want it to be, even nil.
However, since createArrTable() is still not a member of a class, you cannot assign it directly to the OnClick event, but you can use a TMethod variable to facilitate the assignment, eg:
var
M: TMethod;
begin
M.Code := #createArrTable;
M.Data := WhateverYouWantSelfToBe;
Button1.OnClick := TNotifyEvent(M);
end;
Now createArrTable() will work as expected when OnClick is fired at run-time.
What should I change in unit2 that I can assign ButtonClick to myButton1.OnClick
Nothing. It is already a suitable event handler as-is. All you would have to do is add unit2 to the uses clause of the interface section in unit1 so the IDE can see ButtonClick() at design-time, then you would be able to assign Form2.ButtonClick to myButton1.OnClick. Just know that you will have to setup your project to create Form2 before Form1 at runtime, otherwise you will likely crash the code when the DFM streaming system tries to access ButtonClick via an invalid Form2 object when assigning the value of Form1.myButton.OnClick.
To avoid having to change the creation order of the Forms, you can place the event handlers into a separate TDataModule instead, and then link its methods to events on your Form. Just make sure the TDataModule is created at runtime before the Form is created:
Access DataModule's event from another Form (delphi design-time)
You cannot ever assign that procedure as an event handler since it is not a method of a class. So you could make the procedure be a method of another class and make sure that there was a global instance of that class visible to the designer.
However that would be a very poor solution in my view. It is best practice to decouple UI logic from application logic where possible. The clean solution is to simply call the procedure from an event handler. That means that your procedure is still available to other parties in its current form and does not need to be shoe-horned into looking like an event handler. You could also likely remove the Sender parameter which I suspect you are not using in any case.

Resources