Hello everyone, I am attempting to tackle a new project.
I'm writing a small routine to enable layer toggles based off of a few characters inputted by a user, such as:
Laymod "IFC" thaw
would be the user execution command, and within that I want this program to search for any matches within the list of returned layers in the drawing to what's in the double-quotes, in the example above, it would return any or all layers that have the string "IFC" within them.
I've been able to construct the layer list, and have set vars for the layers to be an argument of the subfunction required to toggle the layers.
What I need some assistance with is the string matching portion of this routine, that would search the table of layers and return any matches to the user input....if anyone would assist me in this i would be grateful.
Thanks and cheeeeeeers!
Solved! Go to Solution.
Solved by Kent1Cooper. Go to Solution.
@bhull1985 wrote:What I need some assistance with is the string matching portion of this routine, that would search the table of layers and return any matches to the user input
Look into the tblsearch function.
Thanks Lee, I will look into it!
I was wondering on an unrelated note if you had received the email I sent to you yesterday?
Just simply inquiring as to if you've written a specific program or not because I was not able to locate it on your website....yet I would think you've done something similar, so was just hoping to find out.
Anyhow, thanks for the hint with this one, i'll study up!
@bhull1985 wrote:
....
I'm writing a small routine to enable layer toggles based off of a few characters inputted by a user, such as:
Laymod "IFC" thaw
would be the user execution command, and within that I want this program to search for any matches within the list of returned layers in the drawing to what's in the double-quotes, in the example above, it would return any or all layers that have the string "IFC" within them.
....
If you really mean toggle [that is, switch from one state of a possible pair, whichever it is, to the opposite], it's more complicated, but your sample User input suggests maybe you mean to switch to a specified state, regardless of which of the possible pair of states they start in. If that User input means you want to thaw all Layers containing "IFC" in their names, rather than toggle their freeze/thaw state, you don't need to make a list, but can do something as simple as this:
(defun laymod (substr option)
(command "_.layer" option (strcat "*" substr "*") "")
)
Usage:
In your example:
(laymod "IFC" "Thaw")
or even just
(laymod "IFC" "T")
Note that the option argument needs to be in double-quotes, in addition the Layer-name substring as in your example. And as a function with arguments, the whole thing needs to be in parentheses, but:
If you want it as a Command, with User inputs in answer to prompts rather than as arguments to a function:
(defun C:LAYMOD (/ substr option)
(setq
substr (getstring "\nPortion of Layer name(s) to apply option to: ")
option (getstring "\nLayer option to apply to them: ")
); setq
(command "_.layer" option (strcat "*" substr "*") "")
); defun
And then, in answer to the prompts, the User wouldn't include the double-quotes around the substring or option.
You could also use (initget) and (getkword) to force the User to supply a valid Layer option [the above will have trouble if they type something wrong].
@bhull1985 wrote:
....it would return any or all layers that have the string "IFC" within them.
@Lee_Mac wrote:
....Look into the tblsearch function
Unfortunately, (tblsearch) doesn't like wildcards, but needs a fully spelled-out individual [in this case] Layer name. It can't find more than one Layer, nor even a single Layer if only one matches, given only a portion of the Layer name(s).
Great, thanks again Kent.
I'll attempt my routine using these instead, and see how it works.
Much appreciated!
And ah, alright. I wasn't intent on using wcmatch, just thought that it may be the best option for a user to type a few characters and have it match those few characters with any layers containing those characters from a list of layers obtained earlier in the routine.
@bhull1985 wrote:
Great, thanks again Kent.
I'll attempt my routine using these instead, and see how it works.
Much appreciated!
And ah, alright. I wasn't intent on using wcmatch, just thought that it may be the best option for a user to type a few characters and have it match those few characters with any layers containing those characters from a list of layers obtained earlier in the routine.
You're welcome. The Layer command itself will perform the (wcmatch)-like operation on the Layer collection, without the need for you to make a list of them, in the place where it's asking for Layer name(s), where [unlike (tblsearch)] it can work with (wcmatch)-style wildcards.
Okay, and with the quickprop hover over item information boxes in autocad that show the layer of the item being hovered, that will work great. Thanks for the zillionth time 🙂
Alright I'm getting a strange error message,
one that I haven't seen before.
Perhaps someone else has??
And could tell me why...
I'm having a bit of difficulty in establishing the variables in a manner that will have the program display a list of the layers in the drawing (table "layer") within the code to do that, calling a sub.
That's step 1, then I want the users to be able to simply issue on their command line the following:
Laymod "Layername-From-list-or-portion-of-layername-from-list" State
where Laymod is the command to invoke the routine, the quoted information is the layer to be modified , accepting full or partial layer name from the given list, and then state is the layers property to be modified.
I've got the subroutines all in it and am just having a hard time in establishing a way to inform the user to only enter those 3 words as their terms, and having it set the vars correctly based from that
@bhull1985 wrote:
Alright I'm getting a strange error message,
one that I haven't seen before.
....
then I want the users to be able to simply issue on their command line the following:
Laymod "Layername-From-list-or-portion-of-layername-from-list" State
....
Posting the error message would help.
A command defined by way of
(defun C:Something ...
cannot contain arguments [entries before the backslash in the parentheses following the command name].
If you want it as a command the User can type in as a command name, remove those [it looks like the first is not used except inside sub-routines anyway, and the second is also in the localized variables list after the parentheses, which I imagine would be a conflict].
If you want it as a function with arguments, then remove the C:, and it has to be used with those three terms in parentheses, and the last one would also need to be in double-quotes [see my first Reply on this thread].
Oh duh, my bad
was getting rushed away to complete another task 😛
Here's the error msg:
Command: (LOAD "Y:/bhull/_layermod.lsp") too few arguments in SETQ: (SETQ
LSTATE (GETKWORD "\nChoose layer control:") (COND ((= LSTATE "Freeze") (FRZTOG
LAYOBJ) (COMMAND "regen")) ((= LSTATE "Thaw") (THAWTOG LAYOBJ) (COMMAND
"regen")) ((= LSTATE "On") (LAYERONOFF LAYOBJ T LAYOBJ) (COMMAND "regen")) ((=
LSTATE "Off") (LAYERONOFF LAYOBJ nil) (COMMAND "regen")) ((= LSTATE "Lock")
(LOCKTOG LAYOBJ) (COMMAND "regen")) ((= LSTATE "Unlock") (UNLOCKTOG LAYOBJ)
(COMMAND "regen"))))
And yeah, I want it to be however is required for the users to call the functions by typing
Laymod "layer" On
Laymod "layer" freeze
...etc
I was thinking that I could require arguments in the command to call the function, but apparently this is not true?
Hrm...how do you make a command-line-issued function that uses subfunctions if not able to require arguments in the (defun C:laymod) ? Ugh, i'm missing something here that'll connect these dots together I feel that my routine is pretty close....
@bhull1985 wrote:
....
Here's the error msg:
Command: (LOAD "Y:/bhull/_layermod.lsp") too few arguments in SETQ: (SETQ
LSTATE (GETKWORD "\nChoose layer control:") (COND ....
And yeah, I want it to be however is required for the users to call the functions by typing
Laymod "layer" On
Laymod "layer" freeze
...etc
I was thinking that I could require arguments in the command to call the function, but apparently this is not true?
....
On the error message, you need an additional right parenthesis after the (getkword) function to close the (setq) function, before going on to the (cond) function:
(SETQ LSTATE (GETKWORD "\nChoose layer control:")) (COND ....
That's right, it's not true. A command function can call sub-routines without their being listed as arguments, and may not have listed arguments before the backslash in the parentheses following the command name, but may have only localized variables after the backslash [or nothing, not even the backslash, if there are no localized variables, though even then it still needs the parentheses].
When used as a command in that way, the User's input of the second term in your examples can be without the double-quotes around it [it can have them, but they're superfluous], except when the string they want to put in contains any space(s), in which case the quotes would be needed.
Oh, doh!
Thanks Kent, didn't see that'n and the error message through me off .
I thought it normally mentions parenthesis missing? Oh well.
And yeah, thanks for explaining that some, I'll try and finish it up now
Have a look at the basic AutoCAD commands; how many of them are formatted/take arguments that way? Commands which take additional parameters ask for them one at a time. Since this is the pattern users are used to following with existing commands, then its a good idea to follow it as well.
The upside is, by using a single "LAYMOD" command line function which prompts for arguments you can script in answers in the command macros and scripts e.g. ^C^CLAYMOD;TEST;FREEZE. By using a command line wrapper function to call a non-command function with arguments, you can create single-purpose commands to do the same thing e.g.
(defun c:TEST_FREEZE_COMMAND ( / ) (laymod "TEST" "FREEZE") (princ) ) (defun c:TEST_THAW_COMMAND ( / ) (laymod "TEST" "THAW") (princ) )
Precisely, and that's interesting to read your post because most of it was my last few moments of thought.
Here's what I've got , and it works alright except for the case-sensitive getstring, though I've just noticed it and via strcase should be able to fix it.
It's kinda neat, just a command version to execute the layfrz and layoff and other express tool selection layer modifiers.
And it's handy for us because as you said, this can be used in scripts rather easily
And in fact i was just able to fix the case-sensitivity by changing the following:
(if (setq layobj (getstring "\n Select layer to modify from this list.")) ;;
(progn
(tblsearch "LAYER" "layobj")
(princ "Freeze Thaw On oFF Lock Unlock eXit")
(setq lstate (strcase (getstring "\nChoose layer control:")))
(cond
((= lstate "FREEZE")(FRZTOG layobj)(command "regen")) ;; freeze layer
((= lstate "THAW")(THAWTOG layobj)(command "regen")) ;; thaw layer
((= lstate "ON")(LAYERONOFF layobj t layobj)(command "regen")) ;; on layer
((= lstate "OFF")(LAYERONOFF layobj nil)(command "regen")) ;; off layer
((= lstate "LOCK")(LOCKTOG layobj)(command "regen")) ;; lock layer
((= lstate "UNLOCK")(UNLOCKTOG layobj)(command "regen")) ;; unlock layer
) ;; cond
) ;; setq
) ;; progn
) ;; if
hooray for getting something , even as minor as this, right 🙂
Thought KentCooper,
this line
(command "_.layer" option (strcat "*" substr "*") "")
caused this error, and I am interested to hear your thoughts as to why, when you see this
Error: bad argument type: stringp #<SUBR @000000002bc8e570 SUBSTR>*
And alright, cleaned up. Solved. Thanks guys 🙂
@bhull1985 wrote:
Thought KentCooper,
this line
(command "_.layer" option (strcat "*" substr "*") "")
caused this error, and I am interested to hear your thoughts as to why, when you see this
@Anonymous: bad argument type: stringp #<SUBR @000000002bc8e570 SUBSTR>*
That's probably because I shouldn't have used an AutoLisp function name as a variable name -- didn't think of the fact that it is a function name. I expect if you changed 'substr' to something else, it shouldn't have a problem.
@bhull1985 wrote:
And in fact i was just able to fix the case-sensitivity by changing the following:
(if (setq layobj (getstring "\n Select layer to modify from this list.")) ;;
....(princ "Freeze Thaw On oFF Lock Unlock eXit")
(setq lstate (strcase (getstring "\nChoose layer control:")))
(cond
((= lstate "FREEZE")(FRZTOG layobj)(command "regen")) ;; freeze layer
....
A slightly better way to do that is this:
(initget "Freeze Thaw On oFF Lock Unlock eXit") ;; establish controls
(setq lstate (getkword "\nChoose layer control {Freeze/Thaw/On/oFF/Lock/Unlock/eXit}:"))) ;; get state
(cond ;; which option selected
((= lstate "Freeze") (FRZTOG layobj)(command "regen")) ;; freeze layer
... etc. ...
The advantages of the (initget)/(getkword) approach are:
1) The user doesn't need to enter the entire word as they do for your (getstring) version to work, but just the capitalized key letter(s) [as they're used to doing in typical commands], and the (getkword) function will return the appropriate word in exactly the format it has in the (initget) function [so you need to duplicate that in each test in the (cond) function -- note the case agreement of the green words].
2) It's not case-sensitive. The user can type F or f or Freeze or freeze, or even some more of the word than the key letter(s), in any case combination [e.g. FrE], and it will still return it in the "correct" case combination, and no (strcase) is required.
By the way, if you have people who are accustomed to the Command:-line version of the Layer command, you might consider changing your key letter(s) to agree with those for the options in LAYER: ON and OFF in all-capitals, and LOck with the first two letters capitalized.