找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 14255|回复: 30

[教学] 【牢固】和我一起学OpenDCl对话框程序设计【二】模态对话框与CAD的交互

[复制链接]

已领礼包: 344个

财富等级: 日进斗金

发表于 2013-5-4 15:55:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 牢固 于 2013-5-4 16:23 编辑

我借用OpenDcl自带的实例Selections.lsp来介绍一下模态对话框和CAD之间交互应用的技巧和方法,先看下这个应用程序的演示:

该程序演示了模态对话框打开后,点击选择按钮,然后对话框关闭,在CAD屏幕进行相关操作,然后又如何返回到对话框的运行机制。下面我逐步介绍一下:
首先,加载对话框:
[pcode=lisp,true]    ;; 加载OpenDcl
    (setq cmdecho (getvar "CMDECHO"))
    (setvar "CMDECHO" 0)
    (command "_OPENDCL")
    (setvar "CMDECHO" cmdecho)

    ;; 加载Selections.odcl"对话框
    (dcl_Project_Load (FindFile "Selections.odcl") t)
[/pcode]然后建立一个循环可使对话框能够重复加载
[pcode=lisp,true](setq doContinue T) ;_ 设置对话框可循环加载标志
    (while doContinue
        ;; 为避免进入死循环,首先将循环标志doContinue 设为nil,是否继续循环,由对话框的按钮事件来控制
(setq doContinue nil)

        ;;显示对话框,当对话框关闭时,该句代码对话框将返回一个值给变量intResult ,该变量反应对话框时如何关闭的
        ;; 返回值=1表示对话框正常关闭,2表示用 ESC 关闭,其它返回值可由 dcl_form_close函数指定,
        ;;例如 (dcl_Form_Close Selections_Form 3)
        (setq intResult (dcl_form_show Selections_Form))

        ;;因为这是一个模态对话框,所以程序将一直停留在  (dcl_form_show Selections_Form)  处,
        ;;直到对话框关闭,才会往下执行代码,程序的所有任务都要交给对话框中的事件来处理。

        ;;对话框关闭后,根据 intResult 的返回值,进行下一步处理
        (cond
            
            ;; intResult = 1 ,正常关闭对话框,循环标志doContinue设为 nil,不在循环,
            ((= intResult 1) (setq doContinue nil)
              ;;此处可根据实际需要添加处理功能的代码
               )

            ;; intResult = 2 , ESC 取消关闭对话框
            ((= intResult 2) (setq doContinue nil))

            ;; intResult = 3 , 关闭对话框,屏幕选点
            ((= intResult 3)
               (point_selection) ;_ 执行屏幕选点子程序
                 )

            ;;  intResult = 4 , 关闭对话框,屏幕选择对象
            ((= intResult 4)
              (object_selection) ;_ 执行屏幕选择对象 子程序
              )

        ); cond
    ); while
[/pcode]
对话框打开时,我们要把所有改变对话框各种控件属性状态的代码放在对话框的 OnInitialize 事件中:
[pcode=lisp,true]    (defun c:Selections_Form_OnInitialize (/)
        
        ;; clean if necessary
(dcl_ListBox_Clear Selections_Form_PointListBox)
(dcl_ListBox_Clear Selections_Form_ObjectListBox)

        ;; fill pointlist
        (if lstPoints
            (dcl_ListBox_AddList Selections_Form_PointListBox lstPoints)
        ); if

        ;; fill objectlist
        (if lstObjects
            (dcl_ListBox_AddList Selections_Form_ObjectListBox lstObjects)
        ); if
        (princ)
    ); c:Selections_Form_OnInitialize
[/pcode]
模态对话框打开后,所有事情都交给事件来处理,我们给屏幕选点图像命令按钮添加OnClicked事件:
[pcode=lisp,true]    (defun c:Selections_Form_PickPointButton_OnClicked (/)
;;关闭对话框,并将数值 3 传递给dcl_form_show 处的变量intResult ,主程序根据intResult  的值,执行选点处理的函数
        (dcl_form_close Selections_Form 3)
    )
[/pcode]
选点处理的函数 :
[pcode=lisp,true](defun point_selection (/ intBlip ptPoint strPoint doSel)
        ;; 修改系统变量 BLIPMODE为1,以便选点时在屏幕上留下痕迹
        (setq intBlip (getvar "BLIPMODE"))
        (setvar "BLIPMODE" 1)

        (setq doSel T) ;_ 设置循环选点标志
        (while doSel ;_ 循环选点

            ;; 执行安全选点
            (setq ptPoint (vl-catch-all-apply 'getpoint (list "\nPick a point (or press ENTER to return to the form): ")))

            (cond
                ;; 用户 按下回车或右键,结束选择,设置对话框可循环加载标志doContinue  为真,继续重新加载对话框
((not ptPoint)
                 (setq ptPoint nil
                       doSel nil
                       doContinue T))

                ;; 用户按下ESC, 结束选择,设置对话框可循环加载标志 doContinue  为 nil,不再加载对话框
                ;; to cancel the loop and cancel the command
                ((vl-catch-all-error-p ptPoint)
                 (setq ptPoint nil
                       doSel nil
                       doContinue nil))

                ;; 将选择的点转为字符串
                ((not (setq strPoint (vl-prin1-to-string ptPoint)))
                 (setq ptPoint nil
                       doSel T)) ;_ 继续选择

                ;; 如果点表中不含选择的点,则将该点添加到点表中
((not (member strPoint lstPoints))
                 (setq lstPoints (reverse (cons strPoint (reverse lstPoints)))
                       doSel T)) ;_ 继续选择
            ); cond
        ); while
        
        ;; restore BLIPMODE
        (setvar "BLIPMODE" intBlip) ;_ 恢复系统变量
    )[/pcode]
同样,我们给选择对象按钮也添加一个OnClicked事件:
[pcode=lisp,true](defun c:Selections_Form_PickObjectButton_OnClicked (/)
;关闭对话框,并将数值 4 传递给 dcl_form_show 处的变量 intResult ,主程序根据 intResult  的值 ,执行选择对象处理的函数
( (dcl_form_close Selections_Form 4)
    )
[/pcode]
选择对象处理的函数 :
[pcode=lisp,true]
(defun object_selection (/ intBlip ssAusw intLen entObj vlaObj strObj)

        ;; 修改系统变量 BLIPMODE为1,以便选对象时在屏幕上留下痕迹
        (setq intBlip (getvar "BLIPMODE"))
        (setvar "BLIPMODE" 1)

        ;;  执行安全选择对象
        (princ "\nSelect objects (or press ENTER to return to the form): ")
        (setq ssAusw (vl-catch-all-apply 'ssget nil))
        
        (cond
            ;; 用户 按下回车或右键,没有选择对象, 设置对话框可循环加载标志 doContinue  为真,继续重新加载对话框
((not ssAusw)
             (setq ssAusw nil
                   doContinue T))

            ;;  用户按下ESC, 结束选择, 设置对话框可循环加载标志 doContinue  为 nil,不再 加载对话框  
((vl-catch-all-error-p ssAusw)
             (setq ssAusw nil
                   doContinue nil))

            ;; 检查选择集中是否有对象
            ((zerop (setq intLen (sslength ssAusw)))
             (setq ssAusw nil
                   doContinue T))

            ;; 如果选择的对象不在对象表lstObjects 中,则将对象添加到表中
(T (repeat intLen
                   (setq entObj (ssname ssAusw (setq intLen (1- intLen))))
                   (setq vlaObj (vlax-ename->vla-object entObj))
                   (setq strObj (strcat (vla-get-ObjectName vlaObj) " (" (vla-get-Handle vlaObj) ")"))
                   (if (not (member strObj lstObjects))
                       (setq lstObjects (reverse (cons strObj (reverse lstObjects))))
                   ); if
               ); repeat
             (setq doContinue T)) ;_ 继续加载对话框
        ); cond
        
        ;; 还原系统变量 BLIPMODE值
        (setvar "BLIPMODE" intBlip)
    )[/pcode]
该演示代码中还有ListBox的双击事件,删除选中项的代码示例:
[pcode=lisp,true]    ;; 点列表双击事件,删除选中项
    (defun c:Selections_Form_PointListBox_OnDblClicked (/ intRow)
        (if (not (minusp (setq intRow (dcl_ListBox_GetCurSel Selections_Form_PointListBox))))
            (progn
                 (setq lstPoints (vl-remove (dcl_ListBox_GetItemText Selections_Form_PointListBox intRow) lstPoints))
                (dcl_ListBox_DeleteItem Selections_Form_PointListBox intRow)
            ); progn
        ); if
    )
; 对象列表双击事件,删除选中项
    (defun c:Selections_Form_ObjectListBox_OnDblClicked (/ intRow)
        (if (not (minusp (setq intRow (dcl_ListBox_GetCurSel Selections_Form_ObjectListBox))))
            (progn
(setq lstObjects (vl-remove (dcl_ListBox_GetItemText Selections_Form_ObjectListBox intRow) lstObjects))
                (dcl_ListBox_DeleteItem Selections_Form_ObjectListBox intRow)
            ); progn
        ); if
    )
[/pcode]
至此,该程序全部完成。完整的代码和对话框文件下载:
请点击此处下载

查看状态:需购买或无权限

您的用户组是:游客

文件名称:Selections.rar 
下载次数:417  文件大小:4.69 KB 
下载权限: 学生 以上  [免费赚D豆]



总结一下模态对话框重复加载的方法:

1、在主程序中建立循环,由循环标志来控制对话框的重复加载,这种方式和DCL的方法一致,所不同的是,OpenDcl重新加载对话框,OpenDcl会自动保留上次对话框的数据,而Dcl需要我们自己来设置对话框的初始值。
[pcode=lisp,true]...
(setq doContinue T) ;_ 设置循环加载对话框标志
(while doContinue
  (setq doContinue nil) ;_ 禁止循环
  (setq intResult (dcl_form_show Selections_Form)) ;_ 显示对话框
  ;;根据关闭对话框的返回值intResult分别处理
  (cond
    ((= 1 intResult)
     ...
     )
    ((= 2 intResult)
     ...
     )
    ...
    )
  )
...[/pcode]
2、对话框打开后,所有的事情都要交给对话框的按钮事件来处理,直到对话框关闭,代码才会执行(dcl_form_show )后面的代码,牢记这点尤其重要,初学者往往因不理解OpenDcl这种机制,往往将上面的程序代码写成了如下方式:
[pcode=lisp,true];;错误的代码方式
(defun c:Sel ()
    (vl-load-com)
    (setq cmdecho (getvar "CMDECHO"))
    (setvar "CMDECHO" 0)
    (command "_OPENDCL")
    (setvar "CMDECHO" cmdecho)

    ;; 加载对话框
    (dcl_Project_Load (FindFile "Selections.odcl") t)

    ;;显示对话框
    (dcl_form_show Selections_Form)
    ;;关闭对话框事件
    (defun c:Selections_Form_Close_OnClicked (/)
        (dcl_form_close Selections_Form 1)
     )

    ;;屏幕选点按钮事件
    (defun c:Selections_Form_PickPointButton_OnClicked (/)
      ;;关闭对话框
      (dcl_form_close Selections_Form )
      ;;执行屏幕选点
      (point_selection)
      ;;选完点重新显示对话框
      (dcl_form_show Selections_Form)
    )
   
    ;; 屏幕选择对象按钮事件
    (defun c:Selections_Form_PickObjectButton_OnClicked (/)
      ;;关闭对话框
        (dcl_form_close Selections_Form )
      ;;执行屏幕选对象
      (object_selection)
      ;;选完对象后重新显示对话框
      (dcl_form_show Selections_Form)
    )
  )[/pcode]
这种写法就是因为不了解OpenDcl运行机制,才导致的错误!在OnClicked  事件中,(dcl_form_close Selections_Form ) 代码后面的(dcl_form_show Selections_Form) 代码根本不会执行,在OnClicked  事件中 关闭了对话框,其实对话框并没有正真结束,直到跳出 OnClicked  事件 才结束,所以后面的(dcl_form_show Selections_Form)  也不会执行!
所以 dcl_Form_Show 显示模态对话框代码,代码的本质是显示窗体,暂时直至用户关闭对话框,正是基于这个理由,不要把用于即时改变或操作模态对话框的代码放在 dcl_Form_Show 函数的后面,相反,应把这些相关的代码放在对话框的 OnInitialize 事件中。不论对话框是模态还是非模态都需要这样做。

3、显示和隐藏窗体
当隐藏对话框时,用户应调用 dcl_Form_Close 来关闭它,而重新显示可用 dcl_Form_Show。所有控件的属性设置在对话框关闭后OpenDcl会自动保存下来,重新打开后对话框的数据依旧保存下来。


4、取消关闭对话框
用户可在应用程序中使用CancelClose事件来禁止用户关闭模态或非模态对话框。  这将防止所有通过常用途径关闭对话框的方法,如点击确定或取消键,或按下Esc键。  

选择对话框后,在事件窗口中选定CancelClose项,添加该事件到你的LISP代码中。  以下代码可用于指定是否可以出现关闭。

[pcode=lisp,true]; ...
(setq AllowClose T)
; AllowClose 是一个全局变量,用户可设置该事件来指示关闭对话框
; 该变量可被其它函数更改以标记OnCancelClose函数的需求动作。
; ...
(defun c:DclForm1_DclForm1_OnCancelClose (bCancelling / rCancelClose)

(setq rCancelClose nil)
                                      
; 在应用程序中跟踪用户设置以判断该对话框是否应该关闭。

(if (= AllowClose T)
; 设置返回变量以允许对话框关闭
(setq rCancelClose nil)
; 否则设置返回变量,不驱允许对话框关闭
(setq rCancelClose T)
)

; 变量放在这个位置以返回值给 OpenDCL
; 以通知应当取消关闭。

rCancelClose
)[/pcode]

评分

参与人数 1威望 +3 D豆 +10 贡献 +3 收起 理由
XDSoft + 3 + 10 + 3

查看全部评分

本帖被以下淘专辑推荐:

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 344个

财富等级: 日进斗金

 楼主| 发表于 2013-5-4 18:34:48 | 显示全部楼层
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 1 反对 0

使用道具 举报

已领礼包: 2688个

财富等级: 家财万贯

发表于 2013-5-4 17:25:32 | 显示全部楼层
太好了,又有新东西了,跟固版学习下
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 1999个

财富等级: 堆金积玉

发表于 2013-5-4 17:48:14 | 显示全部楼层
DEAR SIR,


WOW IT'S VERY COOOOOOOL

THX

点评

能看懂汉语,不会拼音输入法???  发表于 2013-6-23 05:39
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 146个

财富等级: 日进斗金

发表于 2013-5-8 10:59:26 | 显示全部楼层
正在学opendcl  苦于教程太少 G版太及时了!感谢!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2013-6-16 10:24:12 | 显示全部楼层
这个循环真是经典,收藏了。。。 还不知道DCL_FORM_CLOSE 还可以返回变量,继续期待G版的教程。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 1个

财富等级: 恭喜发财

发表于 2013-6-23 05:37:20 | 显示全部楼层
敬佩,G斑的精神值得大家学习。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 55个

财富等级: 招财进宝

发表于 2014-3-9 17:13:57 | 显示全部楼层
现在还看不懂 只能先收藏 慢慢学习了
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2014-6-8 00:30:47 | 显示全部楼层
学习了,后面部分还得继续学习的
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2014-6-8 04:38:57 | 显示全部楼层
这个东西不错,收藏了~,留着今后可以用~~:)
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 117个

财富等级: 日进斗金

发表于 2014-7-4 09:39:29 | 显示全部楼层
太好了,又有新东西了,跟固版学习下
  
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2014-7-8 20:50:10 | 显示全部楼层
新手路过学习一下...
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2014-8-26 18:02:08 | 显示全部楼层
很给力~~~赞一个!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2014-10-12 22:58:50 | 显示全部楼层
正在学opendcl  苦于教程太少 G版太及时了!感谢
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2015-1-30 10:57:07 | 显示全部楼层
· 牢不可破之VLisp/OpenDCL专辑
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-4-27 03:44 , Processed in 0.376614 second(s), 71 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表