User input & System variables |
![]() |
Most programs require some information from the user. AutoLISP includes a set of functions designed to get user input (see "4 - User input" in the Catalog of Function Definitions). These functions are sometimes called get-functions because they all begin with "get...". This lesson illustrates several of these functions as well as the initget function, which controls the allowable input for the get-functions. It also covers system variables.
The get-functions
All of the get-functions pause for user input. They can also display a prompt to tell the user what type of information to enter. Their ability to wait for input sets them apart from other AutoLISP functions. The other functions execute completely without any further user input. When you typed the various expressions from the previous practice sessions, they executed completely, their result was displayed, then the AutoCAD command prompt reappeared, at which time AutoCAD waits for your next command. But the get-functions pause for user input before returning any result.
The getint function
The getint function pauses for the user to enter an integer. If you enter (getint) at the AutoCAD command prompt, it pauses until you enter an integer, then returns that integer. If you enter something other than an integer, getint responds with an appropriate error message. For example, if you enter the letters "seven," or the floating point real 5.5, getint would display the error message "Requires and integer value" and then prompt you to "Try again". There is one other thing the getint function will accept: you can simply press 'Enter' without typing an integer (this is known as a "null response"). When you give a null response to getint, it returns nil.
Recommendation: You should experiment with getint at the command prompt. It is well worth your time with this function, as with all functions, to try out various forms and various input in order to "get to know" the functions. Also, it is very helpful to you if, as you learn the various functions, you learn not only the name and the syntax, but also exactly what the function will and will not accept, and exactly what the function returns (including what the function returns when you give a null response).
Suppose you are writing a program to make some calculations for a chain drive. At a certain place in the program you will use the getint function to get two integers from the user: the number of teeth on the small and large sprockets. You will need to include a prompt in each getint expression, and you will need to save the value that the user enters by surrounding the getint expression with a setq expression. It would look something like this in your program.
(setq teeth1 (getint "\nNumber of teeth
on small sprocket: "))
(setq teeth2 (getint "\nNumber of teeth
on large sprocket: "))
Although the prompt is optional, without it the user would not know which number to enter first. And without the setq function the number would be lost.
Also notice the following:
The getreal function pauses for the user to enter a real (floating point decimal) number. You will use getreal more often than getint, as the sample programs in the previous lessons illustrate. Nevertheless, both are important. At times a program need a real, at other times it needs an integer.
The getreal function works just like the getint function with these two exceptions:
The getpoint and getcorner functions
The getpoint function pauses for the user to locate a point. The point can be located with the mouse, or from the keyboard. The user can use the usual osnap modes, or the program can enable a particular osnap mode for the user. Getpoint will take a point argument, or a string argument (a prompt), or both and would usually be surrounded by a setq expression. Below is an example of getpoint with a string argument as a prompt.
(setq p1 (getpoint "\nLocation of first point: "))
The getpoint function returns a list of three reals, which are the X, Y, and Z coordinates of the point. Even if the user enters only the X and Y coordinates at the keyboard (for example "4,2"), getpoint adds the Z coordinate and returns the list (4.0 2.0 0.0). If the elevation is currently set (with the ELEV command) at something other than zero, and only two points are indicated (when picking by mouse or entering two coordinates at the keyboard), then getpoint adopts the current elevation as the Z coordinate.
When a point argument is added, as shown below, that point is used as the anchor for a rubber-band cursor as the user moves the mouse away from the anchor point. The point argument can be placed before or after the string argument (most programmers put it before).
(setq p2 (getpoint p1 "\nLocation of second point: "))
This use of an anchor (or "base") point was used in the mslot sample program in Lesson 1 (line 10).
The getcorner function is very similar to getpoint. The main difference is that it requires the point argument, and it uses that point as the anchor for a rectangular rubber-band cursor rather than a straight line rubber-band cursor.
To enable a particular osnap mode so that the mode is displayed dynamically as the user moves the cursor around the screen, use a sequence like this:
(setvar "osmode" 1)
; 1 enables endpoint
(setq p7 (getpoint "\nPick point: "))
(setvar "osmode" 0)
; 0 disables all running osnap modes
The getstring function
The getstring function pauses for the user to enter a string, up to 132 characters. It takes a string argument (a prompt), a non-nil argument (to allow spaces), or both. For example:
(getstring "\nEnter color: ")
would accept a single word (no spaces) and return that word as a string. If you tried to enter a space, the space would function as an 'Enter' just like it usually does. In contrast,
(getstring 1 "\nEnter description: ")
would accept a phrase including spaces. The phrase must be entered with the 'Enter' key rather than the space bar. The use of the number 1 as the non-nil argument is better than using T as you will often see recommended, because T can be accidentally set to nil, but 1 cannot. As with getpoint, either order will work, but most programmers place the non-nil argument before the prompt.
The initget function takes an integer or string argument, or both, which place limitations on the responses allowed for the next get-function. (String arguments are discussed in a later lesson.) For example, in the following sequence the initget function with the integer 4 initializes the getreal function so that the user cannot enter a negative number.
(initget 4)
(setq wid (getreal "\nEnter width: "))
If the user enters a negative number, a prompt appears indicating that the number must be positive and the user is told to try again.
The integers are bitwise, which means that they are best understood
when you think of the binary equivalents of the integers. Below are
the first five integers with their binary equivalents, for illustration.
When the first column of the binary number (counting from the right) is
flagged (has a 1), null response is disallowed. When the second column
is flagged, no zeros are allowed. When the third column is flagged,
no negative numbers are allowed.
Decimal | Binary | Meaning |
1 | 0001 | no null response |
2 | 0010 | no zeros |
3 | 0011 | no zeros and no null response |
4 | 0100 | no negative numbers |
5 | 0101 | no negative numbers and no null response |
See initget under "4 - User input" for a complete list of numbers and their meaning.
The above discussion pertains to the use of initget with the getreal function. Initget works similarly with getint and getdist, but there are some differences when you use initget with the other get-functions. There is a helpful chart of the various get-functions and how initget values effect them in the AutoCAD R14 Customization Guide, under "initget."
Using initget is very important to your program because it filters out bogus input and thus keeps the program from crashing. Just one simple scenario will make the point. Suppose you are getting a number from the user which you plan to use later in the program as a divisor. You do not want the user to enter a zero, since that would cause the program to crash and return a "divide by zero" error message. Using initget with an argument of 2 (or any number which in binary flags the second column) will keep the user from entering a zero.
Practice session
Practice entering each of the get-functions described above, without prompts, with prompts, with additional arguments where appropriate, and with initget. Notice not only what works and what does not work, and not only the data type returned, but also what is returned for a null response.
AutoCAD uses over 200 system variables to store information about the drawing and the drawing environment. You will find all the system variables listed in Appendix B of the AutoCAD R14 Command Reference. This appendix also lists the data type of each variable and where it is stored.
Most of these variables are set in the normal course of creating and editing a drawing. For example, when you hit function key F7 (or click on "GRID" in the status bar) to turn the grid on or off, its new state is recorded in system variable "gridmode." And when you change the size of the pickbox used to select entities, its new size is recorded in system variable "pickbox." Many of these system variables are saved with the drawing, so the settings will be the same the next time you edit the drawing. Others, in order to be consistent from one drawing to the next, are saved in the Windows registry.
AutoLISP has two functions devoted to retrieving and setting system variables: getvar and setvar. You can retrieve the current value of any system variable with the getvar function. You can set most system variables to a new value with the setvar function (some system variables are read-only and cannot be changed with setvar).
The syntax of the setvar function is simple. It takes one argument, the name of the system variable as a string (enclosed in quotation marks). For example
The syntax of the setvar function is also simple. The first argument is the name of the system variable as a string. The second argument is the value to be assigned to that system variable, submitted in the same form that getvar would retrieve it. Thus if you are setting "orthomode," you would submit an integer, but if you are setting "limmax," you would submit a 2D point. For example,
There are several other data types which are listed in the practice session below.
Another practice session
Experiment with several system variables. For example:
Sample program,
table
Designers often need to include tables in their drawings. Tables
can be used to list revisions, bolt circle offsets, parametric dimensions,
and many other things. The table program illustrates most of the
functions discussed in this lesson and produces a table similar to the
one shown here.
The user determines these aspects of the table:
There is another aspect of the program which, because it has been kept simple, might cause some confusion. In section 50 the program takes the simplest approach possible to detecting whether the current text style has a variable or fixed height. (Several functions used in this section are not explained until later lessons). In the last line of section 50, the program sets the text height at one-half the row height, which is a reasonable height for the header as well as for any text placed in the table later. But whether or not that text height is applied to the header depends on the drawing's current text style. If the current text style has a variable height (if the height for the current style is set to zero), then the program's setting for the text height is used. But if the current text style has a fixed height, then the program uses that fixed height. A more sophisticated program might create a new text style or give the user the option to alter the fixed height, or even change fonts for the header, etc.
Notice that variable sp serves several different roles in the program. It holds different starting points for each of the vertical lines (section 30), then for each of the horizontal lines (section 40), then for the middle point of the text (section 50). Variable len also holds two different values (the length of vertical lines, then the length of horizontal lines). And variable rowhei is reset (see third line in section 50) if the current text style has a fixed height. (The table has already been drawn at this point, so this does not change the height of the rows in the table. It merely allows the text to be spaced a reasonable distance above the table even if the current fixed text height is much smaller or larger that what would be appropriate for text inside the table.)
Notice also that this program captures the current settings of two system variables, blipmode and osmode (section 10). Then blipmode is turned on before picking the upper left corner of the table (section 20) then turned off before drawing all the lines (section 30). Osmode (osnap mode) is turned off before the lines are drawn. This is a precaution, in view of the possibility that, after the table is drawn, it might overlap existing geometry. (This situation could cause lines to be drawn incorrectly if a running osnap mode were enabled while the program was drawing the lines.) Both system variables are then reset to their original settings at the end of the program (section 60).
One final note. In an AutoLISP program, the parenthesis that closes a loop or other long expression usually occupies a whole line by itself. This is done so that the parenthesis can line up directly below its matching opening parenthesis and is a good format when you are first learning AutoLISP. But it is also a waste of "vertical space" when you are editing the program. In order to get more of the code on screen at one time, the closing parenthesis can be moved from its usual location to the end of the previous line. This is illustrated below at the end of sections 30, 40, and 50.
------ marker ------ beginning of working program ------ try it out ------
;| TABLE
Copyright © 1998 Ronald W. Leigh
Draws a table with any number of
equal spaced columns and rows
Variables:
colwid Column width
cols Number of columns
head Heading
len Length of hor. then ver. lines in table
obm Old blipmode
oom Old osnap mode
rowhei Row height
rows Number of rows
sp Start pt. for ver. lines, hor.
lines, text
ts Current text style
tshei Height of current text style
ulc Upper left corner of table
|;
;10====PROGRAM SETUP
(defun c:table (/ colwid cols head len obm oom
rowhei rows sp ts tshei ulc)
(setq obm (getvar "blipmode") oom (getvar "osmode"))
(graphscr)
;20====GET TABLE LOCATION, COLUMNS & ROWS, HEADING
(setvar "blipmode" 1)
(setvar "osmode" 0)
(initget 1)
(setq ulc (getpoint "\nUpper left corner of table: "))
(initget 7)
(setq cols (getint "\nNumber of columns: "))
(initget 7)
(setq colwid (getreal "\nWidth of each column: "))
(initget 7)
(setq rows (getint "\nNumber of rows: "))
(initget 7)
(setq rowhei (getreal "\nHeight of each row: "))
(setq head (getstring 1 "\nHeading: "))
;30====DRAW VERTICAL LINES
(setvar "blipmode" 0)
(setq sp ulc len (* rows rowhei))
(repeat (1+ cols)
(command ".line" sp (polar sp (* 1.5 pi) len) "")
(setq sp (polar sp 0 colwid)))
;40====DRAW HORIZONTAL LINES
(setq sp ulc len (* cols colwid))
(repeat (1+ rows)
(command ".line" sp (polar sp 0 len) "")
(setq sp (polar sp (* 1.5 pi) rowhei)))
;50====DRAW TEXT
(setq ts (getvar "textstyle"))
(setq tshei (cdr (assoc 40 (tblsearch "style" ts))))
(if (> tshei 0) (setq rowhei (* 2 tshei)))
(setq sp (polar ulc 0 (/ len 2)))
(setq sp (polar sp (* 0.5 pi) (/ rowhei 2)))
(if (> tshei 0)
(command ".text" "M" sp 0 head)
(command ".text" "M" sp (/ rowhei 2) 0 head))
;60====RESET
(setvar "blipmode" obm)
(setvar "osmode" oom)
(princ)
)
-------- marker
-------- end of working program -------- try it out --------