我必须在应用程序中打开多个表单,并且我使用TtoolButton和TActionlist作为菜单栏。我编写了一个程序来创建/显示每个表单。我很难在此过程中触发Form OnActivate事件。 每个表单都在Tpanel内打开,Tpanel位于FormHome的主要表单中。 我很感激你的帮助!
请参阅Delphi 10.2中的代码
procedure TFormHome.PR_OpenForm(Pform : TFormClass);
var
vform : TForm;
begin
vform := Pform.Create(Application);
vform.Parent := PanelCorpo;
vform.Align := alclient;
vform.BorderIcons := [biSystemMenu];
vform.BorderStyle := bsNone;
vform.Show;
vform.SetFocus;
vform.OnActivate(??); // That is the issue, how to call this event ?
end;
提前致谢!
**添加免费信息以解释为什么我需要一种方法来创建/打开表单**
这是我用来打开每个特定表单的代码。我有一个方法,每个表单具有完全相同的代码。唯一的区别是Form实例本身:
procedure TFormHome.OpenDiretorioExecute(Sender: TObject);
begin
if Not Assigned(FormDiretorio) then
begin
FormDiretorio := TFormDiretorio.Create(Self);
FormDiretorio.Parent := PanelCorpo;
FormDiretorio.Align := alclient;
FormDiretorio.BorderIcons := [biSystemMenu];
FormDiretorio.BorderStyle := bsNone;
FormDiretorio.Show;
FormDiretorio.SetFocus;
FormDiretorio.OnActivate(Sender); // In this way , OnActivate works fine
end;
end;
我需要/想要的东西:
我只需要一种方法来打开所有表单。上面编码的TFormHome.PR_OpenForm(Pform:TFormClass)几乎就在那里,除了OnActivate方法不起作用!
你能帮我解决一下吗?
示例代码 - 包含旧代码和新代码的项目 ===>主要表格" FormHome"
... // This is the main Form FormHOme which calls FormA, FormB and FormC
// There is a TToolbar with 3 Toolbutton that uses a TActionlist
// FormA and FormB are called by the old style method Action1Execute
// and Action2Execute
// FormC is called by the new method PR_CreateOpenForm , which
// presents the error
var
FormHome: TFormHome;
implementation
uses
UnitFormA,
unitFormB,
UnitFormC;
{$R *.dfm}
procedure TFormHome.Action1Execute(Sender: TObject);
// Action1 : OnExecute event, called from ToolButton1
begin
if Not Assigned(FormA) then
begin
FormA := TFormA.Create(Self);
end;
FormA.Parent := Panelhome;
FormA.Align := alclient;
FormA.BorderIcons := [biSystemMenu];
FormA.BorderStyle := bsNone;
FormA.Show;
FormA.SetFocus;
FormA.OnActivate(Sender); // There is a code in OnActivate event in FormA
end;
procedure TFormHome.Action2Execute(Sender: TObject);
// Action2 : OnExecute event , called from ToolButton2
begin
if Not Assigned(FormB) then
begin
FormB := TFormB.Create(Self);
end;
FormB.Parent := Panelhome;
FormB.Align := alclient;
FormB.BorderIcons := [biSystemMenu];
FormB.BorderStyle := bsNone;
FormB.Show;
FormB.SetFocus;
FormB.OnActivate(Sender); // There is a code in OnActivate event in FormB
end ;
procedure TFormHome.Action3Execute(Sender: TObject);
// Action3 OnExecute event, called from ToolButton3
// This is the desired code to implment in all Action OnExecute event
begin
PR_CreateOpenForm(TFormC); // Fails in the OnActivate event
end;
procedure TFormHome.PR_CreateOpenForm(PClassform : TFormClass);
// This routine should be used to create/open all forms
//
var
vform : TForm;
begin
if Not Assigned(Tform(PClassform)) then
begin
vform := Pclassform.Create(Application);
end;
vform.Parent := PanelHome;
vform.Align := alclient;
vform.BorderIcons := [biSystemMenu];
vform.BorderStyle := bsNone;
vform.Show;
vform.SetFocus;
vform.onActivate(self); // Does not work !! Tried with : vform.Onactivate(nil) - vform.Onactivate(Tform)
end;
end.
FORMA - OnActivate事件
procedure TFormA.FormActivate(Sender: TObject);
begin
Edit1.Text := 'content from OnActivate';
end;
FORMB - OnActivate事件
procedure TFormB.FormActivate(Sender: TObject);
begin
Edit1.Text := 'content from OnActivate';
end;
FORMC - OnActivate事件
procedure TFormC.FormActivate(Sender: TObject);
begin
Edit1.Text := 'content from OnActivate';
end;
调用PR_CreateOpenForm(TFormC)时出错
DEBUG - 逐步运行此事件处理程序错误:
procedure TWinControl.MainWndProc(var Message: TMessage);
begin
try
try
WindowProc(Message);
finally
FreeDeviceContexts;
FreeMemoryContexts;
end;
except
Application.HandleException(Self);
end;
end;
如果我必须提供任何其他信息/代码,请告知我们,以便获得您的建议和宝贵的提示!
谢谢你们!
答案 0 :(得分:0)
尝试将正在运行的OpenDiretorioExecute方法更改为下面显示的代码,并告诉我您是否仍然收到错误。在PR_OpenForm中使用vform.OnActivate(Self)。还请显示TFormDiretorio的OnActivate事件处理程序。
procedure TFormHome.OpenDiretorioExecute(Sender: TObject);
begin
FormDiretorio:=PR_OpenForm(TFormDiretorio) as TFormDiretorio;
(* if Not Assigned(FormDiretorio) then
begin
FormDiretorio := TFormDiretorio.Create(Self);
FormDiretorio.Parent := PanelCorpo;
FormDiretorio.Align := alclient;
FormDiretorio.BorderIcons := [biSystemMenu];
FormDiretorio.BorderStyle := bsNone;
FormDiretorio.Show;
FormDiretorio.SetFocus;
FormDiretorio.OnActivate(Sender); // In this way , OnActivate works fine
end; *)
end;
更改PR_OpenForm以返回vForm。我假设您需要变量FormDiretorio。
答案 1 :(得分:0)
错误出现在这段代码中:
if Not Assigned(TForm(PClassform)) then
begin
vform := PClassform.Create(Application);
end;
如果您查看源代码以实现Assigned()
,您将看到它只检查传入的参数是否为零。因此,您可能认为代码不会检查是否存在PClassForm
类型的表单。它仅检查参数PClassForm
是否为零。
在您的情况下Assigned()
返回true
,表单未创建,随后vform
包含堆栈中发生的任何内容。它只会在您调用OnActivate()的行中崩溃,这只是一个巧合。您可能通过访问未初始化的vform
变量来销毁重要数据(可能还有)。
为防止此类错误致命,您应将本地指针变量初始化为nil
(如果它们可能保持未初始化状态)。你可能也有一个编译器警告,但忽略了它。
早些时候我想问你在哪里打算对你创建的表单进行引用,以便你可以访问它们,但我没有,因为这不是你的问题。
您需要对此进行决定,然后使用这些引用来检查存在并访问表单。
答案 2 :(得分:0)
<强>更新强>
您在评论中提问
关键是:给定TformClass类的参数PClassForm,如何检查在Application中是否创建了这样的参数实例? &#34; ,
您可以使用下面FormInstance
之类的功能执行此操作。 VCL应用程序的Screens
对象具有Forms
属性,您可以迭代它,查看其中一个表单是否为指定类,并将其作为函数的结果返回(否则为Nil)。一旦找到了实例,你当然可以使用强制转换来调用它的一些特定方法。
function FormInstance(AClass : TClass) : TForm;
var
i : Integer;
begin
Result := Nil;
for i := 0 to Screen.FormCount - 1 do begin
if Screen.Forms[i].ClassType = AClass then begin
Result := Screen.Forms[i];
Break;
end;
end;
end;
procedure TMyForm.Button1Click(Sender: TObject);
var
F : TForm;
begin
F := FormInstance(TForm2);
if F <> Nil then
Caption := 'Found'
else
Caption := 'Not found';
end;
原始回答您编写q的方式似乎纠结了您的实际技术问题
vform.OnActivate(??); //这是问题,如何调用此事件?
有很多与之无直接关系的问题。而是尝试
调用OnActivate
处理程序(如果有),可能会更好
覆盖表单的Activate
过程,以执行您想要的任何特殊处理
然后将其留给TForm
中的代码,以决定何时调用OnActivate
。这不太可能导致其他形式的行为错误(如TScreen
)。
下面的代码显示了如何执行此操作。
type
TForm1 = class(TForm)
procedure FormActivate(Sender: TObject);
protected
procedure Activate; override;
public
end;
[...]
procedure TForm1.Activate;
begin
inherited;
Caption := Caption + ' called from TForm1.Activate';
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
Caption := 'Activated';
end;
当然,也许您可以将OnActivate中要执行的代码放在OnShow处理程序中。