DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: kmh
今日帖子: 20
在线用户: 14
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 guxiang (hanxin) ★☆☆☆☆ -
盒子活跃会员
2020/8/19 17:25:13
标题:
创建新的form的一个问题 浏览:444
加入我的收藏
楼主: procedure SwitchForm(pLastForm, pNextForm: tform; pNextFormType: tcomponentclass);
begin
  application.CreateForm(pNextFormType, pNextForm);
  pNextForm.Show;
  FreeAndNil(pLastForm);
end;

我调用以上方法来创建form同时释放当前form,但是遇到一个奇怪的问题,就是在pNextForm的create事件中创建的动态控件在form上不显示,设计时控件则没问题,但测试发现create确实被执行了。

而如果不封装这个方法,在创建新form时直接写方法内的这三行代码就没有问题。
----------------------------------------------
-
作者:
男 kaida (kaida) ★☆☆☆☆ -
盒子活跃会员
2020/8/19 17:31:50
1楼: procedure SwitchForm(pLastForm, pNextForm: tform; pNextFormType: tcomponentclass);
begin
  application.CreateForm(pNextFormType, pNextForm);
  pNextForm.Show;//窗体还在显示中
  FreeAndNil(pLastForm);//怎么允许释放?
end;
----------------------------------------------
http://down.desei.com.cn/down/1041485/MyWeb/VCLs.html
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2020/8/19 20:59:23
2楼: 楼主的问题,确实是一个问题。相当于你在一个对象的事件代码里面把这个对象释放了。会不会出问题,需要仔细研究。

其实可以换个思路来达到相同的效果。

不就是想要有新的界面,然后又不想占用更多资源嘛。假设资源很多,之前的 Form 是不用释放的。

那么可以换一个思路,一个 Form 可以实现多个 Form 的功能。办法就是使用 TFrame。在一个 Form 里面,切换界面时就是创建新的 Frame,释放之前的 Frame。
----------------------------------------------
-
作者:
男 guxiang (hanxin) ★☆☆☆☆ -
盒子活跃会员
2020/8/20 10:36:32
3楼: @kaida 我没明白你的意思,我显示的窗体和释放的窗体不是一个窗体啊,为什么不允许?

@pcplayer 用frame当然可以,我只是想知道原因是啥,因为同样的代码直接写就没问题,封装成方法就不行,所以就觉得很奇怪。

另外最关键的就是,就算不执行freeandnil这行代码,新form上还是不显示动态创建的控件。所以问题应该不是出在释放原form上。
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2020/8/20 10:58:06
4楼: 发出来的代码和你描述的 控件不显示 有关系吗?

出问题的代码,是保密的。我们理解。
反正 我们自己写的 动态控件建立,从来不出问题就行了。你写的,出问题很正常。因为是你写的啊。

你发一个和问题无关的代码,还怪1楼的 没看懂。
我觉得 1楼就是 粗心大意 没仔细看而已。
反正 看懂了,又不能解决问题。不仔细看 反而不会浪费时间。

2楼 出谋划策了,反而浪费了他的宝贵时间。结果 你还不领情。

我不回复,也就不浪费时间了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 guxiang (hanxin) ★☆☆☆☆ -
盒子活跃会员
2020/8/20 11:05:16
4楼: 啊,我貌似发现了问题,比如创建的是form2,form2的所有事件中调用自身实际上调用的都不是新创建的这个实例,assigned(form2)返回的也是false,因此所有调用form2的代码都会报错,比如给form2上的某个控件赋值。也就是说,动态控件必须create到这个新实例上,否则就不会显示。

但是我不知道该怎么解决这个问题。貌似引用类参数也不能用于控件。
----------------------------------------------
-
作者:
男 kenliaoliao (ben) ★☆☆☆☆ -
普通会员
2020/8/20 11:07:41
5楼: 把动态创建控件的代码贴出来呀
----------------------------------------------
-
作者:
男 guxiang (hanxin) ★☆☆☆☆ -
盒子活跃会员
2020/8/20 11:10:26
5楼: @wang_80919 你是吃了炝药了吗?老是针对我干嘛?还整天挑拨离间,你是童年有啥阴影吗?真是忍你一次两次你还得寸进尺了。
你不想回答就别回答,我也没求着你来回答,我发的贴子你老来下面凑热闹干嘛?
我的代码也没啥可保密的,出问题的代码就这么几行我把所有代码贴出来干嘛?浪费大家时间吗?你时间不值钱不代表其他人时间也不值钱。
----------------------------------------------
-
作者:
男 guxiang (hanxin) ★☆☆☆☆ -
盒子活跃会员
2020/8/20 11:16:02
6楼: @kenliaoliao 这也需要贴吗?不就是正常的创建动态控件吗
比如
var label1:tlabel;

label1:=tlabel.create(self);
label1.parent:=form名;//问题就出在这句,实际parent并没有指向创建出来的实例,所以没有显示,我在上面的回复中已经提到了。

我明白你的意思可能是我代码写错了,我也说了不封装方法都没问题的,说明我创建动态控件的代码没问题,而且我也新建过简单项目测试过了,结果一样,所以我才没贴创建的代码。
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2020/8/20 11:19:22
7楼: 我也没打算回答啊。
2ccc 又不是你家开的。
我只是 认为 你 不提供 出错的代码。浪费时间而已。

你不喜欢 我的发言,就当没看见不行吗?

我看你才是容易动气啊。动气对身体不好。

不过,千万不要发 出错代码啊,你发了,就是被我说动了。你就输了。

可惜,你已经发了一部分了,没关系,不要继续发就行了,否则 你就输了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 kaida (kaida) ★☆☆☆☆ -
盒子活跃会员
2020/8/20 12:25:10
8楼: 确实是我粗心了。
大家消消火气。
估计是动态创建的控件没有正确设置父控件。瞎猜的。wang_80919 说的对,没有相关代码,不好判断。
----------------------------------------------
http://down.desei.com.cn/down/1041485/MyWeb/VCLs.html
作者:
男 emailx45 (emailx45) ▲▲▲△△ -
注册会员
2020/8/20 12:59:01
9楼: FormSecond and FormThird is not created automatically

---------- FormMain ----------
unit uFormMain;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TfrmFormMain = class(TForm)
    btnCreateFormSecond: TButton;
    btnCreateFormThird: TButton;
    btnFormOnMemory: TButton;
    procedure btnCreateFormSecondClick(Sender: TObject);
    procedure btnCreateFormThirdClick(Sender: TObject);
    procedure btnFormOnMemoryClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmFormMain: TfrmFormMain;

implementation

{$R *.dfm}
//
// ReportMemoryLeaksOnShutdown := true; // in DPR file for report leak memory!
//

uses
  uUnitGlobalFunctions,
  uFormSecond,
  uFormThird;

procedure TfrmFormMain.btnCreateFormSecondClick(Sender: TObject);
var
  lMyNewForm: TForm;
begin
  lMyNewForm := prcCreateMyNewForm(TfrmFormSecond);
  //
  if not(lMyNewForm = nil) then
    lMyNewForm.ShowModal;
end;

procedure TfrmFormMain.btnCreateFormThirdClick(Sender: TObject);
var
  lMyNewForm: TForm;
begin
  lMyNewForm := prcCreateMyNewForm(TfrmFormThird);
  //
  if not(lMyNewForm = nil) then
    lMyNewForm.ShowModal;
end;

procedure TfrmFormMain.btnFormOnMemoryClick(Sender: TObject);
begin
  prcHowFormsOnMemory;
end;

procedure TfrmFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  try
    prcCloseAllFormsOnMemory;
  except
    on E: Exception do
    begin
      Action := TCloseAction.caNone;
      ShowMessage('My error:' + sLineBreak + E.Message);
    end;
  end;
end;

end.
---------- Global functions -------
unit uUnitGlobalFunctions;

interface

uses
  System.SysUtils,
  Vcl.Forms,
  Vcl.Dialogs;

procedure prcHowFormsOnMemory;
procedure prcCloseAllFormsOnMemory;
function prcCreateMyNewForm(lNewFormClass: TFormClass): TForm;

var
  OldFormToClose: TForm;

implementation

uses
  uFormMain;

function prcCreateMyNewForm(lNewFormClass: TFormClass): TForm;
var
  i: integer;
begin
  // is not possible delete and re-create same form on screen
  if (not(OldFormToClose = nil)) and (OldFormToClose.ClassName = lNewFormClass.ClassName) then
  begin
    result := OldFormToClose;
    ShowMessage('same class is not possible delete it for while');
    exit;
  end;
  //
  if (not(OldFormToClose = nil)) and { }
    (not(OldFormToClose = frmFormMain)) then
  begin
    FreeAndNil(OldFormToClose);
  end;
  //
  result := lNewFormClass.Create(nil); // "nil", user should "free" this object!
  //
  OldFormToClose := result;
end;

procedure prcHowFormsOnMemory;
var
  i    : integer;
  lText: string;
begin
  lText   := '';
  for i   := 0 to (Screen.FormCount - 1) do
    lText := Screen.Forms[i].Name + sLineBreak + lText;
  //
  ShowMessage('Forms on memory:' + sLineBreak + lText);
end;

procedure prcCloseAllFormsOnMemory;
var
  i: integer;
begin
  for i := 0 to (Screen.FormCount - 1) do
  begin
    if not(Screen.Forms[i] = frmFormMain) then
      Screen.Forms[i].Free;
  end;
end;

end.
---------- FormSecond ----------
unit uFormSecond;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TfrmFormSecond = class(TForm)
    btnFormOnMemory: TButton;
    procedure btnFormOnMemoryClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmFormSecond: TfrmFormSecond;

implementation

{$R *.dfm}

uses
  uUnitGlobalFunctions;

procedure TfrmFormSecond.btnFormOnMemoryClick(Sender: TObject);
begin
  prcHowFormsOnMemory;
end;

end.
---------- Form Third ----------

unit uFormThird;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TfrmFormThird = class(TForm)
    btnFormOnMemory: TButton;
    btnRecreateFormThird: TButton;
    procedure btnFormOnMemoryClick(Sender: TObject);
    procedure btnRecreateFormThirdClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmFormThird: TfrmFormThird;

implementation

{$R *.dfm}

uses
  uUnitGlobalFunctions;

procedure TfrmFormThird.btnFormOnMemoryClick(Sender: TObject);
begin
  prcHowFormsOnMemory;
end;

procedure TfrmFormThird.btnRecreateFormThirdClick(Sender: TObject);
begin
  prcCreateMyNewForm(TfrmFormThird);
end;

end.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 iamdream (银河恒久远,梦想无止境!) ★☆☆☆☆ -
大贡献会员
2020/8/20 13:49:35
10楼: 如果你是窗口的OnCreate里创建,则应该这样写:
label1 := TLabel.Create(Self);
label1.Parent:= Self;
labe1l.Left := 123;
label1.Top := 22;
----------------------------------------------
-广袤璀璨的银河,永无止境的梦想(梦无止境游银河) 博客挂了……
作者:
男 emailx45 (emailx45) ▲▲▲△△ -
注册会员
2020/8/20 13:57:37
11楼: 按此在新窗口浏览图片
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲△△ -
注册会员
2020/8/20 14:17:49
12楼: add this "uses"

  Vcl.StdCtrls,
  Vcl.Graphics,
----------

function prcCreateMyNewForm(lNewFormClass: TFormClass): TForm;
var
  i       : integer;
  lMyLabel: TLabel;
begin
  if (not(OldFormToClose = nil)) and (OldFormToClose.ClassName = lNewFormClass.ClassName) then
  begin
    result := OldFormToClose;
    ShowMessage('same class is not possible delete it for while');
    exit;
  end;
  //
  if (not(OldFormToClose = nil)) and { }
    (not(OldFormToClose = frmFormMain)) then
  begin
    FreeAndNil(OldFormToClose);
  end;
  //
  result          := lNewFormClass.Create(nil); // "nil", user should "free" this object!
  lMyLabel          := TLabel.Create(result);
  lMyLabel.Name       := 'MyLabel1';
  lMyLabel.Caption    := 'Hello World';
  lMyLabel.Left       := result.Width - (result.Canvas.TextWidth('W') * Length(Trim(lMyLabel.Caption)));
  lMyLabel.Top        := 20;
  lMyLabel.Font.Color := clWhite;
  // ....
  lMyLabel.Parent := result; // use for last!
  //
  OldFormToClose := result;
end;



按此在新窗口浏览图片
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2020/8/20 14:35:51
13楼: 国际友人的代码好长,值得学习。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2020/8/20 22:00:51
14楼: 动态创建窗口比动态创建控件要复杂些,稍不小心就AV,这些AV主要在释放窗口时出现,特别是动态创建的窗体里又还有复杂的动态创建组件、对象时更容易AV,而动态创建窗口又是构建复杂项目所必须的,同时动态创建对象也是构建复杂系统所必须的。
很奇怪,如果动态创建窗口用动态创建Frame替代,一样的代码,也错会少很多,当然不小心也会AV,但主要记住创建和销毁一一对应,一般是不会出错的。
原因还没找到,可能与vcl创建窗口的消息机制相关,因为form并不是一个普通的vcl对象,正如dll里创建form总有理不清的问题一样。
所以,我的建议是,用tframe替代tform,构建复杂系统。
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2020/8/20 23:56:03
15楼: 简单的方法:在创建的窗体里释放前一个窗体。前一个窗体的引用可以赋给一个全局的变量或传递到新窗体里(比较适用于只保持一个窗体Duck在一个PANEL或layout中的情况),
正如14楼说的,如果是DUCK显示窗体,一般用FRAME来显示比较好
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2020/8/21 7:51:11
16楼: 你的创建窗体函数是没有问题的。问题出在你的调用代码;

TfrmFormSecond(prcCreateMyNewForm(TfrmFormSecond)).Show;


注:
 创建窗体函数其实有一个小问题。程序自动释放上一个窗体,和用户关闭窗体释放窗体,你没有区分开。
----------------------------------------------
Delphi7爱好者
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2020/8/21 11:36:06
17楼: 14 楼
Create 的 第一个参数 AOnwer 你要懂了,就能少一些 AV。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2020/8/21 16:20:04
18楼: 创建窗体,释放窗体。我的代码里面很多,没碰到过什么问题。

我以前的程序喜欢创建窗体然后把这个窗体放进另外一个窗体。
----------------------------------------------
-
作者:
男 hawke2e (hawke2e) ▲▲▲▲▲ -
注册会员
2020/8/21 18:08:17
19楼: 答主接触delphi即使超过1年也不会超多少。
application.CreateForm(pNextFormType, pNextForm); 的处理过程:
1. 调用pNextFormType的constructor
   1.1 分配窗体以及所有控件的空间
   1.2 调用pNextFormType.Create的本级代码
2. 从dfm里把控件的属性读取出来设置
3. 触发OnCreate事件

答主是把动态创建的代码写到pNextFormType.Create里了是吧? 设计阶段2和3不会发生所以没问题,运行时有了2,其它控件覆盖了动态创建的控件

----------
吐槽一下delphi的RAD,borland当年设计RAD时,既没想透RAD这件事,也没做好。
就说2点:
1. RAD的威力在于在运行时能不停系统而改变设计,显然delphi做不到
2. 一个TComponent把设计的事跟运行的事混了起来,稍不注意就引入bug
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
男 guxiang (hanxin) ★☆☆☆☆ -
盒子活跃会员
2020/8/21 20:09:23
20楼: 感谢楼上诸位回答,我终于知道问题在哪里了。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v2.1 版权所有 页面执行46.875毫秒 RSS