NP CAD Page | Articles | Russian | Download

Toolbar Dances

(from the book "AutoLISP and Visual LISP Inside AutoCAD")

Toolbars life is similar to the life of menus (e.g. popup menus) but it is rather difficult to work with them from LISP programs because ActiveX tools are to be used.
This article shows an example of solving in AutoCAD 2006/2007 the following tasks:

creation of a new toolbar in memory;
adding buttons into toolbar;
setting button pictures;
developing button functions (adding macro and helpstring);
moving toolbar on the screen;
erasing toolbar.

In the next source code a toolbar will be created and filled in. Then it will move on the screen with a required speed and a required path. At the end of "dance" toolbar will be deleted. The algorithm for AutoCAD versions different from 2006/2007 is similar to described one but some changes are to be made (corresponding comments will be given).
In listing 1 source code for the cr_tb function is shown. This function is designed for creation of a new toolbar in the selected menu group. During its execution it is necessary to check toolbar name validity (two toolbars with the same names in one group are impossible).

Listing 1. File cr_tb.lsp
; Appendix 5\cr_tb.lsp
; N.Poleshchuk, 2006
; Based on the book: N.Poleshchuk, P.Loskutov
;"AutoLISP and Visual LISP Inside AutoCAD"
; ("BHV-Petersburg" Publishing House, 2006)
; http://poleshchuk.spb.ru/cad/eng.html

(defun cr_tb (g_name t_name l_names l_helps l_macros l_icons cx cy nrows / wbOK mgs mg tbs tb i tbitem)
(vl-load-com)
(setq mgs (vla-get-MenuGroups (vlax-get-acad-object)))
(if (= (type g_name) 'STR)

(setq wbOK (if mgs T nil)))
(if wbOK
(progn
; If there is no such group: Automation Error. Invalid argument XXX in Item
(setq mg (vl-catch-all-apply 'vla-Item (list mgs g_name)))
(if (/= (type mg) 'VLA-OBJECT)
(progn
(setq wbOK nil)
(princ "\nGroup name is invalid. ")
);progn
);if
);progn
);if
; Group name is valid
; Check if there is already toolbar with the same name
(if wbOK
(progn
(if (= (type t_name) 'STR)
(progn
(setq tbs (vla-get-Toolbars mg))
; If there is no such toolbar: Automation Error. Invalid argument XXX in Item
(setq tb (vl-catch-all-apply 'vla-Item (list tbs t_name)))
(if (not (vl-catch-all-error-p tb))
(progn
(setq wbOK nil); name already exists
(princ "\nToolbar name is already used. ")
);progn
);if
);progn
(progn
(setq wbOK nil)
(princ "\nToolbar name is invalid. ")
);progn
);if
);progn
);if
; Toolbar name is valid. We create new toolbar
(if wbOK
(progn
(setq tb (vla-Add tbs t_name))
(if tb
(progn
; Add buttons and icon pictures
; It is necessary to add check for list arguments
(setq i -1)
(repeat (length l_names)
(setq i (1+ i))
(setq tbitem (vla-AddToolbarButton tb i (nth i l_names) (nth i l_helps) (nth i l_macros))); button i
(vla-SetBitmaps tbitem (nth i l_icons) (nth i l_icons))
);repeat
; Toolbar coordinates and number of rows
(vla-Float tb cx cy nrows)
(princ (strcat "\nToolbar " t_name " is created in the group " g_name ". "))
(setq g_tb tb); save in global variable for future use
(vlr-beep-reaction); beep sound
);progn
(princ (strcat "\nToolbar " t_name " already exists in the group " g_name ". "))
);if
);progn
);if
; Release memory for unnecessary VLA objects
(mapcar (function (lambda (x) (if (and x (not (vlax-object-released-p x))) (vlax-release-object x)))) (list mgs mg tbs tbitem))
(princ)
);defun cr_tb

The cr_tb function has the following arguments:

g_name - menu group name to add a toolbar (it should be a string containing name of a loaded group). For example: "ACAD";
t_name - name of toolbar to be created (it should be different from the names of toolbars from the group named g_name). For example: "Dancing Queen";
l_names - string list with button names (they appear in the yellow tooltip windows when you move cursor over the buttons). For example: '("Dance1" "Dance2" "Dance3" "Dance4" "Dance5");
l_helps - string list with helpstrings apearing in the status line when cursor is over the button. For example: '("Tooltip 1" "Tooltip 2" "Tooltip 3" "Tooltip 4" "Tooltip 5");
l_macros - string list with macros to be run after button click. For example: '("(alert\"New\") " "(alert\"Open\") " "(alert\"Save\") " "(alert\"SaveAs\") " "(alert\"Print\") "). Each macro ends with a space (Enter analogue);
l_icons - string list with icon resource names linked to buttons. Resources should be AutoCAD icon resources or bmp files. For example: '("RCDATA_16_NEW" "RCDATA_16_OPEN" "RCDATA_16_SAVE" "RCDATA_16_SAVE" "RCDATA_16_PRINT") - these are resource names for the New, Open, Save and Print buttons form the Standard toolbar. 2004 and 2005 versions use the same names. But 2002 version use prefix ICON_ instead of RCDATA_;
cx - horizontal coordinate of the toolbar start position (non-negative number);
cy - vertical coordinate of the toolbar start position (non-negative number);
nrows number of button rows (integer from 1 to total number of buttons in the toolbar).
First of all cr_tb checks name validity for menu group to insert toolbar. Group name is transferred through the first argument. Program checks its type (string) and then checks menu group existence (it should be a member of MenuGroups collection). While verifying an important vl-catch-all-apply function is used. If error break arises (there is no group) then the function returns not group VLA object but object with VL-CATCH-ALL-APPLY-ERROR type.
The following construction is applied for checking:
(setq tb (vl-catch-all-apply 'vla-Item (list mgs g_name)))
After evaluating this expression we can analyze result type without exiting program.
Similar check is done for t_name argument that is to be a string. But here vl-catch-all-apply function is used in opposite manner: if there is no error then Toolbars collection already has a toolbar named t_name and we must exclude this!
When group and toolbar names are suitable, program goes to toolbar creation. First of all Add method generates VLA object of an empty toolbar:
(setq tb (vla-Add tbs t_name))
Then with the help of AddToolbarButton method we add buttons. Number of buttons is equal to l_names list length (it should be mentioned that to shorten program source code we missed check for length of l_helps, l_macros and l_icons lists; if thes lists are shorted then program wil not work; moreover you should test that all the list members are strings).
Next method SetBitmaps is used to attach pictures to buttons. In this example we use icons of the Standard toolbar. Equal names are taken for small and large buttons (system admits this). As a result a toolbar must appear on the screen (pic.1 shows Dancing Queen toolbar with five buttons).


Pic.1. Dancing Queen toolbar

VLA object of the built toolbar is saved in a global variable g_tb to use in other functions. Then we delete the rest VLA objects with vlax-release-object function and free their memory.
Next move_tb function must move the toolbar from one screen point to another in required number of steps (too quick movement is unintersting). Function source code is in listing 2.

Listing 2. File move_tb.lsp
; Appendix 5\move_tb.lsp
; N.Poleshchuk, 2006
; Based on the book: N.Poleshchuk, P.Loskutov
;"AutoLISP and Visual LISP Inside AutoCAD"
; ("BHV-Petersburg" Publishing House, 2006)
; http://poleshchuk.spb.ru/cad/eng.html

(defun move_tb (tb x1 y1 x2 y2 ntime / i x y)
(vla-Float tb x1 y1 1)
(setq i 0 x x1 y y1)
(repeat ntime

(setq i (1+ i) x (+ x1 (/ (/ (* i (- x2 x1)) ntime))))
(setq y (+ y1 (/ (/ (* i (- y2 y1)) ntime))))
(vla-put-Left tb x)
(vla-put-Top tb y)
);repeat
(vlr-beep-reaction)
);defun move_tb

The move_tb function converts toolbar into one row of buttons and recalculates toolbar screen position. The ntime argument controls the time for toolbar moving between edge points. At the end of the path beep sound is generated by vlr-beep-reaction function. As background window does not restore in time we see toolbar track.
Next function is called dance_tb (listing 3) pushes toolbar along the path defined by the list of points.

Listing 3. File dance_tb.lsp
; Appendix 5\dance_tb.lsp
; N.Poleshchuk, 2006
; Based on the book: N.Poleshchuk, P.Loskutov
;"AutoLISP and Visual LISP Inside AutoCAD"
; ("BHV-Petersburg" Publishing House, 2006)
; http://poleshchuk.spb.ru/cad/eng.html

(defun dance_tb (tb plist ntime / wbOK p x0 y0 x1 y1)
(if (and (listp plist)(> (vl-list-length plist) 0))

(progn
(setq plist (vl-remove-if-not 'test plist))
(setq x0 (vla-get-Left tb) y0 (vla-get-Top tb))
(while plist
(setq x1 (caar plist) y1 (cadar plist))
(move_tb tb x0 y0 x1 y1 ntime)
(setq x0 x1 y0 y1 plist (cdr plist))
);while plist
);progn
);if
);defun dance_tb
; Checking whether list has 2 elements and they both are numbers (numberp)
; Additional function
(defun test (p / wbOK)
(setq wbOK (if (and (listp p) (= (vl-list-length p) 2)) T nil))
(if wbOK
(setq wbOK (and (numberp (car p)) (numberp (cadr p))))
);if
);defun test (returns T only for valid list)

Function dance_tb checks list named plist first and deletes improper elements (that are not 2D points). Afterwards move_tb function is called many times for movement.
To finish we will write a sample program that runs the whole dancing from begin to end (listing 4).

Listing 4. File show.lsp
; Appendix 5\show.lsp
; New toolbar parameters
(setq gn "ACAD" tn "Dancing Queen")
(setq ln (list "Dance1" "Dance2" "Dance3" "Dance4" "Dance5"))
(setq lh (list "Tooltip 1" "Tooltip 2" "Tooltip 3" "Tooltip 4" "Tooltip 5"))
(setq lm (list "(alert\"New\") " "(alert\"Open\") " "(alert\"Save\") " "(alert\"SaveAs\") " "(alert\"Print\") "))
(setq li (list "RCDATA_16_NEW" "RCDATA_16_OPEN" "RCDATA_16_SAVE" "RCDATA_16_SAVE" "RCDATA_16_PRINT"))
(setq k1 200 k2 150 kr 1)
(cr_tb gn tn ln lh lm li k1 k2 kr)
;;; Sample dancing
(dance_tb g_tb (list '(100 100) '(500 200) '(0 400)) 10000)
;;; Delete dancer
(vla-Delete g_tb)
(vlax-release-object g_tb)
(setq g_tb nil)
(princ "\nToolbar is removed. Concert is over. ")
(princ)

In the pic.2 "dancing moment" is shown. There is track left by toolbar. And you can see curious "imaginary" toolbars below (it is difficult to explain them).


Pic.2. Dancing toolbar

One may leave new toolbar unremoved: it disappears itself after exiting AutoCAD session. Toolbar exists only in computer memory (we can say, in our imagination...). But it works fine.
If user permanently needs created toolbars he is recommended not to create them dynamically but to load them with CUI file in 2006/2007 or with menu file in previous versions.


NP CAD Page | Articles | Russian | Download