FormShow 为什么执行两次

本文探讨了一个常见的MDI窗体编程问题——FORMSHOW事件被触发多次的情况及其解决方案。作者通过调整代码逻辑,引入一个布尔变量iFirstExecute来确保FORMSHOW中的关键代码仅被执行一次。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以前就发现过这个问题,但一直没有在意。昨天一个窗体FORMSHOW执行了两次,对数据有影响,于是搜索了一下这个问题的答案。

Since your other thread finally gave your situation, it was very easy to find the problem:
AForm.Position := poMainFormCenter;

This calls Perform(CM_RECREATEWND, 0, 0); which will execute an immediate recreate of the form.

这种情况多发生在MDI的窗体中。

解决的办法:
如果你不能干掉AForm.Position语句,那么可以设置一个变量来记录执行次数。

var iFirstExecute:boolean;
formCreate{
iFirstExecute:=true;
}

formShow{
if not iFirstExecute then exit;
// code of do sth.
iFirstExecute:=false;
}

<think>好的,用户问的是Delphi中一段代码的意思,具体是: procedure TFsubject.FormShow(Sender: TObject); begin inherited; Cpanel.ActiveCard := Card1; end; 首先,我需要理解这段代码的结构。用户可能刚接触Delphi,或者对事件处理不太熟悉。首先,确定这是一个FormShow事件的处理程序。当窗体显示时触发这个事件。 inherited; 这一行是调用父类的方法,确保继承链中的方法被执行,保持VCL框架的正常运作。可能用户不知道inherited的作用,需要解释清楚。 接下来是Cpanel.ActiveCard := Card1; 这里的Cpanel可能是一个TPanel或者更可能是TCardPanel(因为ActiveCard属性常见于TCardPanel)。TCardPanel用于管理多个卡片,切换显示不同的卡片。ActiveCard设置为Card1,意味着在窗体显示时,默认显示Card1这个卡片。 用户可能想知道这段代码的具体功能,以及为什么这样写。需要解释FormShow事件的触发时机,inherited的必要性,以及TCardPanel的作用。同时,用户可能是在学习如何动态切换界面中的不同部分,或者遇到了卡片未正确显示的问题,需要确认代码是否正确。 另外,用户之前的问题是关于如何在打开页面时调用函数,所以可能这段代码是他们实现的一部分,现在想确认其正确性或理解其含义。需要确保解释清晰,帮助他们理解代码逻辑,并可能给出使用建议,比如检查组件命名是否正确,是否存在Card1等。 还要考虑用户可能的错误点,比如是否Cpanel确实有ActiveCard属性,或者Card1是否属于Cpanel的子组件。如果有拼写错误或组件未正确放置,可能导致运行时错误。因此,在解释代码的同时,提醒他们检查这些点也是必要的。 最后,总结代码的作用:在窗体显示时,设置Cpanel的活动卡片为Card1,确保用户看到的是Card1对应的界面。同时,强调inherited的重要性,确保父类的方法执行,避免潜在的问题。</think>以下是您提供的Delphi代码解析: --- ### **代码结构解析** ```delphi procedure TFsubject.FormShow(Sender: TObject); begin inherited; // 关键点1:继承父类方法 Cpanel.ActiveCard := Card1; // 关键点2:卡片面板操作 end; ``` --- ### **逐行解读** #### 1. `inherited;` - **作用**:显式调用父类的`FormShow`方法 - **必要性**: - 确保VCL框架的基础窗体显示逻辑正常执行 - 避免因覆盖父类方法导致窗体渲染异常 - **等效写法**:`inherited FormShow(Sender);` #### 2. `Cpanel.ActiveCard := Card1;` - **组件要求**: - `Cpanel`应为`TCardPanel`组件(FireMonkey框架)或`TPageControl`组件(VCL框架) - `Card1`必须是`Cpanel`的子卡片组件 - **功能效果**: - 设置卡片面板默认显示的初始卡片 - 相当于界面初始化时自动切换到指定卡片页 --- ### **运行时机示意图** ```mermaid sequenceDiagram participant 系统 participant 窗体 as TFsubject 系统->>窗体: 执行Form.Show() 窗体->>窗体: 触发FormShow事件 窗体->>父类: 执行inherited父类方法 窗体->>Cpanel: 设置ActiveCard为Card1 窗体-->>系统: 完成窗体显示 ``` --- ### **典型应用场景** 1. **多步骤表单**:向导式界面初始化时自动定位到第一步 2. **选项卡控制**:根据用户权限预设默认可见的功能面板 3. **状态恢复**:程序重启后自动还原上次操作的界面状态 --- ### **调试建议** 1. **组件验证**: ```delphi Assert(Assigned(Cpanel), 'Cpanel 组件未初始化'); Assert(Assigned(Card1), 'Card1 卡片不存在'); ``` 2. **执行顺序检查**: - 在`inherited`前后设置断点,确认父类方法是否正常执行 3. **可视化验证**: - 在窗体设计器中检查`Card1`的`Index`属性是否与预期一致 --- ### **扩展对比** | 事件 | 执行时机 | 适用操作类型 | |-----------|-----------------------|----------------------| | OnCreate | 窗体对象创建时(界面未渲染) | 初始化非可视化数据、创建动态组件 | | OnShow | 窗体首次显示/从隐藏恢复时 | 界面状态控制、权限校验 | | OnActivate| 窗体获得焦点时(可能多次触发) | 数据刷新、动画启动 | --- ### **常见问题排查** 1. **卡片不显示**: - 检查`Card1`是否属于`Cpanel`的子组件 - 确认`Card1.Visible`属性为`True` 2. **访问违规错误**: - 确保不在`FormCreate`中过早操作卡片面板 - 使用`if Assigned(Cpanel) then`进行安全调用 3. **布局异常**: - 检查卡片面板的`Align`属性设置 - 验证父容器的`AutoSize`属性配置 需要进一步了解具体应用场景的实现细节,可以补充说明需求背景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值