Jump to content

Either input allowed


saim

Recommended Posts

Is there a way to prompt something like "Click on a polyline with the desired elevation or just type the value" and AutoCad accept either input? How?

 

What I really want:

- if the user clicks on a polyline, I get the height and set it to variable H1

- if the user types an real value, I set it to the same variable H1

- if the usar clicks anywhere else or types anything but a real value, I understand that as an error and keep the command waiting for the correct input

- if the usar presses esc or enter, exit the command

Link to comment
Share on other sites

I use something similar to this quite a lot.

Something like

 

(Defun c:test ( / docontinue h1 end)

(While (not docontinue)

(Setq h1 (vl-catch-all-apply 'entsel (list "pick polyline or press enter to input value")))

(Cond

((Not h1)
(Setq h1 (getreal "enter value")
         docontinue T
         End nil)
)

((vl-catch-all-error-p h1)
(setq docontinue T
         End T)
)

(T (setq docontinue T
              End nil))
)
)

(If (not end)
'dosomething
(Print h1)

'else
(Print "You pressed escape")
)

(Princ)

)

 

untested code wrote on my phone but it should give you an idea

 

You can substitute the entsel for an ssget with ':e:s' and a polyline filter to make it more robust but have a play

 

Sent from my Pixel XL using Tapatalk

Edited by SLW210
Added Code Tags
Link to comment
Share on other sites

Should be able to put them manually, [NOPARSE]

Your Code Here[/NOPARSE]

 

But now that you mention it, I haven't used Tapatalk in quite some time, I'll look into that.

Link to comment
Share on other sites

Thanks! It'll take me a little time reading through the help file to check what some of the commands means, but I should be fine.

The code didn't work as it is right now, but I suppose I should change some stuff in it, right?

One tiny problem is that I didn't want to press enter before entering the value... I wish it was something like the "line" command, where you can either click somewhere to define the second point or just type in the coordinates. Tell me if I'm asking too much, I can live with pressing enter...

Link to comment
Share on other sites

If your mainly wanting to enter a value you can use getstring instead of entsel and check the value with the condition statement. I'll be able to get in the computer later and test something if your stuck.

 

Sent from my Pixel XL using Tapatalk

Link to comment
Share on other sites

Use [noparse](initget 128)[/noparse] to allow arbitrary input - here is a quick example:

(defun c:test ( / rtn )
   (while
       (progn (initget 128)
           (and (setq rtn (getpoint "\nPick a point or specify elevation <exit>: "))
               (not
                   (or (and (listp rtn) (setq rtn (caddr rtn)))
                       (setq rtn (distof rtn))
                   )
               )
           )
       )
       (princ "\nThe specified value is not numerical.")
   )
   (if rtn
       (princ (strcat "\nThe user entered " (rtos rtn)))
       (princ "\nThe user did not enter a value.")
   )
   (princ)
)

Link to comment
Share on other sites

Thanks again! That sounds pretty much more like what I have in mind. What I'm meaning to do is getting the topographic height into a variable - either clicking on the level curve, the point text (that comes along with the topography) or by typing it down. I think I'll be able to change the "getpoint" to an "entget" and copy-paste your code.

I'd appreciate if you commented that code, but spending some time crunching on it may help, too. The greatest problem seems to be that I don't know a lot of commands, perhaps just commenting won't help if I don't learn them. I'll do.

:)

 

...but I'd really like explained what the ( / rtn) part, on the first line, means. I have no idea how to look for it on the manual

Edited by saim
Link to comment
Share on other sites

Inside the brackets the left side of the / is for arguments sent to the command, on the right side are localised variables. This means if you set a variable in your code you also place the variable here and once the routine has finished the variables will be set back to nil. It's just a way of tidying up after yourself.

 

Sent from my Pixel XL using Tapatalk

Link to comment
Share on other sites

  • 2 weeks later...

There is no "spoiler" wrapping to hide all the rambling I made while typing all my doubts, so I'll wrap it in quote brackets. It might be useful in understanding my doubt.

I figured out a lot about how the code works, but could not fully understand the initget function. I assumed that if I typed anything, instead of clicking, the code would take it as a string. If that was correct, then the following code would work:

(
(initget 128)
(setq tstvar (getpoint "\nClick an object "))
(setq tstvar (distof tstvar))
)

Also tried with entget instead of getpoint (which is the final intent, by the way).

When I typed a real value instead of clicking some object, the "bad argument type" error came up and "tstvar" did not receive the inputted value (it received a point, which I can't find out how it was selected).

So... How does initget REALLY work?

 

 

Now, the rambling:

I'm diggin. Can't tell why it works (but it sure does!). I'll try to write this in pseudocode. Please tell me where I'm wrong.

 

(initget 128)

Allow either input. This seems to be the core of the answer. But I'm having problems in understanding the rest of the code.

 

(setq rtn (getpoint "\nPick a point or specify elevation <exit>: "))

"getpoint" Asks the user to click somewhere. I understand that the code will pause here until the user does something. Not sure what would happen when the value is typed in, I'm assuming the program will receive it as a string and the rest of the code will transform it into a real value.

 

 

(and (listp rtn) (setq rtn (caddr rtn)))

"rtn" is a list and the 3rd element on that list is a value. "rtn" becomes that 3rd element, a.k.a. the height of the point.

I'll call this "statement 1" for further using.

 

Doubt one: if the user types a value, listp will return "false". Will (caddr rtn) do anything? Tried to run that piece of code to a string and to a real value, both returned errors. Does it still happen during the code or is it skipped, somehow?

 

 

(setq rtn (distof rtn))

"rtn" gets transformed from the user input - a string - into a real value.

I'll call this "statement 2"

 

Doubt twoo: if the user inputs a click, I understand that at this point of the code, "rtn" would be the height - a real value. Tried (distof 4) and it returned an error (bad argument type). Does this still happen during the code or is it skipped, somehow?

Doubt three: Are errors treated like boolean values (false) by autolisp?

 

(or (and (listp rtn) (setq rtn (caddr rtn)))
(setq rtn (distof rtn))
)

Returns true if either statement1 or statement2 is true.

 

                (not
                   (or (and (listp rtn) (setq rtn (caddr rtn)))
                       (setq rtn (distof rtn))
                   )
               )

Returns false if either statement1 or statement2 is true. Or true, if they are both false.

I'll call this "statement3".

 

Hmmm... starting to make sense...

(and (setq rtn (getpoint "\nPick a point or specify elevation <exit>: "))
               (not
                   (or (and (listp rtn) (setq rtn (caddr rtn)))
                       (setq rtn (distof rtn))
                   )
               )
           )

If user inputted anything and it cound NOT be transformed into a real value, then returns true. If it DID get transformed into a real value, returns false. My confusion is because I expected that it returned "true" for the right input and it doesn't. Admitting the other way around clarifies things a little bit.

Link to comment
Share on other sites

Initget allows you to enter text when the getxxx command is called. You can then use cond to further test the response from the getxxx call. You can actually give a list of words after the initget, sort of like a filter. Look on Google for 'autolisp initget'.

 

Sent from my Pixel XL using Tapatalk

Link to comment
Share on other sites

Hopefully the following explanation will clear everything up:

([color=BLUE]defun[/color] c:test ( [color=BLUE]/[/color] rtn )
   [color=GREEN];; Define function, declare local variables[/color]
   
   ([color=BLUE]while[/color]
       [color=GREEN];; While the following returns a non-nil result[/color]
       [color=GREEN];; Read: "While the user provides some input and the input is invalid"[/color]
       
       ([color=BLUE]progn[/color]
           [color=GREEN];; Evaluate the following expressions and return the result of the last evaluated expression[/color]

           ([color=BLUE]initget[/color] 128)
           [color=GREEN];; Allow arbitrary input at the next prompt[/color]
           
           ([color=BLUE]and[/color]
               [color=GREEN];; Return T if ALL of the following expressions return a non-nil value[/color]
               [color=GREEN];; STOP evaluating expressions if an expression returns NIL (short-circuit evaluation)[/color]

               ([color=BLUE]setq[/color] rtn ([color=BLUE]getpoint[/color] [color=MAROON]"\nPick a point or specify elevation <exit>: "[/color]))
               [color=GREEN];; Prompt the user for a point or any text input[/color]
               [color=GREEN];; If the user presses ENTER here or right-clicks, AND will return NIL and the WHILE loop will cease[/color]


               [color=GREEN];; If we've reached this point, the user must have entered something or left-clicked the mouse[/color]
               
               ([color=BLUE]not[/color]
                   [color=GREEN];; Invert the value returned by the following expression[/color]
                   [color=GREEN];; Read: "While neither of the following are True"[/color]
                   
                   ([color=BLUE]or[/color]
                       [color=GREEN];; Return T if EITHER of the following expressions return a non-nil value[/color]
                       [color=GREEN];; STOP evaluating expressions if an expression returns T (short-circuit evaluation)[/color]
                       [color=GREEN];; Read: "Either..."[/color]

                       ([color=BLUE]and[/color]
                           [color=GREEN];; Return T if ALL of the following expressions return a non-nil value[/color]
                           [color=GREEN];; STOP evaluating expressions if an expression returns NIL (short-circuit evaluation)[/color]
                           
                           ([color=BLUE]listp[/color] rtn)
                           [color=GREEN];; Test whether the value returned by getpoint is a list[/color]
                           [color=GREEN];; Read: "The value is a list (i.e. the user clicked a point)"[/color]

                           ([color=BLUE]setq[/color] rtn ([color=BLUE]caddr[/color] rtn))
                           [color=GREEN];; If so, retrieve the 3rd element (i.e. the Z-coord)[/color]

                       ) [color=GREEN];; end AND[/color]

                       [color=GREEN];; Else 'rtn' is not a list and so must be a string[/color]
                       [color=GREEN];; Otherwise OR would have already returned T and the following would NOT be evaluated[/color]
                       
                       ([color=BLUE]setq[/color] rtn ([color=BLUE]distof[/color] rtn))
                       [color=GREEN];; Attempt to convert the string to a number[/color]
                       [color=GREEN];; This will return NIL if the string is not numerical, causing OR to return NIL, causing NOT to return T, causing the WHILE loop to continue[/color]

                   ) [color=GREEN];; end OR[/color]
                   
               ) [color=GREEN];; end NOT[/color]
               
           ) [color=GREEN];; end AND[/color]
           
       ) [color=GREEN];; end PROGN[/color]

       ([color=BLUE]princ[/color] [color=MAROON]"\nThe specified value is not numerical."[/color])
       [color=GREEN];; If we're here, the user must have entered non-numerical text[/color]
       [color=GREEN];; Inform them and continue the loop.[/color]
       
   ) [color=GREEN];; end WHILE[/color]

   ([color=BLUE]if[/color] rtn
       [color=GREEN];; If the variable 'rtn' holds a non-nil value[/color]
       
       ([color=BLUE]princ[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nThe user entered "[/color] ([color=BLUE]rtos[/color] rtn)))
       [color=GREEN];; Print the value[/color]
       
       ([color=BLUE]princ[/color] [color=MAROON]"\nThe user did not enter a value."[/color])
       [color=GREEN];; Else notify the user that no [valid] value was entered[/color]
       
   ) [color=GREEN];; end IF[/color]

   ([color=BLUE]princ[/color])
   [color=GREEN];; Supress the value returned by the last evaluated expression[/color]
   
) [color=GREEN];; end DEFUN[/color]

Please repay the time I have invested in constructing this explanation by investing the same amount of time reading & studying the comments carefully.

Link to comment
Share on other sites

Lee everytime I read something of yours I learn something new. 'Listp' I've always used type = 'list [emoji849]

 

Sent from my Pixel XL using Tapatalk

Link to comment
Share on other sites

Lee everytime I read something of yours I learn something new. 'Listp' I've always used type = 'list [emoji849]

 

Sent from my Pixel XL using Tapatalk

 

He is like the best LISP book out there! One can teach alot by reading his posts. :beer:

 

Perhaps this should clear things about listp :

 

_$ (listp nil)
T
_$ (type nil)
nil
_$ (eq (type nil) 'LIST)
nil

 

Note that nil symbol stands for 'empty list', thats why listp returns T.

 

Checks like (eq (type lst) 'LIST) or (vl-consp lst) will return true only if lst is indeed a list and is not null.

Link to comment
Share on other sites

I see, so if the variable cannot possibly be set as nil then use listp else use the eq type method?

 

Sent from my Pixel XL using Tapatalk

 

In short, yes - Lee did make sure that rtn holds a non-nil value by wrapping it inside the and expression,

(and
 ;; Return T if ALL of the following expressions return a non-nil value
 ;; STOP evaluating expressions if an expression returns NIL (short-circuit evaluation)
 
 (setq rtn (getpoint "\nPick a point or specify elevation <exit>: "))
 ...
)

then he performed the listp checking, which would mean if rtn is a list indeed - then to retrieve the Z-coord.

 

Else like he commented:

;; Else 'rtn' is not a list and so must be a string
;; Otherwise OR would have already returned T and the following would NOT be evaluated

 

 

 

BTW If you want to avoid type checking, another common way is:

(and lst (listp lst))

Which is equivalent of:

(vl-consp lst)

that I oftenly use.

Link to comment
Share on other sites

As for me, everything anyone posts has something new... XP

Thanks a huge bunch for the comments, Lee! I realised I wasn't totally wrong at the rambling, after all, was I?

The STOP evaluation conditions were gold! I would NEVER get to that info by just readind the help file.

So, if (listp rtn) returns false, then (setq rtn (caddr rtn)) won't do anything. If it does, then the rest of the "or" won't try to execute. Brilliant!

 

I did understand that (initget 128 ) will allow either input... but then, why doesn't that piece of code on my latest post work? This one:

(
(initget 128)
(setq tstvar (getpoint "\nClick an object "));I will just type a value, like 50
(setq tstvar (distof tstvar))
)

When I typed "50", I expected the tstvar to get that value, like in your code. I didn't test for a click, but since I didn't click, it shouldn't matter.

 

Other than that, I did a further reading on the help file and it seems that even if it worked, (initget 128 ) does NOT work with the entsel function. The only value that might allow entsel would be... none?

There IS a column in which entsel gets a tick, but it is listed before "bit 0" (in which I should type "1"), so I don't know if it really exists. Furthermore, all the other bits are shown with the input bit value between parenthesis, this one isn't.

Am I doomed to choose between using the initget or entsel?

Link to comment
Share on other sites

Thanks all - I'm pleased to see that this thread has evolved into an interesting discussion :thumbsup:

 

Thanks a huge bunch for the comments, Lee! I realised I wasn't totally wrong at the rambling, after all, was I?

The STOP evaluation conditions were gold! I would NEVER get to that info by just readind the help file.

So, if (listp rtn) returns false, then (setq rtn (caddr rtn)) won't do anything. If it does, then the rest of the "or" won't try to execute. Brilliant!

 

You're most welcome saim - I'm always happy to help those keen to learn.

 

The branching logic that I've implemented in my example is known as 'short-circuit evaluation' or 'McCarthy evaluation' (after John McCarthy, the inventor of LISP); it's a very useful exploit for writing concise code, but just be aware that other languages (for example VBA) don't offer this form of evaluation.

 

I did understand that (initget 128 ) will allow either input... but then, why doesn't that piece of code on my latest post work? This one:

(
(initget 128)
(setq tstvar (getpoint "\nClick an object "));I will just type a value, like 50
(setq tstvar (distof tstvar))
)

When I typed "50", I expected the tstvar to get that value, like in your code. I didn't test for a click, but since I didn't click, it shouldn't matter.

 

Because you have enclosed the three expressions inside outer parentheses, meaning the value returned is then evaluated as a function.

 

Try instead:

(defun c:test ( / tstvar )
   (initget 128)
   (setq tstvar (getpoint "\nClick an object ")) ;I will just type a value, like 50
   (if (= 'str (type tstvar))
       (setq tstvar (distof tstvar))
   )
)

Other than that, I did a further reading on the help file and it seems that even if it worked, (initget 128 ) does NOT work with the entsel function. The only value that might allow entsel would be... none?

 

Indeed entsel does not support arbitrary input - you would need to roll your own...

[color=GREEN];; Selection or Text  -  Lee Mac[/color]
[color=GREEN];; Prompts the user to select an object or enter an arbitrary string.[/color]
[color=GREEN];; msg - [str] [Optional] Prompt string[/color]
[color=GREEN];; ftr - [lst] [Optional] ssget filter list[/color]
[color=GREEN];; Returns: [ent/str] Entity name of selected entity or entered string; "" if enter is pressed.[/color]

([color=BLUE]defun[/color] LM:select-or-text ( msg ftr [color=BLUE]/[/color] gr1 gr2 rtn sel )
   ([color=BLUE]setq[/color] msg ([color=BLUE]princ[/color] ([color=BLUE]cond[/color] (msg) ([color=MAROON]"\nSelect object: "[/color])))
         rtn [color=MAROON]""[/color]
   )
   ([color=BLUE]while[/color]
       ([color=BLUE]progn[/color]
           ([color=BLUE]setq[/color] gr1 ([color=BLUE]grread[/color] [color=BLUE]nil[/color] 14 2)
                 gr2 ([color=BLUE]cadr[/color] gr1)
                 gr1 ([color=BLUE]car[/color]  gr1)
           )
           ([color=BLUE]cond[/color]
               (   ([color=BLUE]=[/color] 3 gr1)
                   ([color=BLUE]if[/color] ([color=BLUE]ssget[/color] gr2) [color=GREEN];; nentselp is slow for xrefs[/color]
                       ([color=BLUE]if[/color] ([color=BLUE]setq[/color] sel ([color=BLUE]ssget[/color] gr2 ftr))
                           ([color=BLUE]progn[/color] ([color=BLUE]setq[/color] rtn ([color=BLUE]ssname[/color] sel 0)) [color=BLUE]nil[/color])
                           ([color=BLUE]princ[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nInvalid object selected."[/color] msg))
                       )
                       ([color=BLUE]princ[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nMissed, try again."[/color] msg))
                   )
               )
               (   ([color=BLUE]=[/color] 2 gr1)
                   ([color=BLUE]cond[/color]
                       (   ([color=BLUE]<[/color] 31 gr2 127)
                           ([color=BLUE]setq[/color] rtn ([color=BLUE]strcat[/color] rtn ([color=BLUE]princ[/color] ([color=BLUE]chr[/color] gr2))))
                       )
                       (   ([color=BLUE]=[/color] 13 gr2)
                           [color=BLUE]nil[/color]
                       )
                       (   ([color=BLUE]and[/color] ([color=BLUE]=[/color] 8 gr2) ([color=BLUE]<[/color] 0 ([color=BLUE]strlen[/color] rtn)))
                           ([color=BLUE]setq[/color] rtn ([color=BLUE]substr[/color] rtn 1 ([color=BLUE]1-[/color] ([color=BLUE]strlen[/color] rtn))))
                           ([color=BLUE]princ[/color] [color=MAROON]"\010 \010"[/color])
                       )
                       (   [color=BLUE]t[/color]   )
                   )
               )
               (   ([color=BLUE]=[/color] 25 gr1)
                   [color=BLUE]nil[/color]
               )
               (   [color=BLUE]t[/color]   )
           )
       )
   )
   rtn
)

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...