Lisp 操作 Excel 三例

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/yxp_xa/article/details/80910654

一、LISP导出数据到新建Excel工作表

如果当前 Windows 系统已经打开了 Excel 程序,则导出数据较快,否则将自动创建 Excel 对象进程,处于隐藏模式。为简便起见,本函数未检测当前系统是否安装 Excel 程序。如果已经打开了包含若干工作表的工作簿文件,则本函数将会在激活的工作表后插入一个空白工作表,用来导出 lisp 数据,而不会覆盖已有工作表,导致原数据丢失。操作 Excel 对象时必须清楚对象模型结构,工作簿与工作表的区别,对象集合与对象的区别:

  • 工作簿对象集合: WorkBooks,一个 Excel 进程可以有 0 到多个工作簿,就是同时打开了多个 excel 文件(同一进程)。点两次 Excel 软件图标,将会打开两个 Excel 进程
  • 工作表对象集合: Sheets,一个 Excel 文件(工作簿)可以包含1 到多个工作表,一个工作表对象是工作表对象集合的子集
  • 对象是对象集合的子集,对象集合名称以对象加 s 后缀,集合可以为空,具有 cont 属性和 item 属性;对象集合可以用 vlax-for 来遍历,而不必关心集合的
;;函数: (List_Save_Excel List)
;;功能: 将表数据输出到Excel (新建工作表)
;;参数: List 表,可以是一维或者二维表,或任意 list 表数据
;;返回: 0
;;示例: (List_Save_Excel '(1 2 3))
(defun List_Save_Excel( Lit / GetPy PutPy wbs wb sht xcells d c r)
(setq *appxls* (vlax-get-or-create-object "excel.application"))
(setq GetPy vlax-get-property PutPy vlax-put-property)
(setq wbs (GetPy *appxls* 'Workbooks))
;;判断工作薄(集合)是否为空,若空则新建工作簿,并返回工作薄指针
(setq wb (if (= 0 (GetPy wbs 'count))
    (vlax-invoke-method wbs 'add)
    (GetPy wbs 'item 1)) ;;如果不为空则返回第一个工作薄
)
;;新建工作表,用于导出数据。 (GetPy wb 'sheets) 是工作表集合对象
(setq sht (vlax-invoke-method (GetPy wb 'sheets) 'add))
;;得到工作表的 cells 对象,该对象与 range 对象的区别就是可以用行列定位
(setq xcells (GetPy sht 'cells) r 0 c 0)
(if (= (type Lit) 'LIST)
(repeat (length Lit)
    (setq d (nth r Lit) r (1+ r))
    (if (= (type d) 'LIST)
        (repeat (length d) (PutPy xcells 'item r (1+ c)(vl-princ-to-string(nth c d))) (setq c (1+ c)) )
    (PutPy xcells 'item 1 r (vl-princ-to-string d))
    )
    (setq c 0)
)(PutPy xcells 'item 1 1 (vl-princ-to-string Lit))
)
(vla-put-visible *appxls* 1)  ;;显示工作表
(vlax-release-object xcells)  ;;用完销毁
(vlax-release-object sht)
(vlax-release-object *appxls*)
)

二、载入工作表区域为 VisualLisp 数组

有 lisp 数据输出到 excel 的函数,反过来,也少不了 excel 数据的输入函数。总有种感觉,VisualLisp 的变体数组就是为了 Excel 量身打造的,因为其他地方几乎用不上

;;功能:载入工作表指定区域数据为 VisualLisp 数组
;;参数:ss 路径及文件名; n 工作表的下标或名称; usg 指定的数据区域
;;返回:VL数组
;;示例:(Get_Sheet_arry "d:\\cpp\\data.xlsx" 1 "a2:e2000")
;;VisualLisp 数组用法,查找第 2 行,第 3 列数据,转 lisp 表用 mapcar
;;(vlax-variant-value(vlax-safearray-get-element arr 2 3))

(defun Get_Sheet_arry(ss n usg / vg ws sht)
(setq excel (vlax-get-or-create-object "excel.application")
    vg vlax-get-property ws (vg excel 'Workbooks)
    sht(vg (vg (vlax-invoke ws 'Open ss) 'Worksheets) 'item n)
    arr (vlax-variant-value (vg (vg sht 'Range usg) 'Formula)))
(vlax-invoke ws 'close) arr
)

三、按名称获取工作表对象句柄

值得一提的是,Excel 对象集合的 Item 属性有一个十分贴心的功能,都可以用数字 ID 或字符串 string 来作为参数。当用 ID 作为 Item 的参数时,ID 表示当前工作簿打开的顺序,例如 (vlax-get-property sheets ‘item 1) 返回当前工作簿集合的第一个打开的工作簿对象;当用字符串 string 作为参数时,(vlax-get-property sheets ‘item “abc”) 可以获取当前工作簿集合中名称为 “abc” 工作簿的对象,如果不存在则返回一个自动化错误。

一般获取地址的函数,都可以通过 ID 和 string 作为参数,例如 GetProcAddress。而用 ID 的调用速度比 string 快,因此推荐使用 ID 来获取工作薄(表)的对象句柄。

;;获取 Excel 进程对象及工作簿对象集合的句柄
(setq Excel (vlax-get-or-create-object "excel.application"))
(setq Wbks (vlax-get-property Excel 'Workbooks))

;;获取第一个打开的文件的句柄以及文件名
(setq wbs1 (vlax-get-property Wbks 'item 1))
(setq wbname (vlax-get-property wbs1 'name))

;;返回当前已经打开的文件 abc.xlsx 的对象句柄,如果该文件未打开,则提示:
;; 错误: Automation 错误。未提供说明。
;;此时可以用 vl-catch-all-apply 捕获错误,并用 vl-catch-all-error-p 判断
(setq wbnName (vlax-get-property Wbks 'item "abc.xlsx"))

用同样的办法,可以按名称得到一个工作表对象的句柄(指针),如果工作表在多个文件中重复存在,则返回最后一个打开的工作簿(文件)的工作表对象,通用函数如下:

;;函数:  (Get_Sheet_obj ss)
;;功能:  根据工作表名称,从当前打开的所有excel文件中获取某个工作表对象
;;参数:  ss 工作表名称,不分大小写
;;返回:  如果 ss 工作表已打开,则返回对象句柄,否则返回 nil
;;示例:  (Get_Sheet_obj "abc")

(defun Get_Sheet_obj(ss / sheets sheet retrun)
(setq excel (vlax-get-or-create-object "excel.application"))
(vlax-for x (vlax-get-property excel 'Workbooks)
    (setq sheets (vlax-get-property x 'Sheets)
        sheet (vl-catch-all-apply 'vlax-get-property (list sheets 'item ss)))
    (if (not (vl-catch-all-error-p sheet))(setq retrun sheet))
)retrun
)

例如:将名为 “abc” 的工作表 C3:C5 单元格背景色设置为黑色

(setq C35 (vlax-get-property (Get_Sheet_obj "abc") "Range" "C3:C5"))
(vlax-put-property (vlax-get-property C35 "Interior") 'Color 1)

猜你喜欢

转载自blog.csdn.net/yxp_xa/article/details/80910654
今日推荐