|
Allegro CL version 8.0 |
Selecting a Form: why more choices now?
You may notice that there is now a form of type doodler in the list of choices of forms to create. This is because you created a new subclass of dialog of type doodler.
Lisp keeps track of all your subclasses in what is most easily described as a giant table. You will begin to see the classes you create appearing in this list whenever you create a new Form. They will all appear regardless of what project you are working in.
Naming conventions
We recommend that names of windows and controls be mnemonic, begin with a colon, and with the words in each name separated by hyphens. Thus, the name of the curve-dialog window is :curve-dialog, not curvedialog or curve_dialog.
Changes Made in the Inspector: when do they appear on the application?
You will see most of these changes as soon as you move the focus in the inspector, i.e., when you click away from the value you've just changed.
But certain changes are not visible on the form while it is in design mode. For example, youll have to run this form to see that it is no longer resizable. All forms are resizable in design mode no matter what their resizable property is set to; we want you to be able to resize your application while you are designing it.
It is likely to be confusing at first that most changes to the GUI Builder do instantly display in a design-stage form, but some do not. All changes will be evident in the running forms. If you are in doubt about the effect of a change, try evaluating the changed expression, saving your code and running the form.
CLOS permits these sorts of dynamic changes. Whether or not a property change will be visible instantly in the design stage will gradually become obvious to you.
(defclass curve-dialog (dialog) ())
Since you are going to make changes to curve-dialog via events and methods, you need to protect dialog from any changes by changing the class property.
- Click on the single-item-list button on the Components toolbar.
- Click on the curve-dialog form where you want the list control placed.
- Resize it once you've placed it where it should be on the form.
Visual Cues and Quick Key Functionality: the ellipsis points & tilde character
The tilde character (~) and the ellipsis points ( ) are important on this and many other following steps for creating buttons. This is standard application design style; you may choose to implement some other visual flag for these options in making your own applications. Microsoft Word uses an underlined character to indicate a quick key shortcut, for example. Some other applications use a bold or brightly colored character to indicate a shortcut.
- You'll need the tilde for special quick key functionality. Inserting a tilde character (~) into the title of a widget (or the value of a static-text) causes the character that follows the tilde to act as a keyboard shortcut to the widget. That character will be underlined when the label is drawn (the tilde itself will not appear). The user may press the key for that character while holding down the Alt key to move the keyboard focus to that widget, and sometimes to simulate a mouse click on the widget, as with buttons and check-boxes. Tildes may be used in menu-item titles in a similar way.
- The ellipsis points in a button label (or a menu command) indicate more choices will be required of your users to complete that buttons command once they click it.
Evenly Spacing Controls on a Form
You can Drag-select several widgets on a form by selecting the form. Place the mouse cursor just above the top-most widget of interest and to the left of all widgets of interest. Depress the left mouse key and drag the mouse down and to the right until all desired widgets are included in the region formed by the rubber-band outline that appears. Release the mouse button. All selected widgets should have small white boxes in their corners.
Drag-select all the button controls and use the Form | Space Equally command to evenly distribute them over the height of the single-item-list box.
Space Equally distributes the buttons in the distance between the two end buttons. Set each of the end buttons where youd like them to be (at the top and bottom edges of the list) first, then issue the command.
(defclass doodler (non-refreshing-window) ((doodler-curve-dialog :accessor doodler-curve-dialog :initform nil)))
Naming Slots and Accessor Functions
Slot names and their accessor functions should have the same names. This is a convention we use and endorse; it keeps things much simpler.
Style Hint
It is better programming style to add a slot than a global variable in this step, because you could have multiple Doodlers running, each with its own curve dialog. Adding a global variable would create a conflict there.
The Status Bar
Evaluating the defclass awakens Lisp to the new class relationships. You can also see the results of your evaluations and other actions in the Status Bar (the gray band at the bottom of the Project Window directly underneath the Standard Toolbar on the left side).
This is (or will be) the name of the on-change event-handler function for the multi-picture-button (which you placed in the doodler forms toolbar). You are about to write this event handler.
(defun doodler-toolbar-click (widget new-value old-value) (declare (ignore-if-unused widget new-value old-value)) ;; Do the action only when a button is ;; being pressed (not unpressed) (when new-value (let ((doodler (parent (parent widget)))) (case (first new-value) (:curve (show-curve-dialog doodler)) (t nil))) ) (not new-value))
You do this by replacing the whole definition with the above or adding this part where the cursor is placed:
(let ((doodler (parent (parent widget)))) (case (first new-value) (:curve (show-curve-dialog doodler)) (t nil)))and replacing the t in the last line with
(not new-value)Do not evaluate the new definition yet. (If you do, you will get a warning that the function show-curve-dialog is undefined. We are about to define it.)
(defmethod show-curve-dialog ((window doodler)) (let* ((dialog (doodler-curve-dialog window))) (when (or (not dialog) (not (windowp dialog))) (setq dialog (make-curve-dialog :owner window)) (setf (doodler-curve-dialog window) dialog)) (select-window dialog)))
(defmethod close :before ((window doodler) &key) (let ((curve-dialog (doodler-curve-dialog window))) (when (and (windowp curve-dialog) curve-dialog) (close curve-dialog)) (setf (doodler-curve-dialog window) nil)))
Whats going on here?
The show-curve-dialog method is responsible for creating displaying, and initializing the curve-dialog. It first checks to see if there is a valid curve-dialog, and if needed will create one and save it in the doodler-curve-dialog slot. Then it selects the curve-dialog; selecting the dialog un-hides it and brings it to the front of the display.
Since the doodler creates the curve-dialog, it must also close it. Closing the doodler automatically closes all of its child windows, but curve-dialog is a pop-up window, not a child window.
The owner window of the curve-dialog is the doodler, therefore the doodler must explicitly close the curve-dialog. Use a :before method on close so that the curve-dialog is closed before the doodler.
You may see a warning about show-curve-dialog being undefined in a message box. If so, click OK and ignore the warning.
(defmethod show-curve-dialog ((window doodler)) (let* ((dialog (doodler-curve-dialog window))) (when (or (not dialog) (not (windowp dialog))) (setq dialog (make-curve-dialog :owner window)) (setf (doodler-curve-dialog window) dialog) ;; Position the dialog to the ;; left of the main window. (let* ((pos (window-to-screen-units window (make-position (- (+ (exterior-width dialog) 10)) 40)))) ;; But don't let it go off the left ;; edge of the screen. (setf (position-x pos) (max 0 (position-x pos))) (move-window dialog pos))) (select-window dialog)))
Whats going on?
This revised method makes the dialog float in a position downward and to the left of the running Doodler. Youll verify this change in a few steps.
Because CLOS is dynamic, you can incrementally change code, evaluate it, and try it without leaving run mode. Make incremental changes in your code to verify that it works before adding further capabilities. This is good programming practice.
With the change youve just made to show-curve-dialog, the Curves dialog will be positioned in a new place. Before you verify that, youll test a feature called Complete Symbol that may speed up your future programming work.
The second change to show-curve-dialog places the coordinates for a single cycloidal curve in the Curves dialog. Youll make that change after you verify the first change.
#<doodler :doodler in Run Project :gui-builder-tutorial @ #x20f4190a>
The system will display all symbols starting with do. There are a lot of them. You will have to type more text in for Complete Symbol to be useful. You will do this in the next steps. Use the ESC key to get rid of the pop-up list of symbol completions for now.
(close (doodler-curve-dialog doodler))
at the prompt. Then evaluate it by pressing ENTER. The result should be t. Note that the curve-dialog has disappeared.
What happened?
You just used Get Component, Complete Symbol, and a small amount of Lisp to find and close the curve-dialog while the application was still running.
(defmethod show-curve-dialog ((window doodler)) (let ((dialog (doodler-curve-dialog window)) (curve-list nil)) ; step 50 (when (or (not dialog) (not (windowp dialog))) (setq dialog (make-curve-dialog :owner window)) (setf (doodler-curve-dialog window) dialog) (setq curve-list ; step 50 (find-component :curve-list dialog)) (setf (range curve-list) ; step 50 (list (make-instance 'cycloidal-curve))) ;; Position the dialog to the ;; left of the main window. (let* ((pos (window-to-screen-units window (make-position (- (+ (exterior-width dialog) 10)) 40)))) ;; But don't let it go off the left ;; edge of the screen. (setf (position-x pos) (max 0 (position-x pos))) (move-window dialog pos))) (select-window dialog)))
Copyright © 2001-2004 Franz Inc. All rights reserved.
|
Allegro CL version 8.0 |