Update of /project/mcclim/cvsroot/mcclim/Examples In directory clnet:/tmp/cvs-serv17986
Added Files: views.lisp Log Message: An example showing the use of CLIM views.
--- /project/mcclim/cvsroot/mcclim/Examples/views.lisp 2006/10/29 15:27:31 NONE +++ /project/mcclim/cvsroot/mcclim/Examples/views.lisp 2006/10/29 15:27:31 1.1 ;;; ;;; This example shows how to use CLIM view objects. We imagine a small ;;; database of members in some organization, and we sometimes want to ;;; see a list of all the members, with one member per line, and sometimes ;;; a detailed view of a single member, perhaps in order to check the ;;; payment record, or to modify some information such as the address.
;;; Copyright (c) 2006 by Robert Strandh
;;; This library is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU Library General Public ;;; License as published by the Free Software Foundation; either ;;; version 2 of the License, or (at your option) any later version. ;;; ;;; This library is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; Library General Public License for more details. ;;; ;;; You should have received a copy of the GNU Library General Public ;;; License along with this library; if not, write to the ;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;;; Boston, MA 02111-1307 USA.
(defpackage :views-example (:use :clim-lisp :clim) (:export #:views-example))
(in-package :views-example)
;;; 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)))