CLIM mail archive


Spreadsheet style input method (or AVV)

    Date: Tue, 25 Jan 1994 17:00 EST
    From: Mike Harper <mlh@BBN.COM>

    Has anyone built some type of spreadsheet like data input system in
    CLIM (1 or 2)? Is this even a reasonable style of input to use CLIM for?
It's perfectly reasonable, but unless the spreadsheet-like thing is
fairly small, using ACCEPTING-VALUES is not the tool for the job.  A
grid arrangement for input fields has strong constraints on what needs
to be redisplayed, but ACCEPTING-VALUES will always go ahead and just
try to redisplay everything it thinks might have changed.  So a large
spreadsheet will be slow.

I believe I may have already posted a "grid" output record frob on which
spreadsheets can be built better.  I will send it to you in another
message.  It's for CLIM 2.0, by the way.

As lagniappe, here is a silly little spreadsheet dialog for CLIM 2.0.
Who knows, you may find it adequate.

-------- Cut here --------
;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Package: CLIM-USER; Base: 10; Lowercase: Yes -*-

(defparameter *default-cell-width* '(6 :character))

(defparameter *cell-text-field-width* '(10 :character))
(defparameter *cell-text-field-view* (make-instance 'text-field-view
				       :width *cell-text-field-width*))

;; A spreadsheet consists of a bunch of rows, a row consisting of
;; column sums, and a total.
(defclass spreadsheet ()
    ((rows :reader spreadsheet-rows)
     (column-sums :reader spreadsheet-column-sums)
     (total :accessor spreadsheet-total :initform 0.0)
     (cell-width :reader spreadsheet-cell-width
		 :initarg :cell-width :initform *default-cell-width*)))

(defmethod initialize-instance :after ((spreadsheet spreadsheet)
				       &key nrows ncells &allow-other-keys)
  (with-slots (rows column-sums) spreadsheet
    (setf rows (make-array nrows))
    (dotimes (i nrows)
      (setf (aref rows i) (make-instance 'spreadsheet-row :ncells ncells)))
    (setf column-sums (make-instance 'spreadsheet-row :ncells ncells))))

;; A row consists of a bunch of cells and a row sum.
(defclass spreadsheet-row ()
    ((cells :reader spreadsheet-row-cells)
     (row-sum :accessor spreadsheet-row-sum :initform 0.0)))
(defmethod initialize-instance :after ((row spreadsheet-row)
				       &key ncells &allow-other-keys)
  (with-slots (cells) row
    (setq cells (make-array ncells :element-type 'float :initial-element 0.0))))

;; Formatting a spreadsheet row consists of getting as input a
;; value for each cell in the row, using as a default the value
;; that is there right now.
(defun format-spreadsheet-row (row stream cell-width &key use-text-fields)
  (let ((cells (spreadsheet-row-cells row)))
    (clim:formatting-row (stream)
      (dotimes (i (length cells))
	(clim:formatting-cell (stream :align-x :right 
				      :min-width (and (not use-text-fields) cell-width))
	  (setf (aref cells i)
		(clim:accept 'float
			     :default (aref cells i)
			     :prompt nil :prompt-mode :raw
			     :query-identifier (list cells i)
			     :stream stream
			     :view (if use-text-fields
      (present-sum (spreadsheet-row-sum row) stream cell-width))
    (setf (spreadsheet-row-sum row) (reduce #'+ cells))))

(defun present-sum (sum stream cell-width)
  (clim:formatting-cell (stream :align-x :right :min-width cell-width)
    (clim:with-text-face (stream :bold)
      (clim:present sum 'float :stream stream))))

(defun spreadsheet (nrows ncells
		    &key (cell-width *default-cell-width*) (stream *query-io*)
			 (use-text-fields t))
  (let* ((spreadsheet (make-instance 'spreadsheet
				     :nrows nrows :ncells ncells
				     :cell-width cell-width))
	 (rows (spreadsheet-rows spreadsheet))
	 (column-totals (spreadsheet-row-cells (spreadsheet-column-sums spreadsheet))))
    ;; :RESYNCHRONIZE-EVERY-PASS T to get the totals recomputed
    (clim:accepting-values (stream :own-window nil
				   :resynchronize-every-pass t)
      (clim:formatting-table (stream :x-spacing '(2 :character)
				     :equalize-column-widths t)
	(map nil #'(lambda (row)
		     (format-spreadsheet-row row stream cell-width
					     :use-text-fields use-text-fields))
	(clim:formatting-row (stream)
	  (map nil #'(lambda (cell)
		       (present-sum cell stream cell-width)) column-totals)
	  (present-sum (spreadsheet-total spreadsheet) stream cell-width)))
      (setf (spreadsheet-total spreadsheet) 0.0)
      (dotimes (i ncells)
	(setf (aref column-totals i) 0.0)
	(dotimes (j nrows)
	  (incf (aref column-totals i) (aref (spreadsheet-row-cells (aref rows j)) i)))
	(incf (spreadsheet-total spreadsheet) (aref column-totals i))))


Main Index | Thread Index