Progress ABL如何捕获UI事件触发错误并传递至主程序块
UI事件触发的错误透传到主块捕获方案
问题描述
在Progress ABL程序中存在如下场景:
- F6按键事件负责更新
ttnom临时表数据 fill_tt过程执行时如果检测到临时表为空,会抛出PROGRESS.lang.apperror('Temp-table is empty')异常
需要确认是否可以让该异常从F6事件处理逻辑透传到程序主块,被主块的CATCH块捕获,而非在事件内部被拦截处理。
对应示例代码如下:
BLOCK-LEVEL ON ERROR UNDO, THROW. DEFINE VARIABLE inomtr AS i NO-UNDO. DEFINE VARIABLE lexit AS L NO-UNDO. DEFINE TEMP-TABLE ttnom NO-UNDO FIELD uid AS int64 INDEX idx1 IS unique uid. DEFINE FRAME fupd SKIP(1) inomtr FORMAT '>>>>>>>>>>>>9' NO-LABEL SKIP(1) WITH VIEW-AS DIALOG-BOX SIDE-LABELS. ON GO OF FRAME fupd DO: _t1: DO ON ERROR UNDO, RETURN NO-APPLY: ASSIGN inomtr. IF CAN-FIND (FIRST ttnom NO-LOCK WHERE ttnom.uid = inomtr) THEN LEAVE _t1. MESSAGE 'inomtr not found' VIEW-AS ALERT-BOX. RETURN NO-APPLY. END. END. ON F3 OF inomtr IN FRAME fupd DO: RUN choose_nom(OUTPUT inomtr). END. ON F6 of FRAME fupd ANYWHERE DO: DO ON ERROR UNDO, THROW : RUN fill_tt. CATCH ERROR AS PROGRESS.lang.error: message error:GetMessage(1) + return-value VIEW-AS ALERT-BOX. lexit = YES. STOP. END CATCH. END. RETURN NO-APPLY. END. _tr: DO ON ERROR UNDO, THROW ON STOP UNDO, LEAVE ON ENDKEY UNDO, LEAVE: RUN fill_tt. DO WHILE TRUE ON ERROR UNDO, throw ON STOP UNDO , RETRY ON ENDKEY UNDO , RETRY : IF RETRY OR lexit = yes THEN DO: IF lexit = NO THEN MESSAGE 'Exit?' VIEW-AS ALERT-BOX BUTTONS YES-NO UPDATE lexit. IF lexit = YES THEN LEAVE _tr. END. DISPLAY WITH FRAME fupd. ENABLE inomtr WITH FRAME fupd. WAIT-FOR GO OF FRAME fupd. RUN do_nomtr(inomtr). END. CATCH ERROR AS PROGRESS.lang.error: message ERROR:GetMessage(1) + RETURN-VALUE VIEW-AS ALERT-BOX. END CATCH. END. PROCEDURE do_nomtr: DEFINE INPUT PARAM inomtr AS i NO-UNDO. MESSAGE inomtr VIEW-AS ALERT-BOX. END PROCEDURE. PROCEDURE fill_tt: DO ON ERROR UNDO, THROW: DISPLAY 'Loading temp-table' WITH FRAME ftt VIEW-AS DIALOG-BOX. EMPTY TEMP-TABLE ttnom. FOR EACH link NO-LOCK WHERE link.type = 3 AND link.class-code = '1B' AND link.file-name = 'r-goods' AND link.arch = no ON ERROR UNDO, THROW: IF CAN-FIND(FIRST ttnom WHERE ttnom.uid = link.link-num) THEN NEXT. CREATE ttnom. ASSIGN ttnom.uid = link.link-num. END. HIDE FRAME ftt NO-PAUSE. IF NOT TEMP-TABLE ttnom:HAS-RECORDS THEN UNDO, THROW NEW PROGRESS.lang.apperror('Temp-table is empty'). END. END PROCEDURE.
核心结论
ABL的UI事件触发器运行在独立的UI消息循环调用栈上,原生不支持异常自动跨栈透传到WAIT-FOR所在的主块,但可以通过错误暂存+主动重抛的方式实现需求。原代码无法透传的原因有两个:
- F6事件块内部直接写了
CATCH块拦截异常,且在块内执行STOP语句直接终止了错误传播流程 - 事件触发的调用栈和主块调用栈隔离,未捕获的事件异常默认会被UI运行时拦截,不会自动传到主块的
CATCH
改造步骤
- 新增模块级错误变量,用于暂存事件处理过程中产生的异常
DEFINE VARIABLE oEventError AS Progress.Lang.Error NO-UNDO. - 改造F6事件块,移除内部直接弹框、
STOP的处理逻辑,捕获异常后暂存到变量,标记退出状态即可ON F6 of FRAME fupd ANYWHERE DO: DO ON ERROR UNDO, THROW : RUN fill_tt. CATCH err AS PROGRESS.lang.error: oEventError = err. lexit = YES. END CATCH. END. RETURN NO-APPLY. END. - 在主块
WAIT-FOR语句执行完成后,立刻检查暂存的错误对象,如果存在有效错误则主动抛出,异常就会被主块的CATCH块统一捕获处理WAIT-FOR GO OF FRAME fupd. /* 主动重抛事件处理中产生的异常 */ IF VALID-OBJECT(oEventError) THEN DO: UNDO, THROW oEventError. END. RUN do_nomtr(inomtr).
注意事项
- 不要在事件处理的CATCH块中使用
STOP、RETURN ERROR这类会直接终止事件上下文的语句,否则异常会丢失 - 如果需要统一处理多个UI事件的错误,只需要让所有事件的CATCH块都把异常赋值给同一个
oEventError变量即可 - 不要尝试给
WAIT-FOR语句加ON ERROR UNDO, THROW来捕获事件异常,该配置仅能捕获WAIT-FOR语句本身的错误,无法捕获其派发的事件触发器内抛出的错误
内容的提问来源于stack exchange,提问作者Александр Овчинников
相关产品推荐
相关产品推荐

