Next: An application displaying a data structure, Previous: Executing the Application, Up: The First Application
In a serious application, you would probably want some area where your application objects are to be displayed. In CLIM, such an area is called an application pane, and would be an instance (direct or indirect) of the CLIM class application-pane. In fact, instances of this class are in reality also streams which can be used in calls both to ordinary input and output functions such as format and read and to CLIM-specific functions such as draw-line.
In this example we have such an application pane, the name of which is app. As you can see, we have defined it with an option :display-time nil. The default value for this option for an application pane is :command-loop, which means that the pane is cleared after each iteration in the command loop, and then redisplayed using a client-supplied display function. The default display function does nothing, and we have not supplied any, so if we had omitted the :display-time nil option, the parity command would have written to the pane. Then, at the end of the command loop, the pane would have been cleared, and nothing else would have been displayed. The net result is that we would have seen no visible output. With the option :display-time nil, the pane is never cleared, and output is accumulated every time we execute the parity command.
For this example, let us also add a few commands. Such commands are defined by the use of a macro called define-name-command, where name is the name of the application, in our case superapp. This macro is automatically defined by define-application-frame.
Let us also add a pane that automatically provides documentation for different actions on the pointer device.
Here is our improved example:
(in-package :common-lisp-user) (defpackage "APP" (:use :clim :clim-lisp) (:export "APP-MAIN")) (in-package :app) (define-application-frame superapp () () (:pointer-documentation t) (:panes (app :application :display-time nil :height 400 :width 600) (int :interactor :height 200 :width 600)) (:layouts (default (vertically () app int)))) (defun app-main () (run-frame-top-level (make-application-frame 'superapp))) (define-superapp-command (com-quit :name t) () (frame-exit *application-frame*)) (define-superapp-command (com-parity :name t) ((number 'integer)) (format t "~a is ~a~%" number (if (oddp number) "odd" "even")))
If you execute this example, you will find that you now have three different panes, the application pane, the interactor pane and the pointer documentation pane. In the pointer documentation pane, you will see the text R possibilities which indicates that if you click the right mouse button, you will automatically see a popup menu that lets you choose a command. In our case, you will have the default commands that are automatically proposed by McCLIM plus the commands that you defined yourself, in this case quit and parity.
fig:figex2 shows what ought to be visible on the screen.
Notice that commands, in order to be available from the command line, must have an option of :name t. The reason is that some commands will be available only from menus or by some other mechanism.
You may notice that if the output of the application is hidden (say by the window of some other application) and then re-exposed, the output reappears normally, without any intervention necessary on the part of the programmer. This effect is accomplished by a CLIM mechanism called output recording. Essentially, every piece of output is not only displayed in the pane, but also captured in an output record associated with the pane. When a pane is re-exposed, its output records are consulted and if any of them overlap the re-exposed region, they are redisplayed. In fact, some others may be redisplayed as well, because CLIM guarantees that the effect will be the same as when the initial output was created. It does that by making sure that the order between (partially) overlapping output records is respected.
Not all panes support output recording, but certainly application panes do, so it is good to use some subclass of application-pane to display application-specific object, because output recording is then automatic.