Author Topic: excel sheet list and selection  (Read 407 times)

0 Members and 1 Guest are viewing this topic.

newlispuser

  • Mosquito
  • Posts: 2
excel sheet list and selection
« on: February 14, 2024, 08:35:55 AM »
hello all,

I am looking to update this code in order for it to present me with a selection for tabs (or sheets) in the excel workbook, let me choose which sheets I want it to read, then give the output looking at only those sheets.

 

I think I am kind of close? I will notate what I've tried to add in order to get this to happen below. I'm pretty rusty with LISP, so I'm sure I'm doing something wrong here.


Code: [Select]
;;-------------------------------------------------------------;;
;;                      ReadExcel                              ;;
;;; Written by "Shadi" in 2020, lifted from "CADTutor" ;
;;; forum. ;
;;; Forum Link: ;
;;; https://www.cadtutor.net/forum/topic/71141-lisp-to-look-up-in-excel-and-insert-text-in-cad/
;;; ;
;;-------------------------------------------------------------;;
; rlx 6 sep 2020
(defun c:ReadExcel ( / actApp actDoc OldErr allOpen xls-app errobj shtlst selshts workbooks activesheet sheets activeworkbook allwb allsht xldata pt txt)
  (Shadi_Init)
  (if (setq xls-app (vlax-get-object "Excel.Application"))
    (progn
      (princ "\nExcel is running\n\n")
      ;;; list all open workbooks
      (setq errobj (vl-catch-all-apply (function (lambda () (setq workbooks (vlax-get-property xls-app "Workbooks"))))))
      (if (vl-catch-all-error-p errobj) (princ "\nUnable to get 'workbooks property from excel"))
      ;;; get active sheet
      (setq errobj (vl-catch-all-apply (function (lambda () (setq activesheet (vlax-get-property xls-app "activesheet"))))))
      (if (vl-catch-all-error-p errobj)(princ "\nUnable to get 'activesheet property from excel"))
      ; ;;; list all sheets
      ; (setq errobj (vl-catch-all-apply (function (lambda () (setq sheets (vlax-get-property xls-app "Sheets"))))))
      ; (if (vl-catch-all-error-p errobj) (princ "\nUnable to get 'sheets property from excel"))
      (if workbooks
        (vlax-for wb workbooks (vl-catch-all-apply (function (lambda ()(setq allwb (append allwb (list (vla-get-fullname wb)))))))))
      (princ "\nAll open workbooks :\n")
      (if (and allwb (setq wb (Shadi_cfl allwb)))
        (Shadi_OpenActiveWorkbook wb) (progn (princ "\nNo open workbooks found - switching to manual selection")(Shadi_OpenNewWorkbook)))

;;THIS IS THE FARTHEST IVE GOTTEN. IT FAILS HERE
  (setq shtlst (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property wb "Sheets"))))
   (if (vl-catch-all-error-p errobj)(princ "\nUnable to get 'sheets property from excel"))
  (setq selshts (Shadi_shtsel shtlst))


    );end progn (select data from active workbook)
    (progn (princ "\nExcel is not running . . . initializing\n\n") (Shadi_OpenNewWorkbook))

  )
  (if xls-app (Shadi_ReleaseExcel)) 
  (Shadi_Exit)
  (if (vl-consp xldata)
    xldata
    nil
  )
)

(defun Shadi_Err ($s) (princ $s)(Shadi_Exit)(setq *error* OldErr)(princ))

(defun Shadi_Exit () (Shadi_ReleaseAll)(gc))

(defun Shadi_Init () (vl-load-com) (setq OldErr *error* *error* Shadi_Err)
  (setq actApp (vlax-get-acad-object) actDoc (vla-get-activedocument actApp))
    (vlax-for doc (vla-get-documents actApp)(setq allOpen (cons (cons (strcase (vla-get-fullname doc)) doc) allOpen))))

(defun Shadi_ReleaseAll ()
  (vl-catch-all-apply 'vlax-release-object (list actdoc))(vl-catch-all-apply 'vlax-release-object (list actapp)))

; choose from list
(defun Shadi_cfl ( lst / dcl-name fp dcl drv inp)
  (if (not (findfile (setq dcl-name (strcat (getvar "MYDOCUMENTSPREFIX") "\\Shadi_cfl.dcl"))))
    (progn (setq fp (open dcl-name "w")) (write-line (strcat "ask : dialog { label = \"Please choose an active Workbook:\"; spacer_1;"
      " : list_box { key = \"lbox\"; width = 100;} spacer_1; ok_cancel;}") fp) (if fp (close fp))(gc)))
  (if (and lst (setq dcl (load_dialog dcl-name))(new_dialog "ask" dcl))
    (progn (vl-file-delete dcl-name) (start_list "lbox")(mapcar 'add_list lst)(end_list)
      (action_tile "lbox" "(setq inp (nth (atoi $value) lst))") (action_tile "ok" "(done_dialog 1)")
        (action_tile "cancel" "(done_dialog 0)") (setq drv (start_dialog))
          (if (and (= drv 1)(not inp)) (setq inp (nth 0 lst)))) (setq inp '()))
  inp
)




;;;THIS BELOW IS FROM LEE MAC TO CREATE A DCL WHERE YOU CAN SELECT MULTIPLE ITEMS IN THE LIST
;; choose sheets from list
(defun Shadi_shtsel ( msg lst bit / dch des tmp rtn )
    (cond
((not (and (setq tmp (vl-filename-mktemp nil nil ".dcl"))
                    (setq des (open tmp "w"))
                    (write-line
                        (strcat "listbox:dialog{label=\"Please choose sheets:\";spacer;:list_box{key=\"list\";multiple_select="
                            (if (= 1 (logand 1 bit)) "true" "false") ";width=50;height=15;}spacer;ok_cancel;}"
                        )
                        des
                    )
                    (not (close des))
                    (< 0 (setq dch (load_dialog tmp)))
                    (new_dialog "listbox" dch)
                )
            )
            (prompt "\nError Loading List Box Dialog.")
        )
        (   t     
            (start_list "list")
            (foreach itm lst (add_list itm))
            (end_list)
            (setq rtn (set_tile "list" "0"))
            (action_tile "list" "(setq rtn $value)")
            (setq rtn
                (if (= 1 (start_dialog))
                    (if (= 2 (logand 2 bit))
                        (read (strcat "(" rtn ")"))
                        (mapcar '(lambda ( x ) (nth x lst)) (read (strcat "(" rtn ")")))
                    )
                )
            )
        )
    )
    (if (< 0 dch)
        (unload_dialog dch)
    )
    (if (and tmp (setq tmp (findfile tmp)))
        (vl-file-delete tmp)
    )
    rtn
)






(defun Shadi_OpenActiveWorkbook ( fn / wb activeworkbook activesheet)
  (if (and xls-app fn (findfile fn) workbooks) (progn (setq activeworkbook (vlax-invoke-method workbooks 'open fn))
    (setq activesheet (vlax-get-property xls-app 'activesheet)) (setq xldata (Shadi_Xls2Lst activesheet)))))



;TRIED HERE TO GET IT TO READ ONLY THE SELECTED SHEETS
; (defun Shadi_OpenActiveWorkbooksheet ( fn / sht sheets activeworkbook activesheet)
;   (if (and xls-app fn (findfile fn) workbooks) (progn (setq activeworkbook (vlax-invoke-method workbooks 'open fn))
;     (setq sheets (vlax-get-property xls-app 'sheets)) (setq xldata (Shadi_Xls2Lstsheets sheets)))))







(defun Shadi_OpenNewWorkbook ( / fn err path)
  (if (and Shadi-LastXlsFile (findfile Shadi-LastXlsFile))(setq path (vl-filename-directory Shadi-LastXlsFile))(setq path ""))
  (if (and (setq fn (getfiled "Select Excel File (*.xlsx is default, change type if needed)" path "xlsx;xls;xlsm" 16))
           (setq xls-app (vlax-get-or-create-object "excel.application")))
    (progn (setq Shadi-LastXlsFile fn err (vl-catch-all-apply (function (lambda ()(setq workbooks (vlax-get-property xls-app 'workbooks)
      activeworkbook (vlax-invoke-method workbooks 'open fn) activesheet (vlax-get-property xls-app 'activesheet))))))
      (if (vl-catch-all-error-p err) (prompt (strcat "\nError: " (vl-catch-all-error-message err)))
(progn (vlax-invoke-method activesheet "Activate")(graphscr)(setq xldata (Shadi_Xls2Lst activesheet))))))
  (vl-catch-all-apply (function (lambda ()(vlax-invoke-method activeworkbook 'close :vlax-false))))
  (vl-catch-all-apply (function (lambda ()(vlax-invoke-method xls-app 'quit))))(Shadi_CloseExcel)
)

(defun Shadi_CloseExcel () (if xls-app (progn (vl-catch-all-apply 'vlax-invoke-method (list activeworkbook "Close" :vlax-False))
  (vl-catch-all-apply 'vla-quit (list xls-app)) (mapcar '(lambda(x)(vl-catch-all-apply 'vlax-release-object (list x)))
    (list activesheet activeworkbook xls-app)) (setq xls-app nil activeworkbook nil activesheet nil) (gc))))

(defun Shadi_ReleaseExcel () (mapcar '(lambda(x) (if x (vl-catch-all-apply 'vlax-release-object (list x))))
  (list activesheet activeworkbook xls-app)) (setq xls-app nil activeworkbook nil activesheet nil) (gc))

(defun Shadi_Xls2Lst
  ( %s / excel-range excel-used-range excel-max-row excel-max-column excel-max-range excel-variant excel-value excel-to-list lst)
  (defun _cl (i / n) (if (< i 27)(chr (+ 64 i))(if (= 0 (setq n (rem i 26)))
     (strcat (_cl (1- (/ i 26))) "Z")(strcat (_cl (/ i 26))(chr (+ 64 n))))))
 
  (setq excel-used-range (vlax-get-property  %s 'UsedRange))
  (setq excel-max-row (vlax-get-property (vlax-get-property excel-used-range "Rows") "Count"))
  (setq excel-max-column (vlax-get-property (vlax-get-property excel-used-range "Columns") "Count"))
  (setq excel-max-range (strcat "A1:" (_cl excel-max-column) (itoa excel-max-row)))

  (setq excel-range (vlax-get-property  %s 'Range excel-max-range))

  (setq excel-variant (vlax-get-property excel-range 'Value))
 
  (setq excel-value (vlax-variant-value excel-variant))
  (setq excel-to-list (vlax-safearray->list excel-value))
  (setq lst (mapcar '(lambda (x) (subst "" nil (mapcar '(lambda (y) (vlax-variant-value y)) x ))) excel-to-list))
  (princ)
  lst
)
;;-------------------------------------------------------------;;
;;        End of ReadExcel by Shadi                            ;;
;;-------------------------------------------------------------;;


The output currently is fine how it is. problem is that it will output only the active sheet of info when I need it to allow me to pick several sheets and push them all out into the current output format.

 

any ideas?

BIGAL

  • Swamp Rat
  • Posts: 1417
  • 40 + years of using Autocad
Re: excel sheet list and selection
« Reply #1 on: February 16, 2024, 12:09:10 AM »
2 methods is Excel open ?

Code: [Select]
(or (setq myxl (vlax-get-object "Excel.Application"))
    (setq myxl (vlax-get-or-create-object "excel.Application"))

Code: [Select]
(setq xlSheets (vlax-get-property myxl "Worksheets"))
(setq curSheet (vlax-get-property xlSheets "Item" 1)); 1 is 1st sheet need names of sheets somehow.
; (vlax-get cursheet 'Name) ; returns name

You should be able to get the count of the xlsheets and get their names into a list.
A man who never made a mistake never made anything

newlispuser

  • Mosquito
  • Posts: 2
Re: excel sheet list and selection
« Reply #2 on: February 20, 2024, 08:48:41 AM »
okay so its still not quite working. forgive me im just getting back into LISP things after years of not using it much, or at least not in this way.

This still doesnt work for populating the list of sheets in the .dcl it calls. Any ideas?

Code: [Select]
  (setq shtlst (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property wb "Worksheets"))))
   (if (vl-catch-all-error-p errobj)(princ "\nUnable to get 'worksheets property from excel"))

  (setq selshts (Shadi_shtsel shtlst))

Code: [Select]
; choose sheets from list
(defun Shadi_shtsel ( msg lst bit / dch des tmp rtn )
    (cond
((not (and (setq tmp (vl-filename-mktemp nil nil ".dcl"))
                    (setq des (open tmp "w"))
                    (write-line
                        (strcat "listbox:dialog{label=\"Please choose sheets:\";spacer;:list_box{key=\"list\";multiple_select="
                            (if (= 1 (logand 1 bit)) "true" "false") ";width=50;height=15;}spacer;ok_cancel;}"
                        )
                        des
                    )
                    (not (close des))
                    (< 0 (setq dch (load_dialog tmp)))
                    (new_dialog "listbox" dch)
                )
            )
            (prompt "\nError Loading List Box Dialog.")
        )
        (   t     
            (start_list "list")
            (foreach itm lst (add_list itm))
            (end_list)
            (setq rtn (set_tile "list" "0"))
            (action_tile "list" "(setq rtn $value)")
            (setq rtn
                (if (= 1 (start_dialog))
                    (if (= 2 (logand 2 bit))
                        (read (strcat "(" rtn ")"))
                        (mapcar '(lambda ( x ) (nth x lst)) (read (strcat "(" rtn ")")))
                    )
                )
            )
        )
    )
    (if (< 0 dch)
        (unload_dialog dch)
    )
    (if (and tmp (setq tmp (findfile tmp)))
        (vl-file-delete tmp)
    )
    rtn
)

Once i get the list of selected sheets, I imagine i have to hand it off to this function:

Code: [Select]
(defun Shadi_OpenNewWorkbook ( / fn err path)
  (if (and Shadi-LastXlsFile (findfile Shadi-LastXlsFile))(setq path (vl-filename-directory Shadi-LastXlsFile))(setq path ""))
  (if (and (setq fn (getfiled "Select Excel File (*.xlsx is default, change type if needed)" path "xlsx;xls;xlsm" 16))
           (setq xls-app (vlax-get-or-create-object "excel.application")))
    (progn (setq Shadi-LastXlsFile fn err (vl-catch-all-apply (function (lambda ()(setq workbooks (vlax-get-property xls-app 'workbooks)
      activeworkbook (vlax-invoke-method workbooks 'open fn) activesheet (vlax-get-property xls-app 'activesheet))))))
      (if (vl-catch-all-error-p err) (prompt (strcat "\nError: " (vl-catch-all-error-message err)))
(progn (vlax-invoke-method activesheet "Activate")(graphscr)(setq xldata (Shadi_Xls2Lst activesheet))))))
  (vl-catch-all-apply (function (lambda ()(vlax-invoke-method activeworkbook 'close :vlax-false))))
  (vl-catch-all-apply (function (lambda ()(vlax-invoke-method xls-app 'quit))))(Shadi_CloseExcel)

which i would assume replace the 'activesheet' areas wih some sort of way to tell it to go through each sheet and add the into onto the return at the end.


that way somehow i can run this for each sheet and continue to add it to the end return without overwriting it.

Code: [Select]
(defun Shadi_Xls2Lst
  ( %s / excel-range excel-used-range excel-max-row excel-max-column excel-max-range excel-variant excel-value excel-to-list lst)
  (defun _cl (i / n) (if (< i 27)(chr (+ 64 i))(if (= 0 (setq n (rem i 26)))
     (strcat (_cl (1- (/ i 26))) "Z")(strcat (_cl (/ i 26))(chr (+ 64 n))))))
 
  (setq excel-used-range (vlax-get-property  %s 'UsedRange))
  (setq excel-max-row (vlax-get-property (vlax-get-property excel-used-range "Rows") "Count"))
  (setq excel-max-column (vlax-get-property (vlax-get-property excel-used-range "Columns") "Count"))
  (setq excel-max-range (strcat "A1:" (_cl excel-max-column) (itoa excel-max-row)))

  (setq excel-range (vlax-get-property  %s 'Range excel-max-range))

  (setq excel-variant (vlax-get-property excel-range 'Value))
 
  (setq excel-value (vlax-variant-value excel-variant))
  (setq excel-to-list (vlax-safearray->list excel-value))
  (setq lst (mapcar '(lambda (x) (subst "" nil (mapcar '(lambda (y) (vlax-variant-value y)) x ))) excel-to-list))
  (princ)
  lst
)

perhaps im in over my head   :thinking:

BIGAL

  • Swamp Rat
  • Posts: 1417
  • 40 + years of using Autocad
Re: excel sheet list and selection
« Reply #3 on: February 20, 2024, 09:54:14 PM »
Ok step 1
Code: [Select]
(setq xlSheets (vlax-get-property myxl "Worksheets"))
(setq curSheet (vlax-get-property xlSheets "Item" 1))  ; 1 is 1st sheet need names of sheets somehow.
(vlax-invoke-method curSheet "Activate")


Code: [Select]
(setq lst '())
(vlax-for xlsheet xlsheets
(setq lst (cons (vlax-get xlsheet 'name) lst))
)
(setq lst (reverse lst))
(setq lst (cons "Please choose " lst))

(if (not AH:Butts)(load "Multi radio buttons.lsp")) ; loads the program if not loaded already
(setq ans (ah:butts 1 "V"   lst)) ; ans holds the button picked value as a string
; hidden inside Multi r is variable But.

(setq curSheet (vlax-get-property xlSheets "Item" but))
(vlax-invoke-method curSheet "Activate")


« Last Edit: February 20, 2024, 10:03:53 PM by BIGAL »
A man who never made a mistake never made anything