LISP to grab text hyperlink and insert it into selected text

LISP to grab text hyperlink and insert it into selected text

brian_shick
Enthusiast Enthusiast
1,147 Views
12 Replies
Message 1 of 13

LISP to grab text hyperlink and insert it into selected text

brian_shick
Enthusiast
Enthusiast

Good morning,

I am trying to create a LISP file that will allow me to select a piece of text that has hyperlink data, copy the hyperlink information, store it, then insert that information into another piece of text on the next selection click, then clear the stored data and start over again.  I know this should be possible, but I don't see how to do this with the hyperlink data.

 

This is what I am trying to do:

1. Select a text string

2. Copy the "Hyperlink Path" and the "Text to Display" fields storing them in the code

3. Prompt for selection where to push the data into.

    a. Push hyperlink data into that selected text string.

4. Clear stored data

5. Prompt for next selection to copy hyperlink data

 

Does this sound possible to you?

Thanks for any suggestions.

 

0 Likes
Accepted solutions (1)
1,148 Views
12 Replies
Replies (12)
Message 2 of 13

hosneyalaa
Advisor
Advisor

Can you attached example drawing 

0 Likes
Message 3 of 13

paullimapa
Mentor
Mentor

this old thread describes the process to retrieve the hyperlink path (URL) and text to display (URL description):

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/get-hyperlink/td-p/848744

(setq ent (car (entsel "\nSelect Object: "))) ; select object with hyperlink:
(setq obj (vlax-ename->vla-object ent)
      hyprlnk (vlax-get-property obj 'Hyperlinks) ;The collection of all 
hyperlinks for 'obj'
)
; number of hyperlinks
(vlax-get-property hyprlnk 'Count) ; if 0 then no hyperlinks

; the first hyperlink
(setq hypr1 (vla-item hyprlnk 0))

; the URL for the first hyperlink
(setq linkUrl (vlax-get-property hypr1 'URL))

; URL description , the text you see on the screen
; when your mouse hoovers over the object
(setq linkDesc (vlax-get-property hypr1 'URLDescription))

 


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 4 of 13

pbejse
Mentor
Mentor


 a. Push hyperlink data into that selected text string.

As the string value of the text?

Prompt for next selection to copy hyperlink data

For a new source or the same source and apply to the next selected  text object? [ more than one selection?]

 

0 Likes
Message 5 of 13

Moshe-A
Mentor
Mentor
Accepted solution

@brian_shick  hi,

 

check this CPYHYP command

 

enjoy

Moshe

 

 

(defun c:cpyhyp (/ hasHyperLinkData ; local function
		   ss0 ss1 AcDbText0 AcDbHyperLinks0 AcDbText1 AcDbHyperLinks1 AcDbHyplnk0)

 (defun hasHyperLinkData (/ AcDbText AcDbHyperLinks n)
  (setq AcDbText (vlax-ename->vla-object (ssname ss0 0)))
  (setq AcDbHyperLinks (vla-get-hyperlinks AcDbText))

  (setq n (vla-get-count AcDbHyperLinks))
   
  (vlax-release-object AcDbHyperLinks)
  (vlax-release-object AcDbText)

  n
 ); hasHyperLinkData

 (while (and
          (not (prompt "\nPick source text: "))
          (setq ss0 (ssget ":s:e+." '((0 . "dtext,text"))))
          (not (prompt "\nPick target text: "))
          (setq ss1 (ssget ":s:e+." '((0 . "dtext,text"))))
        )
  (cond
   ((ssmemb (ssname ss1 0) ss0)
    (vlr-beep-reaction)
    (princ "\ninvalid target object.")
   ); case
   ((not (hasHyperLinkData))
    (vlr-beep-reaction)
    (princ "\nObject has no Hyperlink data.")
   ); case
   ( t
    (setq AcDbText0 (vlax-ename->vla-object (ssname ss0 0)))
    (setq AcDbHyperLinks0 (vla-get-hyperlinks AcDbText0))
    
    (setq AcDbText1 (vlax-ename->vla-object (ssname ss1 0)))
    (setq AcDbHyperLinks1 (vla-get-hyperlinks AcDbText1))

    (vlax-for AcDbHyplnk0 AcDbHyperLinks0
     ; copy hyperlink
     (vla-add AcDbHyperLinks1 (vla-get-URL AcDbHyplnk0) (vla-get-URLDescription AcDbHyplnk0) (vla-get-URlNamedLocation AcDbHyplnk0))

     (vla-delete AcDbHyplnk0)
     (vlax-release-object AcDbHyplnk0)
    ); vlax-for

    (vlax-release-object AcDbHyperLinks1)
    (vlax-release-object AcDbText1)
    
    (vlax-release-object AcDbHyperLinks0)
    (vlax-release-object AcDbText0)
   ); case
  ); cond
  
 ); while

 (princ)
)

 

 

 

0 Likes
Message 6 of 13

brian_shick
Enthusiast
Enthusiast

Here is a copy of the example...

The problem has gotten worse, they have decided to post the DWF and PDF to a website so the existing back slashes will need to become forward slashes.  The attached drawing shows what we are trying to do. The requirement is on the printed version to have 2 buttons that the user can select the type of file to open.

 

I know it's getting extremely complicated now so if you have any better suggestions, please let me know.

0 Likes
Message 7 of 13

komondormrex
Mentor
Mentor

hey,

check the following

(defun c:update_hl (/ file_name hyper_link)
  	(setq file_name (getpropertyvalue (car (entsel "\nPick schematic text number: ")) "text"))
  	(prompt "\nSelect button blocks to update...")
	(foreach insert (mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget '((0 . "insert") (2 . "link to *f")))))))
	  (cond
	    	((= "LINK TO DWF" (vla-get-effectivename insert))
		 	(setq hyper_link (vla-item (vla-get-hyperlinks insert) 0))
			(vla-put-urldescription hyper_link (strcat file_name ".DWF"))

		)
		((= "LINK TO PDF" (vla-get-effectivename insert))
		 	(setq hyper_link (vla-item (vla-get-hyperlinks insert) 0))
			(vla-put-urldescription hyper_link (strcat file_name ".PDF"))
		)
		(t)
	  )
	)
  (princ)
)
0 Likes
Message 8 of 13

Sea-Haven
Mentor
Mentor

Try this very much coded to what was provided, have the excel open before running code.

It is possible to read a Excel direct from CAD and make a list of the 3 cells, so that is handled, then making a list of all blocks by name with the 2 attributes so find and update. Thanks to @komondormrex  for the URL bit. The properties show the description hence URL & description updated.

 

 

;https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/update-hyperlink-path-in-blocks-from-xls/td-p/13101894
; By AlanH OCT 2024

(defun upurl ( / getcell2 myxl row rowmax x k ss ss2 ent banme obj atts att1 att2)

;;	Thanks to fixo			;;
(defun getcell2 (row column / )
(setq cells (vlax-get-property  (vlax-get-property myxl "ActiveSheet") "Cells"))
(setq cell (vlax-get (vlax-variant-value  (vlax-get-property cells "Item" row column)) 'value))
)

(or (setq myxl (vlax-get-object "Excel.Application"))
    (setq myxl (vlax-get-or-create-object "excel.Application"))
)
(vla-put-visible myXL :vlax-true)
(vlax-put-property myxl 'ScreenUpdating :vlax-true)
(vlax-put-property myXL 'DisplayAlerts :vlax-true)

(setq row 2)
(setq rowmax (- (getint "\nEnter last row number ") 1))

(setq lst '())
(repeat rowmax
(setq c1 (getcell2 row 1)
  c2 (getcell2 row 2)
  c3 (getcell2 row 3)
)
(setq lst (cons (list c1 c2 c3) lst))
(setq row (1+ row))
)

(setq ss (ssget (list (cons 0  "INSERT")(cons 2 "**U*"))))

(if (= ss nil)(progn (Alert "you have not selected any DetailBubble blocks will exit ")(exit)))

(setq ss2 (ssadd))

(repeat (setq k (sslength ss))
 (setq ent (ssname ss (setq k (1- k))))
 (setq bname (vlax-get (vlax-ename->vla-object ent) 'effectivename))
 (if (= bname "DetailBubble")
  (setq ss2 (ssadd ent ss2))
 )
)

(repeat (setq k (sslength ss2))
 (setq obj (vlax-ename->vla-object (ssname ss2 (setq k (1- k)))))
 (setq atts (vlax-invoke obj 'Getattributes))
 (setq att1 (vlax-get (car atts) 'textstring))
 (setq att2 (vlax-get (cadr atts) 'textstring))
 (setq hyper_link (vla-item (vla-get-hyperlinks obj) 0))
 (repeat (setq x (length lst))
  (setq hyp (nth (setq x (1- x)) lst))
  (setq hyp1 (car hyp) hyp2 (cadr hyp) hyp3 (caddr hyp) )
  (if (and (= hyp1 att1)(= hyp2 att2))
   (progn
   (vla-put-url hyper_link hyp3)
   (vla-put-urldescription hyper_link hyp3)
   )
  )
 )
)

(princ)
)

 

 

Message 9 of 13

thaydenCJMLL
Contributor
Contributor

Hi @Sea-Haven 

 

Thanks for sharing this - it seems close to the solution I need!

 

When I run this, as (upurl), with the spreadsheet open and active, it opens a blank instance of an Excel file, and asks me for a row number. I type 8 - that's the last row in my test spreadsheet.

 

I then get a  "bad argument type: VLA-OBJECT nil" error.

 

I added (vl-load-com) at the beginning of the code, but not sure why it's opening another instance of Excel.  Also, I found a typo- in the variable list for "bname" (it was spelled "banme").

 

Here is what I'm working with now: 

 

(defun upurl ( / getcell2 myXL row rowmax x k ss ss2 bname ent obj atts att1 att2)
(vl-load-com)
;;	Thanks to fixo			;;
(defun getcell2 (row column / )
(setq cells (vlax-get-property  (vlax-get-property myXL "ActiveSheet") "Cells"))
(setq cell (vlax-get (vlax-variant-value  (vlax-get-property cells "Item" row column)) 'value))
)
(or (setq myXL (vlax-get-object "Excel.Application"))
    (setq myXL (vlax-get-or-create-object "excel.Application"))
)
(vla-put-visible myXL :vlax-true)
(vlax-put-property myXL 'ScreenUpdating :vlax-true)
(vlax-put-property myXL 'DisplayAlerts :vlax-true)
(setq row 2)
(setq rowmax (- (getint "\nEnter last row number ") 1))
(setq lst '())
(repeat rowmax
(setq c1 (getcell2 row 1)
  c2 (getcell2 row 2)
  c3 (getcell2 row 3)
)
(setq lst (cons (list c1 c2 c3) lst))
(setq row (1+ row))
)
(setq ss (ssget (list (cons 0  "INSERT")(cons 2 "**U*"))))
(if (= ss nil)(progn (Alert "you have not selected any DetailBubble blocks will exit ")(exit)))
(setq ss2 (ssadd))
(repeat (setq k (sslength ss))
 (setq ent (ssname ss (setq k (1- k))))
 (setq bname (vlax-get (vlax-ename->vla-object ent) 'effectivename))
 (if (= bname "DetailBubble")
  (setq ss2 (ssadd ent ss2))
 )
)
(repeat (setq k (sslength ss2))
 (setq obj (vlax-ename->vla-object (ssname ss2 (setq k (1- k)))))
 (setq atts (vlax-invoke obj 'Getattributes))
 (setq att1 (vlax-get (car atts) 'textstring))
 (setq att2 (vlax-get (cadr atts) 'textstring))
 (setq hyper_link (vla-item (vla-get-hyperlinks obj) 0))
 (repeat (setq x (length lst))
  (setq hyp (nth (setq x (1- x)) lst))
  (setq hyp1 (car hyp) hyp2 (cadr hyp) hyp3 (caddr hyp) )
  (if (and (= hyp1 att1)(= hyp2 att2))
   (progn
   (vla-put-url hyper_link hyp3)
   (vla-put-urldescription hyper_link hyp3)
   )
  )
 )
)
(princ)
)

 

But I'm still getting the error "bad argument type: VLA-OBJECT nil".

 

In VLIDE, I  ran a "Check Selection" - and this is the return (not sure what I'm doing wrong):

 

[CHECKING TEXT <Untitled-0> loading... SELECTION]
.
; warning: local variable used as function: GETCELL2
; warning: local variable used as function: GETCELL2
; warning: local variable used as function: GETCELL2
; Check done.

0 Likes
Message 10 of 13

Moshe-A
Mentor
Mentor

@thaydenCJMLL  hi,

 

Can not run your lisp cause you did not provide sample dwg but i notice this:

 

correct the following code

(cons 2 "**U*")

 

with this code:

(cons 2 "`*U*")

 

in this line

(setq ss (ssget (list (cons 0  "INSERT")(cons 2 "**U*"))))

 

Moshe

 

Message 11 of 13

thaydenCJMLL
Contributor
Contributor

Hi Moshe-A - thanks for finding those typos! I'll update my working code and try it again.

 

I posted my original question in a different thread here (with sample drawing and xls attached. note that the detail tag blocks are Dynamic):

 

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/update-hyperlink-path-in-blocks-from... 

 

 

Edited To Add:

I replaced the typo's in the code you found, but I'm still getting the error "bad argument type: VLA-OBJECT nil"  argh.

 

I'll work with it more this afternoon and see if I can find a breakthrough.

0 Likes
Message 12 of 13

thaydenCJMLL
Contributor
Contributor

I made a tiny bit of progress:  I realized there is case sensitivity in vlax calls.

 

I revised at line 2 in the example, below:

(or (setq myXL (vlax-get-object "Excel.Application"))
    (setq myXL (vlax-get-or-create-object "excel.Application"))

 

to

 

(or (setq myXL (vlax-get-object "Excel.Application"))
    (setq myXL (vlax-get-or-create-object "Excel.Application"))

 

Note the "E" in the 2nd line of Excel.Application is now capitalized.

 

I passed into the code where I was asked to select the blocks to be processed. and I got this error:

 

2024-11-19_21-50-10.png

 

Please note, this was in my version of the DetailBubble block that I removed all dynamic features from.

 

The dynamic blocks didn't get that far.

 

More sleuthing....

 

 

 

 

0 Likes
Message 13 of 13

thaydenCJMLL
Contributor
Contributor

I realized the original code from @Sea-Haven  is possibly intended to account for Dynamic Blocks. 

 

from https://www.cadtutor.net/forum/topic/54306-lisp-to-select-blocks-using-wildcard/ 

 

"When the dynamic properties of a dynamic block are changed, AutoCAD will automatically generate a new anonymous block definition for the block reference, which is then linked to the original dynamic block definition. Such anonymous block definitions have names *U###, as you have witnessed."

 

This is addressed in the line:

 

(setq ss (ssget (list (cons 0  "INSERT")(cons 2 "**U*"))))

 

I'm prioritizing processing the dynamic block version of the DetailBubble block (for now).

0 Likes