[mcclim-cvs] CVS mcclim/Doc

rstrandh rstrandh at common-lisp.net
Mon Oct 30 06:26:53 UTC 2006


Update of /project/mcclim/cvsroot/mcclim/Doc
In directory clnet:/tmp/cvs-serv12406

Modified Files:
	manual.tex 
Added Files:
	views.lisp 
Log Message:
Added a new part (User manual) to the manual, and a first chapter 
(Using views) to that part. 


--- /project/mcclim/cvsroot/mcclim/Doc/manual.tex	2005/08/22 02:49:05	1.31
+++ /project/mcclim/cvsroot/mcclim/Doc/manual.tex	2006/10/30 06:26:53	1.32
@@ -607,6 +607,78 @@
 What is finally displayed (in the interactor pane, which is the
 standard input of the frame), is ``the 15 of The third month''.
 
+\part{User Manual}
+
+\chapter{Using views}
+
+The CLIM specification mentions a concept called a \emph{view}, and
+also lists a number of predefined views to be used in various
+different contexts.  
+
+In this chapter we show how the \emph{view} concept can be used in
+some concrete programming examples.  In particular, we show how to use
+a single pane to show different views of the application data
+structure at different times.  To switch between the different views,
+we supply a set of commands that alter the
+\texttt{stream-default-view} feature of all CLIM extended output
+streams.
+
+The example shown here has been stripped to a bare minimum in order to
+illustrate the important concepts.  A more complete version can be
+found in \texttt{Examples/views.lisp} in the McCLIM source tree. 
+
+Here is the example:
+
+\verbatimtabinput{views.lisp}
+
+The example shows a stripped-down example of a simple database of
+members of some organization.
+
+The main trick used in this example is the \texttt{display-main-pane}
+function that is declared to be the display function of the main pane
+in the application frame.  The \texttt{display-main-pane} function
+trampolines to a generic function called
+\texttt{display-pane-with-view}, and which takes an additional
+argument compared to the display functions of CLIM panes.  This
+additional argument is of type \texttt{view} which allows us to
+dispatch not only on the type of frame and the type of pane, but also
+on the type of the current default view.  In this example the view
+argument is simply taken from the default view of the pane.
+
+A possibility that is not obvious from reading the CLIM specification
+is to have views that contain additional slots.  Our example defines
+two subclasses of the CLIM \texttt{view} class, namely
+\texttt{members-view} and \texttt{person-view}.  
+
+The first one of these does not contain any additional slots, and is
+used when a global view of the members of our organization is wanted.
+Since no instance-specific data is required in this view, we follow
+the idea of the examples of the CLIM specification to instantiate a
+singleton of this class and store that singleton in the
+\texttt{stream-default-view} of our main pane whenever a global view
+of our organization is required.
+
+The \texttt{person-view} class, on the other hand, is used when we
+want a closer view of a single member of the organization.  This class
+therefore contains an additional slot which holds the particular
+person instance we are interested in.  The method on
+\texttt{display-pane-with-view} that specializes on
+\texttt{person-view} displays the data of the particular person that
+is contained in the view.  
+
+To switch between the views, we provide two commands.  The command
+\texttt{com-show-all} simply changes the default view of the main pane
+to be the singleton instance of the \texttt{members-view} class.  The
+command \texttt{com-show-person} is more complicated.  It takes an
+argument of type person, creates an instance of the
+\texttt{person-view} class initialized with the person that was passed
+as an argument, and stores the instance as the default view of the
+main pane. 
+
+\chapter{Using command tables}
+
+(to be filled in)
+
 \part{Reference Manual}
 
 \chapter{Concepts}

--- /project/mcclim/cvsroot/mcclim/Doc/views.lisp	2006/10/30 06:26:53	NONE
+++ /project/mcclim/cvsroot/mcclim/Doc/views.lisp	2006/10/30 06:26:53	1.1
;;; part of application "business logic"
(defclass person ()
  ((%last-name :initarg :last-name :accessor last-name)
   (%first-name :initarg :first-name :accessor first-name)
   (%address :initarg :address :accessor address)
   (%membership-number :initarg :membership-number :reader membership-number)))

;;; constructor for the PERSON class.  Not strictly necessary. 
(defun make-person (last-name first-name address membership-number)
  (make-instance 'person 
                 :last-name last-name 
                 :first-name first-name
                 :address address
                 :membership-number membership-number))

;;; initial list of members of the organization we imagine for this example
(defparameter *members*
  (list (make-person "Doe" "Jane" "123, Glencoe Terrace" 12345)
        (make-person "Dupont" "Jean" "111, Rue de la Republique" 54321)
        (make-person "Smith" "Eliza" "22, Trafalgar Square" 121212)
        (make-person "Nilsson" "Sven" "Uppsalagatan 33" 98765)))

;;; the CLIM view class that corresponds to a list of members, one member
;;; per line of text in a CLIM application pane. 
(defclass members-view (view) ())

;;; since this view does not take any parameters in our simple example,
;;; we need only a single instance of it. 
(defparameter *members-view* (make-instance 'members-view))

;;; the application frame.  It contains instance-specific data
;;; such as the members of our organization. 
(define-application-frame views ()
  ((%members :initform *members* :accessor members))
  (:panes
   (main-pane :application :height 500 :width 500
              :display-function 'display-main-pane
              ;; notice the initialization of the default view of
              ;; the application pane. 
              :default-view *members-view*)
   (interactor :interactor :height 100 :width 500))
  (:layouts
   (default (vertically ()
              main-pane
              interactor))))

;;; the trick here is to define a generic display function
;;; that is called on the frame, the pane AND the view, 
;;; whereas the standard CLIM display functions are called 
;;; only on the frame and the pane.
(defgeneric display-pane-with-view (frame pane view))

;;; this is the display function that is called in each iteration
;;; of the CLIM command loop.  We simply call our own, more elaborate
;;; display function with the default view of the pane. 
(defun display-main-pane (frame pane)
  (display-pane-with-view frame pane (stream-default-view pane)))

;;; now we can start writing methods on our own display function
;;; for different views.  This one displays the data each member
;;; on a line of its own.
(defmethod display-pane-with-view (frame pane (view members-view))
  (loop for member in (members frame)
        do (with-output-as-presentation 
               (pane member 'person)
             (format pane "~a, ~a, ~a, ~a~%"
                     (membership-number member)
                     (last-name member)
                     (first-name member)
                     (address member)))))

;;; this CLIM view is used to display the information about
;;; a single person.  It has a slot that indicates what person
;;; we want to view. 
(defclass person-view (view)
  ((%person :initarg :person :reader person)))

;;; this method on our own display function shows the detailed 
;;; information of a single member. 
(defmethod display-pane-with-view (frame pane (view person-view))
  (let ((person (person view)))
    (format pane "Last name: ~a~%First Name: ~a~%Address: ~a~%Membership Number: ~a~%"
            (last-name person)
            (first-name person)
            (address person)
            (membership-number person))))

;;; entry point to start our applciation
(defun views-example ()
  (run-frame-top-level (make-application-frame 'views)))

;;; command to quit the application 
(define-views-command (com-quit :name t) ()
  (frame-exit *application-frame*))

;;; command to switch the default view of the application pane
;;; (which is the value of *standard-output*) to the one that
;;; shows a member per line. 
(define-views-command (com-show-all :name t) ()
  (setf (stream-default-view *standard-output*) *members-view*))
    
;;; command to switch to a view that displays a single member. 
;;; this command takes as an argument the person to display.  
;;; In this application, the only way to satisfy the demand for
;;; the argument is to click on a line of the members view.  In 
;;; more elaborate application, you might be able to type a
;;; textual representation (using completion) of the person. 
(define-views-command (com-show-person :name t) ((person 'person))
  (setf (stream-default-view *standard-output*)
        (make-instance 'person-view :person person)))




More information about the Mcclim-cvs mailing list