按钮事件 — ViewRun 处理器
示例的所有用户操作都从 ViewRun.xms 的 6 个点击处理器 开始。每个处理器只一行,调用 Data:: 模块函数 — 业务逻辑与 UI 事件干净分离。
ViewRun(UI 事件) Data(DB 业务逻辑)
───────────────────────── ──────────────────────────
OnOpenClick ───► DB_Open()
OnAddClick ───► DB_InsertSample()
OnUpdateClick ───► DB_UpdateSelected()
OnModifyClick ───► DB_OpenModifyDlg() ──► GUI.ShowDialog → DB_UpdateModified()
OnDeleteClick ───► DB_DeleteSelected()
OnCloseClick ───► DB_Close()1) 按钮处理器标准签名
QMachineStudio 的点击处理器签名都一样。
FUNCTION OnXxxClick(string sender, int tag, array params)
{
// sender : 按钮控件名
// tag : 按钮的 Tag 属性值(分类用)
// params : 附加参数(大多不使用)
Data::DB_Xxx();
}示例的 6 个处理器都是一行 wrapper,都在调用 Data:: 函数。
FUNCTION OnOpenClick (string sender, int tag, array params) { Data::DB_Open(); }
FUNCTION OnAddClick (string sender, int tag, array params) { Data::DB_InsertSample(); }
FUNCTION OnUpdateClick (string sender, int tag, array params) { Data::DB_UpdateSelected(); }
FUNCTION OnModifyClick (string sender, int tag, array params) { Data::DB_OpenModifyDlg(); }
FUNCTION OnDeleteClick (string sender, int tag, array params) { Data::DB_DeleteSelected(); }
FUNCTION OnCloseClick (string sender, int tag, array params) { Data::DB_Close(); }这种分离带来的好处:
- DB 函数可独立单元测试 — 没有 UI 也能验证。
- 同一函数可在其他画面(
ViewMain)或时序中直接复用。 - 调试时立刻能区分问题出在事件侧还是 DB 调用侧。
2) 按钮与处理器的连接
在 ViewRun 设计模式中,把每个按钮的 Click 事件 → Function 名称 设置如下。
| 按钮(Caption) | 控件名 | Click 事件函数 |
|---|---|---|
| Open | BtnOpen | OnOpenClick |
| Add | BtnAdd | OnAddClick |
| Update | BtnUpdate | OnUpdateClick |
| Modify | BtnModify | OnModifyClick |
| Delete | BtnDelete | OnDeleteClick |
| Close | BtnClose | OnCloseClick |
(sender, tag, params)参数始终接收但函数体一般忽略。多个按钮共用一个处理器并按tag分支时才有意义。
3) ModifyDlg 流程 — 两步调用
Modify 按钮与其他处理器不同,需要 模态对话框调用 + 结果分支。实际分支放在 Data::DB_OpenModifyDlg() 内部,所以 ViewRun 侧依然是一行。
[Modify 点击]
│
▼
ViewRun.OnModifyClick
│
▼
Data.DB_OpenModifyDlg
│
├─ 1. 选中行 SELECT → 复制到 Edit* 字段
├─ 2. GUI.ShowDialog("ModifyDlg")
│ │
│ ├─ true (OK) ──► DB_UpdateModified() → DB_Refresh()
│ └─ false (Cancel) ──► 直接返回
│
▼
返回GUI.ShowDialog 在 调用点阻塞 — 对话框关闭前下一行不会执行。因此 OnModifyClick 的一行调用结束时刻就是 用户按下 OK 或 Cancel 之后。
对话框内部事件
ModifyDlg.xms 自身没有业务逻辑 — 仅有诊断用日志。
FUNCTION OnShow()
{
// 对话框显示前 - 编辑字段已由调用方填好
Log($"ModifyDlg OnShow : id={Data::EditId} order_no={Data::EditOrderNo}");
}
FUNCTION OnHide()
{
// 对话框关闭后
}OK / Cancel 两个按钮只需设置 DialogResult,实际的 UPDATE 在调用方 DB_OpenModifyDlg 中根据 ShowDialog 的返回值分支处理。对话框无需知道自身的业务逻辑 — 利于复用。
4) 与 Init / Mon / Event 的关系
示例项目还包含以下模块 — 与 DB 没有直接关系,但属于一般自动化项目的标准结构,简单提及。
| 模块 | 类型 | 用途 |
|---|---|---|
Init | Init | 启动时执行 1 次 — 数据初始化、塔灯设置 |
Mon | Monitor | 周期监控 — Door / IO / 安全等 |
Event | Event | 事件接收(通信、外部信号) |
Data | Monitor | 本教程主角 — 持有 DB 函数 |
Work | Sequence | 主时序(与 DB 无关) |
将 DB 工作放入 Data 模块,是为了 与设备时序(Work)相分离。即使 DB 短暂中断,时序也必须继续运行;时序只调用 Data::DB_* 函数即可。
下一章
接下来是备份与运维 — WAL 模式、BackupFolder、自动备份选项。