【抛砖引玉】关于右键菜单,另类实现工具面板
本帖最后由 x_s_s_1 于 2022-3-27 17:57 编辑文章较长,且逻辑性不强,没兴趣请跳过:lol
对于可能长时间处于一个固定状态的制图工作,一个大面板可能效率不高。我针对于自己的实际需要,采用了右键菜单,模拟小面板。这样做的好处在于1.提高效率;2.可以用快捷键,经常打游戏的asdfqwe用得比较溜的,可以试试。效果如下:
本人水平有限,对于mnu文件和popupmenu对象一知半解,希望各位网友指正。
思路是这样的
1.准备ini文件,通过读ini文件,修改菜单;(这里可以改成读excel,方便修改,我对这方面不熟,用的读txt文件)
文件格式为
"模态标签","模态名称"
"快捷键","命令提示","命令"
下面是ini文件片段
MODE1,转换出图
1,计算导入,AAJSSDRGL
a,图纸转换,XTY-CMD-YJK
MODE2,基础绘制
a,范围选数,XTY-CMD-FWXS
s,墙柱填充,XTY-CMD-HATCH
d,承台桩定位,AACTZDWBZ
。。。
2.读取ini文件(我用的文件名为XTDI-COMMAND.INI,把他放到支持文件夹),形成表;
(defun xty-mnu-getini (/ F FILE LST LST1 TXT temp)
(setqfile (findfile "XTDI-COMMAND.INI")
f (open file "r")
lst'() ;_准备总表
lst1 '() ;_准备分表
)
(while (setq txt (read-line f)) ;_读每行
(if(wcmatch txt "MODE*") ;_当为mode
(setq lst (if lst1
(cons (reverse lst1) lst)
) ;_当分表不空,倒置分表组总表
lst1 (list(xty-str-tolstby txt ",")) ;_mode放入分表
)
(setq temp (xty-str-tolstby txt ",")
temp (list(strcat (car temp)"."(cadr temp))(strcat (caddr temp)" "))
lst1 (cons temp lst1)
) ;_非mode放入分表
)
)
(close f)
(setqlst (cons (reverse lst1) lst) ;_最后一个分表要倒置组入总表
lst (reverse lst) ;_倒置总表
)
)3.替换autocad的默认右键菜单项,我用的是autocad2020中文版,默认菜单的名称为"默认菜单";
;;;=============================================
;;; 通用函数替换菜单全部项
;;;参数: mnugname--------要修改的菜单组名
;;; mnuname---------要修改的菜单名
;;; itemlst-----要修改的菜单项表
;;;返回值:修改的菜单对象
;;;示例:(xty-mnu-changepop "acad" "默认菜单" '(("a.l""line ")))
(defun xty-mnu-changepop(mnugname mnuname itemlst / mnug mnus pop stct i)
(setqmnug (vl-catch-all-apply
'vlax-invoke-method
(list *xty-mnugs* 'item mnugname)
) ;_菜单组是否存在
)
(if (null (vl-catch-all-error-p mnug)) ;_如果存在要搜索菜单组
(progn
(setq mnus (vlax-get-property mnug 'menus)) ;_菜单组中的菜单
(setq stct (vl-catch-all-apply
'vlax-invoke-method
(list mnus 'item mnuname)
)
)
(if (null (vl-catch-all-error-p stct)) ;_如果存在右键弹出菜单pop0
(progn
(vlax-for pop stct (vlax-invoke-method pop 'delete)) ;_删除所有菜单项
(setq i 0)
(foreach n itemlst
(vlax-invoke-method stct 'addmenuitem i (car n) (cadr n))
(setq i (1+ i))
) ;_重新写菜单项
)
)
)
)
stct
)
4.主程序,写mnu文件(我用的名称是CareFromOldXia,可以相应修改),加载到autocad。这里要考虑修改了ini文件,重新加载的方法。现阶段版本autocad都是用cuix文件,所以在重载的时候要将相关文件都删掉;注意*xty-Installfolder*全局变量,这里是我自己的默认文件夹,请根据需求自行修改。
(defun c:xty-cmd-updatemytb(/ a b f i lst lst1 mymnu n)
(setqmymnu (vl-catch-all-apply
'vlax-invoke-method
(list *xty-mnugs*
'item
"CareFromOldXia"
)
)
) ;_获取我的工具条
(vl-catch-all-apply
'vlax-invoke-method
(list mymnu
'unload
)
) ;_删除我的工具条
(foreach n'("CareFromOldXia.cuix"
"CareFromOldXia.mnr"
"CareFromOldXia_light.mnr"
"CareFromOldXia.bak.cuix"
)
(vl-catch-all-apply 'vl-file-delete (list (findfile n)))
) ;_删除加载菜单生成文件,避免不更新
(setqlst(xty-mnu-getini)
lst1 (mapcar 'car lst)
f (findfile "CareFromOldXia.mnu")
f (open f "w")
i 1
)
(write-line "***menugroup=CareFromOldXia" f)
(write-line "***POP0" f);_这里是为其它程序预留的,可以删掉
(write-line "**SNAP" f);_这里是为其它程序预留的,可以删掉
(write-line "" f);_这里是为其它程序预留的,可以删掉
(write-line "***TOOLBARS=allbar" f)
(write-line "**工作模态" f)
(write-line
"ID_TBA_00 "
f
)
(write-line
"ID_TBA_01 ^c^cxty-cmd-updatemytb"
f
)
(setqn (car lst1)
i 0
)
(foreach nlst1
(setq a (car n)
b (cadr n)
)
(write-line
(strcat
"ID_TBA_"
(xty-tr-add0 (itoa (setq i (1+ i))) 2)
" [_Button(\"工作模态切换至"
b
"\",\"BMP\\\xty_"
a
"_16.bmp\",\"BMP\\\xty_"
a
"_32.bmp\")]^c^c^p(setenv \"xty-myworkmode\" \""
a
"\");xty-cmd-menumode"
)
f
)
)
(close f)
(setq
mymnu
(vl-catch-all-apply
'vlax-invoke-method
(list *xty-mnugs*
'load
(strcat *xty-Installfolder* "\\CareFromOldXia.mnu")
)
)
)
(princ)
)
5.点击按钮,切换工作模态。
(defun c:xty-cmd-menumode (/ mode lst lst1 lst2 lst3 n)
(setqmode (getenv "xty-myworkmode");_此处设置环境变量"xty-myworkmode",可根据需要修改
lst(xty-mnu-getini)
lst1 (mapcar 'car lst)
lst2 (mapcar 'car lst1)
lst3 (mapcar 'cdr lst)
n(-(length lst2)(length(member mode lst2)))
lst3(nth n lst3)
)
(xty-mnu-changepop "acad" "默认菜单" lst3)
(princ (strcat"\n当前工作模态切换为:"(cadr(nth n lst1))))
(princ)
)
6.一些用到的函数以及全局变量
;;;全局变量
(setq *xty-acobj* (vlax-get-acad-object));_cad本身
(setq *xty-mnugs* (vlax-get-property *xty-acobj* 'MenuGroups));_菜单组集合
;;;=============================================
;;; 通用函数 将字符串以给定Key分解成表
;;;参数:Str------字符串
;;; Key------分隔符
;;;返回值 字符串表
(defun xty-str-ToLstBy (Str Key / i s lst)
(while
(setq i (vl-string-search Key Str))
(setq
s (substr Str 1 i)
Str
(substr Str
(+ 1
(strlen key)
(if i
i
0
)
)
)
Lst (cons s Lst)
)
)
(vl-remove "" (reverse (cons str Lst)))
)
;;;=============================================
;;; 通用函数加前导0
;;;参数: str-------字符串
;;; n---------加零后字符串长度
;;;返回值:加前导零后字符串
(defun xty-tr-add0 (str n)
(setq n (- n (strlen str)))
(repeat n (setq str (strcat "0" str)))
str
)
7.存在的问题,修改acad默认菜单是比较危险的事情,我现阶段的编程水准导致我无法解决该问题。我在CareFromOldXia.mnu中预留了pop0,
(write-line "***POP0" f);_这里是为其它程序预留的,可以删掉
(write-line "**SNAP" f);_这里是为其它程序预留的,可以删掉
(write-line "" f);_这里是为其它程序预留的,可以删掉
也预留了函数
;;;=============================================
;;; 通用函数显示局部快捷菜单
;;;参数: mnugname--------要修改的菜单组名
;;; mnuname---------要修改的菜单名
;;; itemlst-----要修改的菜单项表
;;;返回值:无,显示快捷菜单
(defun xty-mnu-local(mnugname mnuname itemlst)
(xty-mnu-changepop mnugname mnuname itemlst)
(menucmd "P0=CareFromOldXia.POP0")
(menucmd "P0=*")
)
但是无法找到右键弹出菜单的方法,反应器也不行,好像采用了cuix以后的版本都将右键默认菜单固定为acad.cuix。8.用到的BMP文件,可根据自己需要自定义
e2002 发表于 2022-3-29 11:24
看起来似乎是:点击了1234567这个工具栏上的某个图标,然后切换为对应的右键菜单?如果理解错误请谅解。
...
确实是点击某个图标,然后切换右键菜单。专业所致,在某个工作状态下,使用的命令大部分是重复的,搞个大面板难得找,而且只是在切换工作状态的时候才点工具栏(1.2.3.4.5...)。和ribbon的意思差不多,不过我平时ribbon是关的,节省显示区域,只有某个工作状态才打开,两个显示器都不蛮够用。 本帖最后由 e2002 于 2022-3-29 11:26 编辑
看起来似乎是:点击了1234567这个工具栏上的某个图标,然后切换为对应的右键菜单?如果理解错误请谅解。
我觉得都直接点击了图标,直接显示出一个弹出菜单列表,然后选择即可,为啥还要再去点击右键才选择呢?
而且右键菜单本来就有各种功能。
或者直接做到ribbon中去更加简单。
本帖最后由 x_s_s_1 于 2022-3-28 09:29 编辑
AndyWang 发表于 2022-3-28 09:25
支持,楼主厉害了。你那小面板有兴趣,不知是否可以分享下。
一楼已经分享了所有代码了啊,根据自己的需求去改相关文件名称和ini文件就行了,需要个性化设置的地方我都特殊标示了. 一楼以备不时之需 看起来好牛呀,支持 顶起,,厉害了大神 支持,楼主厉害了。你那小面板有兴趣,不知是否可以分享下。 x_s_s_1 发表于 2022-3-28 09:27
一楼已经分享了所有代码了啊,根据自己的需求去改相关文件名称和ini文件就行了,需要个性化设置的地方我 ...
哦,我以为是用opendcl做的,这是用cuix实现的? 顶起,,厉害了大神 致敬大神,结构大佬~
lisp 处理菜单功能,还是很弱的,没有相关的简便的模块。