Enter key to repeat

Enter key to repeat

saitoib
Advocate Advocate
2,668 Views
21 Replies
Message 1 of 22

Enter key to repeat

saitoib
Advocate
Advocate

Hi all!

I want to make it so that when I ask for user input in a while iteration, if the value is the same as the last time, all I have to do is press Enter.
So, I came up with the following code.
However, I'm wondering if I can make it a bit smarter and more Lisp-like.

 

Please give me some advice.

(defun c:test1 (/ inp temp)
	(while (and
		(if (not inp)
			(progn
				(initget 7)
				(setq inp (getreal "\nEnter a real number :"))
			)
			(progn
				(initget 6)
				(setq temp inp)
				(prompt "\nEnter a real number <")
				(princ inp)
				(setq inp (getreal "> :"))
				(if (not inp)
					(setq inp temp)
					(setq inp inp)
				)
			)
		)
		(princ "\nInput Data = ")
		(princ inp)
		(princ)
	))
)

 

Saitoib
0 Likes
Accepted solutions (3)
2,669 Views
21 Replies
Replies (21)
Message 2 of 22

Moshe-A
Mentor
Mentor
Accepted solution

@saitoib ,

 

the technique i use for many years is to design specific data input function to handle this like (askReal) function.

it pauses for data while it offers a default value. the check for the value can be done in the calling function (as it presented here) or in (askreal). the same technique can be used for getting an integer\string or key words.

 

(c:test) function starts by checking USERR1 sysvar and if it still has a zero value set it to my default value to be offered to user. USERR1 is than set with the value returned from (askreal).

 

AutoCAD has 15 undocumented sysvars:-

USERI1-USERI5    for integers values.

USERR1-USERR5  for real values.

USERS1-USERS5  for strings.

 

these sysvars holds their values only for the duration of the current session and are reset each time the dwg is opened. of course you can use your own variables (instead of USERxx ) to store your data but these variable must be declared as globals while by using USERxx you can keep your variables as locals.

 

enjoy

moshe

 

 

 

 

 

(defun c:test (/ askreal ; local function
                 ndef flag inp)
  
 (defun askReal (m d / v)
  (initget (+ 2 4)) ; prohbit negative & zero values
  (if (not (setq v (getreal (strcat "\n" m " <" (rtos d 2) ">: "))))
   (setq v d)
   (setq d v)
  )
 ); askReal

 
 ; here start c:test
 (if (= (getvar 'userr1) 0.0)
  (setvar 'userr1 (setq ndef 1.0))
  (setq ndef (getvar 'userr1))
 )

 (while (not flag)
  (setvar 'userr1 (setq inp (askReal "Enter real value" ndef)))

  (cond
   ((= inp 10)
    (setq flag t)
    ; do you code
    ; ...
    ; ...
   )
   ( t
    (vlr-beep-reaction)
    (setq flag (prompt "\ninvalid value."))
    ; re loop
   ) 
  ); cond
   
 ); while

 (princ)  
); c:test

  

 

 

 

0 Likes
Message 3 of 22

ВeekeeCZ
Consultant
Consultant

Here's what I typically do. Sure you can do that without the initial default value but why?! It just complicates things. 

 

(defun c:test nil
  
  (or *t-inp*			; global variable
      (setq *t-inp* 1.)) 	; initial default value
  
  (initget (+ 2 4))
  (setq *t-inp* (cond ((getreal (strcat "\nEnter a real number <" (vl-princ-to-string *t-inp*)  ">: ")))
		      (*t-inp*)))
  )

 

This approach is applicable for all get* functions returning nil on <enter> but the getstring, returning "". If you need a string, and a single word only, you may use the getkword with arbitrary input. Else you need to modify it to test on equality to "".

0 Likes
Message 4 of 22

Kent1Cooper
Consultant
Consultant

@Moshe-A wrote:

....

AutoCAD has 15 undocumented sysvars:-

USERI1-USERI5    for integers values.

USERR1-USERR5  for real values.

USERS1-USERS5  for strings.

 

these sysvars holds their values only for the duration of the current session and are reset each time the dwg is opened. ....


Just to set the record straight, those are not undocumented!  From >this page< of System Variables starting with U in Help [here for Acad2021]:

 

Kent1Cooper_0-1616496886583.png

 

And the USERI1-5 [Integer] and USERR1-5 [Real number] System Variables are saved in the drawing, and will still be there the next time it is opened.  Only USERS1-5 [String] for some reason are not saved.

Kent Cooper, AIA
0 Likes
Message 5 of 22

Kent1Cooper
Consultant
Consultant

That can be handled in several ways depending on the kind of value involved, whether or not you want to offer a particular default value if the User has not yet specified one, and if not to prevent Enter on first use, whether you want to offer a limited selection of options or accept any appropriate input, and for a numerical value whether it is allowed to be zero and/or negative.

 

When I want to offer a specific value as a first default, I don't usually set that in ahead of time if there's no User value yet, but build it right into the (get...) function.  Here's one to set a Fillet radius [allowed to be zero, but not negative] for a special-purpose command, offering as the default the previous setting if there is one, but if not, the current radius setting for regular Fillet:

  (initget 4); no negative
  (setq *fmpr* ; global variable
    (cond
      ( (getdist ; [returns nil on Enter]
          (strcat
            "\nRadius for Filleting all Polyline corners <"
            (rtos (cond (*fmpr*) ((getvar 'filletrad))))
              ; offer prior value as default if present; if not, regular Fillet radius
            ">: "
          ); strcat
        ); getdist            
      ); User-input condition
      (*fmpr*); prior value if present on Enter
      ((getvar 'filletrad)); regular Fillet radius if no prior value on Enter
    ); cond
  ); setq

Here's one for a displacement-type distance, which in this particular command is allowed to be negative, but not zero, and with no particular value appropriate to offer as default on first use, so not permitting Enter unless there is a value:

  (initget (if *RSAdelta* 2 3)); no zero, no Enter on first use
  (setq *RSAdelta* ; global variable for subsequent-use default
    (cond
      ( (getdist
          (strcat
            "\nEdge length change {positive or negative}"
            (if *RSAdelta* (strcat " <" (rtos *RSAdelta*) ">") "")
              ; offer prior value as default if present, otherwise no default
            ": "
          ); strcat
        ); getdist
      ); User-input condition
      (*RSAdelta*); prior value if present
    ); cond & *RSAdelta*
  ); setq

There are many other possibilities.  For example, text-string variables such as Layer or Block names need to be handled differently because (getstring) does not return nil on Enter, as (getint) and (getreal) and (getdist) and (getangle) do, but a text string that "exists" but contains no characters [""].  With specific option possibilities, (getkword) is a better approach than (getstring).

 

In your particular example, I would do it this way:

(initget (if inp 6 7)); no zero, no negative, no Enter unless there's a prior value
(setq inp
  (cond
    ( (getreal ; returns nil on Enter [when permitted]
        (strcat
          "\nEnter a real number"
          (if inp (strcat " <" (rtos inp) ">") "")
            ;; offer default if prior value, otherwise add nothing
          ": " ; end of prompt
        ); strcat
      ); getreal
    ); end User-input condition
    (inp); prior value on Enter [when permitted]
  ); cond
); setq

If you hit Enter on first use when there's no prior value set yet, it will keep asking again until you give it a number.

 

[That (rtos inp) will display the prior value in whatever the current units mode and precision settings are, but can be made more particular.]

Kent Cooper, AIA
0 Likes
Message 6 of 22

john.uhden
Mentor
Mentor

@saitoib 

You have received excellent responses.

All I have to add is that if you multiple defaults (from a previous usage) that you want to start with, then write them to and re them from a file.  One typical way is to write them in AutoLisp format, e.g.

("width" 0.5)

("height" 2.5)

("material" "PVC")

  in a file named C:\Custom\Test.dft

Then, to read the defaults...

(and
  (setq file "c:\\custom\\test.dft")
  (setq fp (open file "r"))
  (while (setq line (read-line fp))
    (setq lines (cons line lines))
  )
  (not (close fp))
  (mapcar '(lambda (x)(set (read (car x))(cadr x)))(mapcar 'read lines))
)

 

John F. Uhden

0 Likes
Message 7 of 22

ronjonp
Advisor
Advisor
Accepted solution

@Moshe-A FWIW, your 'askreal' function could be as simple as this. I like to use getdist over getreal so you can either pick a distance on screen or enter it via command line. 🍻

 

(defun askreal (m d)
  (initget (+ 2 4))			; prohbit negative & zero values
  (cond	((getdist (strcat "\n" m " <" (rtos d 2) ">: "))) (d))
)					; askReal

 

 

 

0 Likes
Message 8 of 22

john.uhden
Mentor
Mentor
@ronjonp
That's clever using getdist.
You could also throw the initget value in as an argument.

John F. Uhden

0 Likes
Message 9 of 22

ronjonp
Advisor
Advisor

@john.uhden  Thanks! 🙂 Adding the initget as an argument is definitely an option too. 🍻

 

Using (VL-PRINC-TO-STRING d) in the default message won't assume a precision either.

 

 

0 Likes
Message 10 of 22

Moshe-A
Mentor
Mentor

@ronjonp 


@ronjonp wrote:

@Moshe-A FWIW, your 'askreal' function could be as simple as this. I like to use getdist over getreal so you can either pick a distance on screen or enter it via command line. 🍻

 


hey? the OP request was (getreal) is it right to assume he knows what he wants?

 

0 Likes
Message 11 of 22

john.uhden
Mentor
Mentor
I almost forgot, but now I think I remember...
I found that using getstring was the answer for accepting architectural
units as input., then using distof.

John F. Uhden

0 Likes
Message 12 of 22

john.uhden
Mentor
Mentor
@Moshe-A
It is right to make the OP aware of alternatives that may improve the
functionality of his work. Thankfully this is not a case of the "needy"
who wants his meal prepared and served, for free no less. Plus, we get to
enjoy (and learn from) each others thoughts.

John F. Uhden

0 Likes
Message 13 of 22

Moshe-A
Mentor
Mentor

@john.uhden 

 

to much overloading the OP is also not right 😍

 

 

 

0 Likes
Message 14 of 22

john.uhden
Mentor
Mentor
@Moshe-A
Should my mother not have graduated from high school at age 14?

John F. Uhden

0 Likes
Message 15 of 22

ronjonp
Advisor
Advisor

@Moshe-A wrote:

@ronjonp 


@ronjonp wrote:

@Moshe-A FWIW, your 'askreal' function could be as simple as this. I like to use getdist over getreal so you can either pick a distance on screen or enter it via command line. 🍻

 


hey? the OP request was (getreal) is it right to assume he knows what he wants?

 


Assume nothing 😋 either way getdist and getreal return a real :).

0 Likes
Message 16 of 22

Kent1Cooper
Consultant
Consultant

@john.uhden wrote:
I almost forgot, but now I think I remember...  I found that using getstring was the answer for accepting architectural units as input., then using distof.

No need -- if your Units are Architectural, you can use them in response to (getdist), and it will return the real-number equivalent:


Command: (getdist)
{type in} 4'6-1/4"
{returns} 54.25

Kent Cooper, AIA
0 Likes
Message 17 of 22

ВeekeeCZ
Consultant
Consultant
Accepted solution

@saitoib wrote:

 

Please give me some advice.

(defun c:test1 (/ inp temp)
	(while (and  ; why while or even and???
		(if (not inp)
			(progn
				(initget 7)
				(setq inp (getreal "\nEnter a real number :"))
			)
			(progn
				(initget 6)
				(setq temp inp)
				(prompt "\nEnter a real number <")
				(princ inp)
				(setq inp (getreal "> :"))
				(if (not inp)
					(setq inp temp)
					(setq inp inp)
				)
			)
		)
		(princ "\nInput Data = ")
		(princ inp)
		(princ)
	))
)

 


 


;; if version
  (initget (if inp 6 7))
  (setq tmp (getreal (strcat "\nEnter a real number" (if inp
						       (strcat "<" (rtos inp 2) ">: ")
						       ": "))))
  (setq inp (if tmp tmp inp))
  (princ (strcat "\nInput Data = ") (rtos inp 2))


;; cond version - no need for tmp variable - much more popular
  (initget (if inp 6 7))
  (setq inp (cond ((getreal (strcat "\nEnter a real number" (if inp
							      (strcat "<" (rtos inp 2) ">: ")
							      ": "))))
		  (inp)))
  (princ (strcat "\nInput Data = ") (rtos inp 2))

 

0 Likes
Message 18 of 22

saitoib
Advocate
Advocate

Thank you, everyone.
You have given me a lot of guidance, and I think it will take me a long time to understand it all.
For now, I would like to thank you.

Saitoib
0 Likes
Message 19 of 22

Sea-Haven
Mentor
Mentor

Why not another, would need a wrapper though to check what is entered is it say a number and greater than -1 for the example like filletrad. If not do again.  Certainly can save the value you can setenv and getenv very easy. The value displayed can be set as last entered. Its a library dcl use in any code.

 

screenshot362.png

 

 

0 Likes
Message 20 of 22

john.uhden
Mentor
Mentor
@Sea-Haven
Yeah, setenv and getenv are handy, but I think they are on a per-profile
basis.
I got into storing defaults in .DFT files to avoid that and to be able to
copy the files onto other workstations back when I was the CAD Manager.

John F. Uhden

0 Likes