버튼 이벤트 — ViewRun 핸들러
샘플의 모든 사용자 동작은 ViewRun.xms 의 6 개 클릭 핸들러 를 통해 시작됩니다.
각 핸들러는 한 줄로 Data:: 모듈 함수 호출만 하는 얇은 layer 라, 비즈니스 로직과
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 개 핸들러는 모두 Data:: 함수를 호출하는 한 줄짜리 wrapper 입니다.
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 을 누른 뒤 입니다.
Dialog 내부 이벤트
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, 자동 백업 옵션을 정리합니다.