Database 手册 · Chapter 8

按钮事件 — 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 事件函数
OpenBtnOpenOnOpenClick
AddBtnAddOnAddClick
UpdateBtnUpdateOnUpdateClick
ModifyBtnModifyOnModifyClick
DeleteBtnDeleteOnDeleteClick
CloseBtnCloseOnCloseClick

(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 没有直接关系,但属于一般自动化项目的标准结构,简单提及。

模块类型用途
InitInit启动时执行 1 次 — 数据初始化、塔灯设置
MonMonitor周期监控 — Door / IO / 安全等
EventEvent事件接收(通信、外部信号)
DataMonitor本教程主角 — 持有 DB 函数
WorkSequence主时序(与 DB 无关)

将 DB 工作放入 Data 模块,是为了 与设备时序(Work)相分离。即使 DB 短暂中断,时序也必须继续运行;时序只调用 Data::DB_* 函数即可。

下一章

接下来是备份与运维 — WAL 模式、BackupFolder、自动备份选项。