Author Topic: Feeding a string to the GetXXX functions  (Read 4934 times)

0 Members and 1 Guest are viewing this topic.

zoltan

  • Guest
Feeding a string to the GetXXX functions
« on: February 18, 2006, 09:25:06 AM »
Is it possible to take a string and feed it to one of the Get functions (like GetPoint) and have it return a value as if the user typed the string?

It's a long shot, I know.

A while ago, i had figured out a way to write characters to the command prompt while a Get function was active, but I did'nt save the code and I can't remember how I did it.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Feeding a string to the GetXXX functions
« Reply #1 on: February 18, 2006, 09:38:41 AM »
If I understand you correctly you'd actually have to fake your own getpoint function using grread. Not impossible. Somewhere I wrote a function to mimic the c/c++ getc (get character with echo) using grread, and another to mask password entry. I'll see if I can find them, they may give you ideas.
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

zoltan

  • Guest
Re: Feeding a string to the GetXXX functions
« Reply #2 on: February 18, 2006, 09:45:48 AM »
I GOT IT!!

I don't know why this works, but it works:
Code: [Select]
(VLA-SendCommand (VLA-Get-ActiveDocument (VLAX-Get-Acad-Object)) (StrCat "10,10" (VL-List->String (List 13))))
(GetPoint)

I would still like to see your code MP.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Feeding a string to the GetXXX functions
« Reply #3 on: February 18, 2006, 10:26:26 AM »
Sorry Zoltan. Two things: I misunderstood what you wanted to do and using using grread in the context of getpoint would be for naught because you can't reasonably replicate object snap behavior (nentsel has limited use, you'd have to code all your own tangent to, perp to, quad of, mid of behaviors etc.). While I could post the code I referred to it's really not germane and would just put this thread further o/t. Sorry for the distraction!

/ slink
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Peter Jamtgaard

  • Guest
Re: Feeding a string to the GetXXX functions
« Reply #4 on: February 19, 2006, 01:58:04 PM »
To type characters in to a getpoint function look at the initget function.

LUCAS

  • Newt
  • Posts: 32
Re: Feeding a string to the GetXXX functions
« Reply #5 on: February 19, 2006, 11:49:04 PM »
(initget 128)
(getpoint)

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Feeding a string to the GetXXX functions
« Reply #6 on: February 20, 2006, 02:54:14 AM »
Hi ZOltan .. that name sounds familiar, yes ?

I had a similar difficulty as Michael determining the question, but ...

Have a play with something like this.
Pick a point,
or U returns "Undo"
otherwise return literally whatever is typed.

Code: [Select]
(setq p0 (getvar "LASTPOINT"))

(initget "Undo _Undo" (+ 32 128))
(setq p1 (getpoint p0 "\nSpecify an option [Undo] or type 'ANYTHING', or <Endpoint of line>: "))
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Feeding a string to the GetXXX functions
« Reply #7 on: February 20, 2006, 03:20:20 AM »
.. or for a working example ..
in the Express Folder
Code: [Select]
;;;    BREAKL.LSP - Written by Randy Kintzley
;;;    Copyright © 1999 by Autodesk, Inc.

;;...... <snip>

(while (not flag)
  (initget "Block Size Extension eXit" 128)
  (setq p1
         (getpoint
           "\nSpecify first point for breakline or [Block/Size/Extension]: "
         )
  )                                                     
  (cond
    ((equal p1 "Block") (bns_breakline_getblkname nil))
    ((equal p1 "Size") (bns_breakline_getblksize))
    ((equal p1 "Extension") (bns_breakline_getblkexe))
    ((equal (type p1) 'list) (setq flag t))
    (t
     (princ "\nInvalid. Expects a point or Block, Size, or Extension."
     )
    )
  )
)

;;...... <snip>
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

sinc

  • Guest
Re: Feeding a string to the GetXXX functions
« Reply #8 on: February 20, 2006, 12:31:10 PM »
I GOT IT!!

I don't know why this works, but it works:
Code: [Select]
(VLA-SendCommand (VLA-Get-ActiveDocument (VLAX-Get-Acad-Object)) (StrCat "10,10" (VL-List->String (List 13))))
(GetPoint)

It looks like you are sending a command to the command line parser.  Since a current command (your Lisp routine) is already active, that command sits there in the queue waiting for a chance to execute.  Except when your (GetPoint) function is called, it asks for user input.  At this point, it looks like it pulls in the data you added to the command queue, and uses it as user input for the (GetPoint) function.

So, it looks like a very roundabout way of getting a point.  Why don't you just create the point directly?

The Autocad Help even warns about what you are doing:
Quote
You should never use this method to issue a command for which there is an ActiveX method available. For example, do not use SendCommand "VBALOAD ". Instead, use the LoadDVB method.

zoltan

  • Guest
Re: Feeding a string to the GetXXX functions
« Reply #9 on: February 20, 2006, 10:50:37 PM »
Exactly... The SendCommand is waiting for a place to put the charecters and plugs it into the GetPoint command.

The idea is that I want to pass a string to a GetPoint function as if the user had typed it and have it return a value.  But without having the GetPoint function pause for the user to type anything.

It's kind of a long story of why I'm doing this.  I creating a set of generic functions for dynamic dragging in Lisp using GrRead which accept keyboard entry just like the GetXXX functions.  The only thing they don't do is allow OSNAPs.

I will post an example when I put one together.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Feeding a string to the GetXXX functions
« Reply #10 on: February 21, 2006, 10:52:53 AM »
OK, My interest is piqued ..
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

zoltan

  • Guest
Re: Feeding a string to the GetXXX functions
« Reply #11 on: February 21, 2006, 10:40:05 PM »
Kerry, you probably recognize my name from the other programing forum.

Ok...I just threw this together, so it is kinda rough.

This is a simple test function that wraps two of my 8 dynamic dragging functions in generic function that allows the GrRead loop in the dynamic function to accept a keyboard input from the user an pretends to be the GetXXX function you specify and returns the data as if the user typed it into the Get function.  InitGet is called before the Get function so Keywords are honored without having to write code to handle it.

I have to use the sneaky SendCommand trick to feed a string that the user is building by trapping the keyboard events from the GrRead loop to the specified Get function so that it acts the same as the get function.  The user is not actually typing into the Get function, so the program is not paused for user input.  This allows the dynamic dragging function to keep looping and pumping a point to the modifier function.

Each of my dynamic draging functions accept some optional boundaries and a quoted symbol of a function that accepts a point or real as its only argument and does something such as draw vectors or modify objects.  While the cursor is moving, the dynaic draging function is looping and pumping the modifier function with the cursur position.  If the the user clicks, right-clicks, or types, the dynamic function returns the last result of the modifier function and the last result of the GrRead function back to the DragInput function that processes the input.  The result determins what happens next.  If the user pushed a keystroke, the ASCII character is stored in a list and concatenated to the end of the prompt to create the appearance of typing at the Get prompt.  If the user right-clicks or hits enter or space and there are characters in the list, the string is fed to the specified GetXXX function and the return is appended to the return of the dynamic dragging function and handed to the main calling funcion.  If there is no string when the user hits enter, then the function returns nil and the calling function processes the default option.

Let's break it down inside-out style  :mrgreen: :
Code: [Select]
;; Drag on screen to input a point with the mouse
;; given an upper bound and lower bound for X, both for Y and the symbol of fuction
;; that takes a point as an argument. FLAG is the curtype flag given to GrRead.
;; Function returns a list whose first element is the last result of the given
;; function and the second element is the last result of the GrRead function.
(Defun DragXYPoint ( LBX UBX LBY UBY FUNK FLAG / elev mp xp yp )
 (SetQ elev (GetVar "ELEVATION") )
 (List
  (While (= (Car (SetQ mp (GrRead T 5 FLAG))) 5 )
   (SetQ xp (Car (Cadr mp)) )
   (SetQ yp (Cadr (Cadr mp)) )
   (Apply FUNK (List (List (Cond
                            ((If LBX
                              (< xp LBX )
                              nil
                             )
                             LBX
                            )
                            ((If UBX
                              (> xp UBX )
                              nil
                             )
                             UBX
                            )
                            (T
                             xp
                            )
                           )
                           (Cond
                            ((If LBY
                              (< yp LBY )
                              nil
                             )
                             LBY
                            )
                            ((If UBY
                              (> yp UBY )
                              nil
                             )
                             UBY
                            )
                            (T
                             yp
                            )
                           )
                           elev
                     )
               )
   )
  )
  mp
 )
)

;; Drag on screen to input a distance from a BASE point
;; given an upper bound and lower bound and the symbol of fuction
;; that takes a real as an argument. Function returns a list whose first
;; element is the last result of the given function and the second element is the
;; last result of the GrRead function.
(Defun DragDistFromPoint ( BASE LB UB FUNK FLAG / mp dist )
 (List
  (While (= (Car (SetQ mp (GrRead T 5 FLAG))) 5 )
   (SetQ dist (Distance BASE (Cadr mp)) )
   (Apply FUNK (List (Cond
                      ((If LB
                        (< dist LB )
                        nil
                       )
                       (prin1)
                       LB
                      )
                      ((If UB
                        (> dist UB )
                        nil
                       )
                       (Prin1)
                       UB
                      )
                      (T
                       dist
                      )
                     )
               )
   )
  )
  mp
 )
)
Here are two of the dynamic draging functions.  The first, is simply inputing a coordinate location on the screen.  It optionally accepts upper and lower bounds for X and Y that the point cannot go outside.  FUNK is a quoted symbol naming the function that will process the point and FLAG is the cursor type flag given for the GrRead function.  The function keeps the tracking GrRead in a loop and feeds a point to FUNK as long as the it returns a Car of 5 (cursor tracking).  Any other input is handed back to the DragInput function.

The second dynamic dragging function gets a real number distance between the cursur and a base point (like a radius).  The upper and lower bounds are minimums and maximums and everything is the same.

Code: [Select]

 (Defun Drag_Point ( POINT / )
  (SetQ entCircle (EntMod (Subst (Cons 10 (Trans POINT 1 0)) (Assoc 10 entCircle) entCircle)) )
  POINT
 )

 (Defun Drag_Rad ( RAD )
  (SetQ entCircle (EntMod (SubSt (Cons 40 RAD) (Assoc 40 entCircle) entCircle)) )
  RAD
 )
These are the modifier function that take the input from the graging functions and modifies the circle entity.  They must return something usefull so the draging function can return it.

Code: [Select]
;;wraps a dynamic draging function in a user interface to allow keyboard entry which if fed to a GetXXX function
;;MSG = Prompt displayed at the Command line.  Omit the \n and \r
;;DRAGFUNK = a quoted list containg a dynamic drag function and all of its parameters
;;INPUTFUNK = a quoted symbol of a GetXXX function to feed input to
;;pntOPTIONAL = optional point for the GetXXX function before the Prompt, can be nil
;;lstINITGET = a quoted list of parameters for the InitGet function, can be nil
;;ex.
;; (DragInput
;;  "Pick a Point: "
;;  '(DragXYPoint (Car LBound) (Car UBound) (Cadr LBound) (Cadr UBound) 'Drag_Point 0)
;;  'GetPoint
;;  nil
;;  '("Test")
;; )
;;returns a list with the result of the INPUTFUNK appended to the end of the result of the DRAGFUNK
(Defun DragInput ( MSG DRAGFUNK INPUTFUNK pntOPTIONAL lstINITGET / lstChars bLoop lstDragReturn FunkReturn return )
 (SetQ lstChars '()
       bLoop T
 )
 (PrinC "\n" )
 (While bLoop
  (PrinC (StrCat "\r" MSG (VL-List->String lstChars)) )
  (SetQ lstDragReturn (Eval DRAGFUNK) )

  ;(PrinC (Cadr lstDragReturn) )
 
  (Cond
   ((= (Caadr lstDragReturn) 3) ;left-click
    (If lstChars
     (SetQ bLoop T )
     (SetQ return lstDragReturn
           bLoop nil
     )
    )
   )
   ((Or (= (Caadr lstDragReturn) 25) ;right-click context menu
        (= (Caadr lstDragReturn) 12) ;right-click
        (And (= (Caadr lstDragReturn) 2) ;keystroke
             (Or (= (Cadadr lstDragReturn) 13) ;space
                 (= (Cadadr lstDragReturn) 32 ) ;enter
             )
        )
    )
    (If lstChars
     (ProgN
      (If lstINITGET
       (Apply 'InitGet lstINITGET )
      )
      (If (SetQ FunkReturn (String->GetFunk
                            (VL-List->String lstChars )
                            INPUTFUNK
                            (If pntOPTIONAL
                             (List pntOPTIONAL (StrCat "\r" MSG) )
                             (List (StrCat "\r" MSG) )
                            )
                           )
          )
       (SetQ bLoop nil
             return (Append lstDragReturn (List FunkReturn))
       )
       (SetQ lstChars '()
             bLoop T
       )
      )
     )
     (SetQ return nil
           bLoop nil
     )
    )
   )
   ((= (Caadr lstDragReturn) 2) ;keystroke
    (Cond
     ((= (Cadadr lstDragReturn) 8) ;backspace
      (SetQ lstChars (Reverse (Cdr (Reverse lstChars))) )
      (PrinC (StrCat "\r" MSG (VL-List->String lstChars) " ") )
     )
     (T ;all characters
      (SetQ lstChars (Reverse (Cons (Cadadr lstDragReturn) (Reverse lstChars))) )
     )
    )
   )
  )
 )

 return
)
This is the DragInput function that wraps the dragging function and allows keyboard entry.  Right now it is a bit ugly, but i still need to streamline it.

Code: [Select]
;;feeds a string to a GetXXX function
;;the string cannot be blank or contain spaces
(Defun String->GetFunk ( STR GETFUNK lstFUNKINPUT / return2 )
 (VLA-SendCommand (VLA-Get-ActiveDocument (VLAX-Get-Acad-Object)) (StrCat STR (VL-List->String (List 13))) ) ;sends input
 (VLA-SendCommand (VLA-Get-ActiveDocument (VLAX-Get-Acad-Object)) (VL-List->String (List 13)) ) ;clears invalid input
 (SetQ return2 (Apply GETFUNK lstFUNKINPUT) )
 (If return2
  (GetString ) ;catches the CR
 )

 return2
)
This tricky little tidbit takes a string and stuffes it into a GetXXX function and returns the value back.  it has to send another carraige return to break out of the unser input if the string is junk.  If the Get function returns something, a GetString function catches the second CR so it does'nt cause trouble.  It's a messy way to do it, and the second CR casues an extra line after the error prompt, but I can't think of any other way.

Code: [Select]
(Defun C:TestCirc ( / entCircle pntLastPoint bCircLoop lstPointReturn dLastRad pntBase lstRadReturn )
 (SetQ entCircle  (EntGet (Car (EntSel "\nPick circle: "))) )
 (SetQ pntLastPoint (Cdr (Assoc 10 entCircle)) )
 (SetVar "LASTPOINT" pntLastPoint )
 
 (SetQ bCircLoop T )
 (While bCircLoop
  (SetQ lstPointReturn (DragInput
                        (StrCat "Specify center point for circle or [Radius]"
                                " <"
                                (RtoS (Car pntLastPoint) (GetVar "LUNITS") (GetVar "LUPREC") )
                                ","
                                (RtoS (Cadr pntLastPoint) (GetVar "LUNITS") (GetVar "LUPREC") )
                                ">"
                                ": "
                        )
                        '(DragXYPoint nil nil nil nil 'Drag_Point 0 )
                        'GetPoint
                        nil
                        '("Radius")
                       )
  )
  (Cond
   ((= (Caddr lstPointReturn) "Radius")
    (SetQ dLastRad (Cdr (Assoc 40 entCircle)) )
    (SetQ pntBase (Car lstPointReturn) )
    (SetQ lstRadReturn (DragInput
                        (StrCat "Specify radius of circle "
                                "<"
                                (RtoS dLastRad (GetVar "LUNITS") (GetVar "LUPREC"))
                                ">"
                                ": "
                        )
                        '(DragDistFromPoint pntBase nil nil 'Drag_Rad 0 )
                        'GetDist
                        (Car lstPointReturn )
                        '(6)
                       )
    )
    (Cond
     ((Caddr lstRadReturn) ;user typed a radius
      (Drag_Rad (Caddr lstRadReturn) )
     )
     ((Null lstRadReturn) ;user accepted default
      (Drag_Rad dLastRad )
     )
     (T ;user picked a radius
      (Drag_Rad (Car lstRadReturn) )
     )
    )
   )
   ((Caddr lstPointReturn) ;user typed a point
    (Drag_Point (Caddr lstPointReturn) )
    (SetQ bCircLoop nil )
   )
   ((Null lstPointReturn) ;user accepted default
    (Drag_Point pntLastPoint )
    (SetQ bCircLoop nil )
   )
   (T ;user picked a point
    (Drag_Point (Car lstPointReturn) )
    (SetQ bCircLoop nil )
   )
  )
 )

 (TerPri )
 (Prin1 )
)
This is the top level test command.  it asks you to pick a circle and you can drag it around the screen and pick a point to place it some where. You can type a coordinate of a point to place it, or enter a relative point (like @10,10) to offset it from its original location (that's what the (SetVar "LASTPOINT" ...) is for).  You can also issue the Radius keyword and drag a new radius for the circle, or type one at the prompt.

The only thing I don't like, it that the GetDistance function needs the optional first point to handle if the user types a coordinate.  If it were not there, the function would rubber-band and ask for the second point, which the second CR in String->GetFunk would cancel and the interface would appear to act strange.

This is essentially my answere to not being able to get Paul Marshall's MouseTracker re-compiled for 2006 and working properly :cry:.

Play with it, make it do neat things, try to break it.  I recomend that you read this post, slowelly, load the code, run it, step through it a few times, and then read this post again.