Archive for the ‘gs:table’ Tag

newLISP で GUI する。。。または、CSV Editor の作成(改造編5)

(以下は、 newLISP v 2.8.16 以上、または、guisever 1.42以上での話です。)

 今回は、前回表示させたテーブルのHTML表示をファイルに落とせるようにします。
 先ずは、ポップアップ・メニューを用意して、

(gs:menu-popup 'viewMenuPopup "View")
(gs:menu-item 'toolCopy 'clip-action "copy")
(gs:menu-item 'toolHTMLFile 'HTMLfile-action "to .html file")
(gs:add-to 'viewMenuPopup 'toolCopy 'toolHTMLFile)

 ついでに、テーブルの list 表示もできるようにしておきます。

(gs:menu-item 'viewHTML 'dialog-action "to html-table")
(gs:menu-item 'viewList 'dialog-action "to lisp-list text")
(gs:add-to 'viewMenu 'viewAdjust 'viewHTML 'viewList)

 どちらも、同じイベント・ハンドラdialog-action に飛びます。

(define (dialog-action id)
  (gs:dialog 'Dialog 'Frame "HTML or List" FWidth FHeight nil true)
  (gs:set-border-layout 'Dialog)
  (gs:table-get *currentCSV*)
  (cond ((ends-with id "HTML")
         (gs:disable 'toolCopy)
         (gs:enable 'toolHTMLFile)
         (gs:text-pane 'OutputArea 'gs:no-action "text/html")
         (gs:set-text 'OutputArea (makeHTMLtable gs:table-full)))
        ((ends-with id "List")
         (gs:disable 'toolHTMLFile)
         (gs:enable 'toolCopy)
         (gs:text-pane 'OutputArea 'gs:no-action "text/plain")
         (dolist (row gs:table-full)
           (if (zero? $idx) (gs:set-text 'OutputArea "(")
             (gs:append-text 'OutputArea " "))
           (gs:append-text 'OutputArea (string (if *Numerics* (map string-convert row) row) "\n")))
         (gs:append-text 'OutputArea ")"))
        (true ))
  (gs:add-to 'Dialog 'OutputArea "center")
  (gs:mouse-event 'OutputArea 'dialog-mouse-handler)
  (gs:set-visible 'Dialog true))

 この中で、マウス・イベントを指定して、

(define (dialog-mouse-handler id type x y button cnt mods)
  (if (or (= button 3) (= mods 18))
    (gs:show-popup 'viewMenuPopup 'OutputArea x y)
  ))

 右クリックでポップアップ・メニューを表示させます。
 テーブル list 表示の場合、こんな感じ。


 あとは、ポップアップ・メニューで指定される処理を用意するだけ。

(define (HTML-save id op file)
  (when file
    (let (fname (base64-dec file))
      (write-file fname (gs:get-text 'OutputArea)))))
(define (HTMLfile-action)
  (let (tmp (if-not (directory? *tabName*) (parse *tabName* {\\|/} 0)))
    (gs:save-file-dialog 'Frame 'HTML-save (join (chop tmp) "/")
                                           (string ((parse (tmp -1) ".") 0) ".html")
                                           "html HTML" "HTML file")))
(define (clip-action)
  (gs:select-text 'OutputArea 0)
  (gs:copy-text 'OutputArea))

 HTMLテーブルはファイルに落とせ、テーブル list はクリップボードにコピーされます。
 全スクリプトは、CSV-Editor.lsp からどうぞ。

 以上、如何でしょうか?

newLISP で GUI する。。。または、CSV Editor の作成(改造編4)

(以下は、 newLISP v 2.8.16 以上、または、guisever 1.42以上での話です。)

 前回で、簡単な編集までできるようになりました。
 でも、実のところ、CSV を編集するなら、Excel か OpenOffice を使ったほうが便利です(笑)。
 それでも、このスクリプト改造を続けているのは、gs:table の限界を見たいというのもありますが、狙いがあります。

 と、言うことで、今回は、View メニューです。

(gs:menu 'viewMenu "View")
(gs:menu-item 'viewAdjust 'adjust-action "adjust current table")
(gs:menu-item 'viewHTML 'html-action "to html-table")
(gs:add-to 'viewMenu 'viewAdjust 'viewHTML)
(gs:menu-bar 'Frame 'fileMenu 'editMenu 'viewMenu)

 メニューの viewAdjust は、列の幅調整です。
 そして、viewHTML が今回の目玉。狙いの一つです。

; define the function for HTML
(define *header* [text]<!-- generated page -->
<html>
<table border="1">
[/text])
(define tableROW '("<tr>" "</tr>"))
(define tableDATA '("<td align=\"right\">" "(</td>"))
(define tableHEADER '("<th>" "</th>"))
(define *footer* [text]</table>
</html>
[/text])
(defun addHTMLtag (data tag)
  (string (tag 0) data (tag 1)))
(defun makeHTMLtable (lst)
  (let (html *header*)
    (dolist (row lst)
      (if *Numerics* (setq row (map string-convert row)))
      (extend html (tableROW 0))
      (dolist (col row)
        (extend html (addHTMLtag col (if (string? col) tableHEADER tableDATA))))
      (extend html (tableROW 1) "\n"))
    (extend html *footer*)))

; define handler
(define (html-action)
  (gs:dialog 'HtmlDisplay 'Frame "HTML" FWidth FHeight nil true)
  (gs:set-border-layout 'HtmlDisplay)
  (gs:text-pane 'OutputArea 'gs:no-action "text/html")
  (gs:table-get *currentCSV*)
  (gs:set-text 'OutputArea (makeHTMLtable gs:table-full))
  (gs:add-to 'HtmlDisplay 'OutputArea "center")
  (gs:set-visible 'HtmlDisplay true))

 さて、これらを CSV-Editor スクリプトに追加すれば、以前やったようなテーブル表示ができます。
 今回は、表示だけです。ファイルに落とすのは、リストのテキストやファイルに変換するのにあわせ、別の機会に。
 これも狙いの一つです。
 つまり、まだまだ、改造が続く?(笑)

 以上、如何でしょうか?

newLISP で GUI する。。。または、CSV Editor の作成(改造編3)

(以下は、 newLISP v 2.8.16 以上、または、guisever 1.42以上での話です。)

 今回は、もちろん、Edit メニューの設定です(笑)。

(gs:menu 'editMenu "Edit")
(gs:menu-item 'editCut 'edit-action "Cell Cut")
(gs:menu-item 'editCopy 'edit-action "Cell Copy")
(gs:menu-item 'editPaste 'edit-action "Cell Paste")
(gs:menu-item 'editCutRow 'cut-action "Row Cut")
(gs:menu-item 'editCopyRow 'copy-action "Row Copy")
(gs:menu-item 'editPasteRow 'paste-action "Row Paste")
(gs:menu-item 'editCutCol 'cut-action "Column Cut")
(gs:menu-item 'editCopyCol 'copy-action "Column Copy")
(gs:menu-item 'editPasteCol 'paste-action "Column Paste")
(gs:disable 'editPaste 'editPasteRow 'editPasteCol)
;(gs:set-accelerator 'editCut "ctrl X")
;(gs:set-accelerator 'editCopy "ctrl C")
;(gs:set-accelerator 'editPaste "ctrl V")
(gs:add-to 'editMenu 'editCut 'editCopy 'editPaste)
(gs:add-separator 'editMenu)
(gs:add-to 'editMenu 'editCutRow 'editCopyRow 'editPasteRow)
(gs:add-separator 'editMenu)
(gs:add-to 'editMenu 'editCutCol 'editCopyCol 'editPasteCol)
(gs:menu-bar 'Frame 'fileMenu 'editMenu)

 シンボルに Row の付いているのが行用、Col の付いているのが列用、残りがセル単品用です。
 実のところ、セル単品用は要らないのかもしれません。Windows の場合、ダブル・クリックでセルに入れば、通常のシュート・カット・キー(ctrl X、ctrl C、ctrl V)が使えます。ただし、ワン・クリックで選択した場合は使えないので、えそのために用意しました。
 では、Edit 動作のスクリプトです。
 先ずは、グローバル変数と補助 macro。

(define *rowBuffer*)
(define *colBuffer*)
(define *cellBuffer*)
(macro (cut-row L P) (pop L P))

 設営は要らないですね。
 そして、セル単品用です。

(define (edit-action id)
  (setf (get-flag) nil)
  (gs:table-get *currentCSV*)
  (when (and (not (apply empty? gs:table-full)) (> *currentRow* -1) (> *currentCol* -1))
    (cond ((ends-with id "Cut")
           (gs:enable 'editPaste)
           (setq *cellBuffer* "")
           (swap (gs:table-full *currentRow* *currentCol*) *cellBuffer*)
           (set-table gs:table-full *currentCSV*))
          ((ends-with id "Copy")
           (gs:enable 'editPaste)
           (setq *cellBuffer* (gs:table-full *currentRow* *currentCol*)))
          ((ends-with id "Paste")
           (setf (gs:table-full *currentRow* *currentCol*) *cellBuffer*)
           (set-table gs:table-full *currentCSV*))
           (true ))
    (set-table gs:table-full *currentCSV*)))

 これも、説明するまでもないかもしれません。特徴としては、動作をまとめたので、gs:table-get-cell を使わずに gs:table-get を使っていることくらい?
 次は、行と列用のペースト動作、

(define (paste-action id)
  (setf (get-flag) nil)
  (gs:table-get *currentCSV*)
  (clear-table *currentCSV*)
  (cond ((and (ends-with id "Row") (> *currentRow* -1))
         (setf (gs:table-full *currentRow*) *rowBuffer*)
         (set-table gs:table-full *currentCSV*))
        ((and (ends-with id "Col") (> *currentCol* -1))
         (gs:table-get-size *currentCSV*)
         (letn (len (- (length *colBuffer*) (gs:table-size 0))
                tmp (if (< len 1) gs:table-full
                      (append gs:table-full (dup (apply append (dup '("") (gs:table-size 1))) len))))
           (setq tmp (transpose tmp))
           (setf (tmp *currentCol*) (if (< len 1) 
                                        (append *colBuffer* (apply append (dup '("") (- len))))
                                      *colBuffer*))
           (set-table (transpose tmp) *currentCSV*)))
        (true )))

 列用のペーストでは、現在のテーブルの列よりバッファの長さが大きい場合、テーブル・サイズを大きくしています。
 行用でやっていないのは、関数set-table で行っているから。

(defun set-table (lst table)
  ;(let (len (length (lst 0)))
  (let (len (apply max (map length lst)))
    (gs:table-get-size table)
    (when (< (gs:table-size 1) len)
      (for (i (i+ (gs:table-size 1)) len) (gs:table-add-column table "")))
      (dolist (row lst)
        (let (r $idx)
          (if (< r (gs:table-size 0))
              (dolist (c row) (gs:table-set-cell table r $idx (string c)))
            (gs:table-add-row table (map string row))))))
  (unless (for-all (curry = "") (flat lst)) (adjust-column table)))

 先頭行の長さで決めていた列の大きさを一番長い行の大きさで決めるようにしました。
 残りのカットとコピーは、

(define (cut-action id)
  (setf (get-flag) nil)
  (gs:table-get *currentCSV*)
  (clear-table *currentCSV*)
  (unless (apply empty? gs:table-full) 
    (cond ((and (ends-with id "Row") (> *currentRow* -1))
           (setq *rowBuffer* (cut-row gs:table-full *currentRow*))
           (gs:enable 'editPasteRow)
           (set-table gs:table-full *currentCSV*))
          ((and (ends-with id "Col") (> *currentCol* -1))
           (let (tmp (transpose gs:table-full))
             (setq *colBuffer* (cut-row tmp *currentCol*))
             (gs:enable 'editPasteCol)
             (set-table (transpose tmp) *currentCSV*)))
          (true ))))
(define (copy-action id)
  (setf (get-flag) nil)
  (gs:table-get *currentCSV*)
  (unless (apply empty? gs:table-full) 
    (cond ((and (ends-with id "Row") (> *currentRow* -1))
           (gs:enable 'editPasteRow)
           (setq *rowBuffer* (gs:table-full *currentRow*)))
          ((and (ends-with id "Col") (> *currentCol* -1))
           (gs:enable 'editPasteCol)
           (setq *colBuffer* ((transpose gs:table-full) *currentCol*)))
          (true ))))

 これらを追加したスクリプトは、こちらからどうぞ
 これで、ほぼ完成?

 以上、如何でしょうか?

newLISP で GUI する。。。または、CSV Editor の作成(改造編2)

(以下は、 newLISP v 2.8.16 以上、または、guisever 1.42以上での話です。)

 今回は、遅まきながら、メニューの設定です(汗)。

(gs:menu 'fileMenu "File")
(gs:menu-item 'fileNew 'new-action "New table")
(gs:menu-item 'fileClose 'close-action "Close table")
(gs:menu-item 'fileOpen 'open-file-dialog "Open ...")
(gs:menu-item 'fileSave 'save-action "Save")
(gs:menu-item 'fileSaveAs 'save-file-dialog "Save As ...")
(gs:menu-item 'fileExit 'closed-window "Exit")
(gs:add-to 'fileMenu 'fileNew 'fileClose )
(gs:add-separator 'fileMenu)
(gs:add-to 'fileMenu 'fileOpen 'fileSave 'fileSaveAs)
(gs:add-separator 'fileMenu)
(gs:add-to 'fileMenu 'fileExit)
(gs:set-accelerator 'fileNew "shift ctrl N")
(gs:set-accelerator 'fileClose "ctrl W")
(gs:set-accelerator 'fileOpen "ctrl O")
(gs:set-accelerator 'fileSave "ctrl S")
(gs:set-accelerator 'fileSaveAs "shift ctrl S")
(gs:menu-bar 'Frame 'fileMenu)

 メニューの設定は、単純に力技です(笑)。
 動作自体は、gs:button や gs:image-button に割り付けてあるイベント・ハンドラをそのまま使います。
 これらを スクリプトに追加して、実行すれば、

 こんな感じ。ショート・カットも使えます。
 File メニュー、とくれば、Edit メニュー? それには、カット&ペーストを用意しなければ、、、

 ということで、Edit メニューの追加は、次回に。

 以上、如何でしょうか?

newLISP で GUI する。。。または、CSV Editor の作成(改造編)

(以下は、 newLISP v 2.8.16 以上、または、guisever 1.42以上での話です。)

 早くも、改造に取りかかります(笑)。
 先ず、*tabList* からカレント・タブの要素を取り出す macro を用意しておきます。

(macro (get-tableID)  (lookup *currentCSV* *tabList* 0))
(macro (get-filename) (lookup *currentCSV* *tabList* 1))
(macro (get-row/col)  (lookup *currentCSV* *tabList* -2))
(macro (get-flag)     (lookup *currentCSV* *tabList* -1))
(macro (get-index)    ((ref *currentCSV* *tabList*) 0))

 こうしておけば、後で *tabList* の要素リストを変更しても最少限の変更で済みますからね。
 さて、今回は、テーブル表示の再表示ボタンを追加します。
 テーブルの行と列の削除でデータを削除できますが、テーブル自体の大きさは変わりません。
 つまり、最終行または最終列に空白の行または列が残ります。それらを削除し、ついでに、列の幅調整も行ないます。

(gs:image-button 'adjustButton 'adjust-action "/local/restart32.png" "/local/restart-down32.png")
(define (adjust-action)
  (unless (get-flag)
    (gs:table-get *currentCSV*)
    (letn (idx (get-index)
           fname (get-filename)
           table (make-table fname))
      (pop *tabList* -1)
      (setf (get-tableID) table)
      (gs:insert-tab 'CSVtab table fname idx)
      (set-table (delete-end-null-all gs:table-full) table)
      (gs:remove-tab 'CSVtab (i+ idx))
      (gs:request-focus 'CSVtab idx)
    )
  )
)

 やっていることは単純で、カレント・タブからデータを取り出し、新しく用意したテーブルにセットし、新しいタブをカレント・タブ位置に挿入してから、古い表示のカレント・タブを削除する、というもの。
 用意しておいた前述の macro のおかげで、簡単に書けます。
 全スクリプトは、こちらからどうぞ

 以上、如何でしょうか?

newLISP で GUI する。。。または、CSV Editor の作成(解説編)

(以下は、 newLISP v 2.8.16 以上、または、guisever 1.42以上での話です。)

 さて、前回紹介した CSV Editor のスクリプトは、如何だったでしょうか?
 今のところ、動作は、

  • CSV(Comma-Separated Values)ファイルの読み書き
  • カレント・テーブルの破棄(閉じる)
  • テーブルのセルの編集
  • 行と列の挿入と削除
  • カレント・テーブルのクリア

 だけです。
 gs:tabbed-panega:table を割り付けてあるのが、CSV Viewer との大きな違い(笑)。
 さて、テーブルを区別するために、タブ毎のプロパティを *tabList* に入れてあります。
 *tabList* の要素は、もちろん、リストで、

(table filename (row column) flag)

 内訳は、

table    : テーブルID
filename : ファイル名(フルパス)
row      : 0 から始まる行番号
column   : 0 から始まる列番号
flag     : true なら変更なし、nil なら変更したかも。

 としています。テーブル番号を含めていないのは、リストの位置をテーブル番号として使っているからです。
 テーブルが切り替わると、

(define (tab-changed id tabID title tabPos)
  ;(println "id=" id " tabID=" tabID " title=" (base64-dec title) " tabPos" tabPos)
  (let (fname (base64-dec title))
    (if *currentCSV* (setf (lookup *currentCSV* *tabList* -2) (list *currentRow* *currentCol*)))
    (aif (ref fname *tabList*) (setq *currentCSV* (*tabList* (it 0) 0)))
    (setq *currentRow* ((lookup *currentCSV* *tabList* -2) 0)
          *currentCol* ((lookup *currentCSV* *tabList* -2) 1))
    (gs:set-text 'Status fname)
    (setq *tabName* fname)))

 関数tab-changed が動作して、*tabList* に今までのテーブルの状況(選択されている行と列の番号)を保存し、切り替わったテーブル用にグローバル変数 *currentXXX* を再設定しています。
 引数の tabID を使っていないのは、guiserver 1.42 では、gs:table を割り付けたタブからは、"null" が返るからです。guiserver 1.43 から テーブルID が返るようになります
 また、前回紹介したスクリプトは、flag を使っていなかったので、使ったバージョンを CSV-Editor.lsp にアップしてあります。
 ついでに、1.43用に直してもよかったのですが、多分これから改良していくことになるので、その際に(笑)。

 リストから CSV文字列への変換や、行と列の挿入と削除は、もうやったし、、、解説としては、こんなところ?

 以上、如何でしょうか?

newLISP で GUI する。。。または、CSV Editor の作成

 さて、gs:table を使った CSV Viewer は、如何だったでしょうか?
 何も見るだけだったら、gs:table を使うまでもなく、gs:text-pane で十分です
 gs:table を使う最大の魅力は、テーブルを直接編集できる点にあります。

 と、言うことで、今回は、CSV Editor を作ってみました。
 スクリプトは、こちらにあります。
 実行すれば、

 こんな感じで、ウィンドウが表示され、CSV ファイルの読書きと簡単な編集ができます。
 とはいえ、まだまだ、開発途上です。
 今日は、スクリプトの紹介まで。
 次回から、スクリプトの解説と併せて、改良していきたいと思います。

 以上、如何でしょうか?

newLISP で GUI する。。。または、gs:table を使ってみる。(解説編)

(以下は、 newLISP v 2.8.16 以上、または、guisever 1.42以上での話です。)

 昨日の gs:table を使った CSV viewer は、如何だったでしょうか?
 さて今日は、その解説をマニュアルを引用しながら行ないます。
 新しい guiserver のテーブル・ウィジェットは、以下の9つの関数と2つの内部変数、gs:table-fullgs:table-size、からなります。
以下の9つの関数と3つの内部変数、gs:table-cellgs:table-fullgs:table-size、からなります。

(gs:table sym-id sym-action [str-column-header-name ...])
(gs:table-add-column sym-id str-column-header-name ...)
(gs:table-add-row sym-id [str-columns ... ])
(gs:table-get sym-id)
(gs:table-get-cell sym-id int-row int-column)
(gs:table-get-size sym-id)
(gs:table-set-cell sym-id int-row int-column str-value)
(gs:table-set-column sym-id int-column-number int-width [str-justification])
(gs:table-set-row-number sym-id bool-row-number)

 関数名から大体の想像がつくと思いますが、
 先ずは、テーブル生成関数 gs:table から、

gs:table

syntax: (gs:table sym-id sym-action [str-column-header-name …])
parameter: sym-id – The name of the table.
parameter: sym-action – The handler function symbol when cell selected.
parameter: str-column-header-name – the optional column header name.

(訳注:sym-id で指定されたテーブルを生成します。)
str-column-header-name で指定された列が行無しで作成されます。
str-column-header-name に空文字列を指定した時は、(訳注:列の見出しに)列の番号が使われます(訳注:str-column-header-name を指定しない時は、column 1 になります)。
列無しなら、空テーブル (0 x 0) が作られます。
Creates a table with str-column-header-name specified column and empty row.
For empty strings specified as column headers, the column number will be used.
If there are no columns, an empty table (0 x 0) is created.

(訳注:イベント・ハンドラは、次のように記述します:

(define (table-action id row col data)
  (println "id=" id " row=" row " col=" col " data=" data))

id – テーブルの ID
row – 0 から始まる行番号
col – 0 から始まる列番号
data – base64 エンコードされていない文字列データ。(つまり、そのまま使えます)

 セルに移動すると発生します。
 セルの移動には、マウスの左クリック、矢印キー、return キー(下方、次の列の先頭、一列目の先頭)が使えます。
 セル内容の変更では、イベントは発生しません。
 )

(2010/10/04 イベント・ハンドラ部分を追加)
 最初に生成されるテープルは、列を指定できますが、行は付いていません。行は、後述するgs:table-add-rowで設定します。また、列も gs:table-add-column を使って後で追加できます。
 列の数は、str-column-header-name の数で決まりますが、他の guiserver のウィジェット生成関数のようにリストで渡せます。

(gs:table 'OutputArea 'table-action '("1" "2" "3"))
; or
(gs:table 'OutputArea 'table-action (map string (sequence 1 3)))

 str-column-header-name を指定しない時は、

(gs:table 'OutputArea 'table-action '())

 と等価で、表示は

 こんな感じ。

(gs:table 'OutputArea 'table-action )
(gs:table-add-column 'OutputArea "")

 という風に、gs:table-add-column を続けると、表示が

 となります。つまり、空テーブル (0 x 0) はならない?、、、実害はないですけどね。
 そして、

(gs:table 'OutputArea 'table-action "")

 と、str-column-header-name に空文字列を指定した時の表示は、

 さらに、

(gs:table 'OutputArea 'table-action "");
(gs:table-add-column 'OutputArea "")

 と、gs:table-add-column を追加して、

 こんな感じの表示。gs:table-add-column での空文字列指定では、列の見出しに列の番号が使われますが、gs:table では、空文字列そのものが、列の見出しになるようです。
 昨日の CSV viewer で、

(gs:table 'OutputArea 'table-action "1")

 としているのは、列の追加時に、

(gs:table-add-column 'OutputArea "")

 を使って、列の見出しを列の番号にするのに合わせたかったからです。
 (map string (sequence 1 n)) を使って、n 個の列を作っておくのが普通の使い方かも。
 さて、お次は、gs:table-add-column ですが、

gs:table-add-column

syntax: (gs:table-add-column sym-id str-column-header-name …)
parameter: sym-id – The name of the table.
parameter: str-column-header-name – Add column header name(s).

str-column-header-name が空文字列なら、名前は列番号に設定されます。
テーブル・サイズが追加されます。
When a column header name is empty, the name is set to the column number.
The table size grows.

 もはや、説明するまでもないですね。
 次は当然、行を追加する gs:table-add-row でしょう。

gs:table-add-row

syntax: (gs:table-add-row sym-id [str-columns … ])
syntax: (gs:table-add-row sym-id ([str-columns …))
parameter: sym-id – The name of the table.
parameter: str-columns – Add a row with contents in str-columns

各列を含む行を追加します。必要ならスクロールバーが現れます。
str-columns に内容が定義されないか、列の数より少ない定義の場合、列の内容は空になります。
複数の列の内容は、文字列のリストか gs:table-add-row の追加パラメータでも指定できます。
Add row with each column value. If necessary a scrollbar will appear.
If no contents is defined in str-columns, or if contents for less
columns is defined than available, column contents is left empty.
Mutliple multiple column content can be specified as either a list
of strings or addtional parameters of gs:table-add-row.

 これも説明は要らないですね。
 CSV viewer では、

(gs:table-add-row 'OutputArea (map string row))

 という形で使っています。変数row に入っているのが CSV ファイルの一行をリスト化したものです。
 そして、gs:table-set-row-number を使って行番号の表示をさせています。

gs:table-set-row-number

syntax: (gs:table-set-row-number sym-id bool-row-number)
parameter: sym-id – The name of the table.
parameter: bool-row-numbertrue if rowns should carry a row number; default nil.

行番号を表示/非表示します。デフォルトは、行番号の非表示です。
Show or hide the row number headers. The default is hiding row numbers.

 行番号は、1 から始まります。
 さて、CSV viewer で使っているテーブル・ウィジェット用関数の残りは2つ。
 まず、テーブルの大きさを取得する関数gs:table-get-size

gs:table-get-size

syntax: (gs:table-get-size sym-id)
parameter: sym-id – The name of the table.

return: table size list (row-size, column-size)

テーブル・サイズを取り出し、gs:table-size に保存します。
注記:追加された列や行は、変数gs:table-size に自動的に更新されません。
この変数を更新するために、gs:table-get-size を使って下さい。
Get table size, stored in gs:table-size.
Note, that adding columns or row will not automatically update
the gs:table-size variable. Use gs:table-get-size to update
this variable.

 マニュアルにあるように、実行すれば、テーブルの大きさが変数gs:table-size にリストで保存されますので、便利です。
 CSV viewer では、現在のテーブルの大きさより CSV テーブルが大きい時、行と列を追加する判断に使っています。
 また、この関数と後述する関数 gs:table-set-cell を使って、全テーブル・セルのクリアができます。

(define (clear-table table)
  (gs:table-get-size table)
  (dotimes (i (gs:table-size 0))
    (dotimes (j (gs:table-size 1))
      (gs:table-set-cell table i j ""))))

 引数table に gs:table で指定した sym-id を渡せば、どんなテーブルでもクリアされます(笑)。
 さて、中でテーブルの個々のセルに値を設定している関数 gs:table-set-cell は、

gs:table-set-cell

syntax: (gs:table-set-cell sym-id int-row int-column str-value)
parameter: sym-id – The name of the table.
parameter: int-row – The row of the cell set.
parameter: int-column – The column of the cell set.
parameter: str-value – The cell value.

return: The previous contents of the cell; also stored in gs:table-cell.

テーブル・セルを新しい内容(訳注:str-value)に設定し、古いセル内容を返します。
行と列の番号は、’0′ (zero) から始まります(テーブルに表示される番号は ‘1’ から始まります)。
セルの内容は、文字列として渡されます(訳注:str-value は文字列入力です)。
Sets a new table cell contents and returns the old cell contents. Row and
column numbering starts with ‘0’ (zero). The cell contents is passed
as a string.

 これも説明は要らないですね。注意点としては、列と行の番号表示は 1 から始まりますが、セルを指定する番号は列と行の共に 0 から始まるということくらい。
 さて、次は当然、gs:table-set-cell となりますが、長くなってきたので、残りの関数と併せて、次回に。CSV viewer でも使っていなかったし(笑)。

 以上、如何でしょうか?

newLISP で GUI する。。。または、gs:table を使ってみる。

 newLISP の開発バージョン 2.8.16 がリリースされ、gs:table が使えるようになりました。
 と、言うことで、gs:table を使って、先日の太陽系惑星のデータを表示させてみましょう。
 先ずは、スクリプトから、(aif と defun は newlisp-utility.lsp に、include は init.lsp に定義してあります。)

; utility
(define *newlispDir* (env "NEWLISPDIR"))
(load (append *newlispDir* "/guiserver.lsp")) 
(include "macro.lsp")
(include "newlisp-utility.lsp")
; define sub-routine
(define CRLF "\x0d\x0a")
(define regexCRLF "\r*\n")
(defun stringEx (x)
  (if (string? x) (string "\"" x "\"") (string x)))
(defun string-convert (str) 
  (if (catch (eval-string str) 'res) (if res res str) str))
(defun list2csv (lst)
  (let (csv "")
    (dolist (row lst)
      (extend csv (join (map stringEx row) ",") CRLF))))
(defun csv2list (csv)
  (let (lst '())
    (dolist (row (parse (if (ends-with csv regexCRLF 0) (chop csv) csv) regexCRLF 0))
      (push (map string-convert (parse row ",")) lst -1))
    (setf (lst -1 -1) (if (string? $it) (trim $it "\r") $it))
    lst))
(defun csvfile2list (file)
  (cond ((directory? file) nil)
         ((file? file)
          (csv2list (read-file *fileName*)))
         (true nil)))
; define the function for gs:table
(defun clear-table (table)
  (gs:table-get-size table)
  (dotimes (i (gs:table-size 0))
    (dotimes (j (gs:table-size 1))
      (gs:table-set-cell table i j ""))))
(defun set-table (lst)
  (clear-table 'OutputArea)
  (let (len (length (lst 0)))
    (when (< (gs:table-size 1) len)
      (for (i (i+ (gs:table-size 1)) len) (gs:table-add-column 'OutputArea ""))))
  (dolist (row lst)
    (let (r $idx)
      (if (< r (gs:table-size 0))
          (dolist (c row) (gs:table-set-cell 'OutputArea r $idx (string c)))
        (gs:table-add-row 'OutputArea (map string row))))))
; define handler
(define *fileName* (real-path))
(define *filemask* "csv CSV")
(define *description* "csv file")
(define (openfile-action id op file)
  (when file
    (setq *fileName* (base64-dec file))
    (gs:set-text 'Status *fileName*)
    (aif (csvfile2list *fileName*)
        (set-table it)
      (gs:set-text 'Status (string *fileName* " is not csv file.")))))
(define (open-file-dialog)
  (gs:open-file-dialog 'Frame 'openfile-action *fileName* *filemask* *description*))
(define (table-action id row col data)
  (println "id=" id " row=" row " col=" col " data=" data))
; initialization
(gs:init)
(define FPosX 100)
(define FPosY 50)
(define FWidth 640)
(define FHeight 480)
(gs:frame 'Frame FPosX FPosY FWidth FHeight "CSV Viewer with gs:table")
(gs:panel 'StatusPanel)
(gs:label 'Status (real-path))
(gs:button 'fileButton 'open-file-dialog "File")
(gs:table 'OutputArea 'table-action "1")
(gs:table-add-row 'OutputArea )
(gs:table-set-row-number  'OutputArea true)
(gs:add-to 'StatusPanel 'fileButton 'Status) 
; mount all on frame
(gs:set-border-layout 'Frame)
(gs:set-flow-layout 'StatusPanel "left")
(gs:add-to 'Frame 'OutputArea "center" 'StatusPanel "south")
(gs:set-visible 'Frame true)
; main routine
(gs:listen)
(exit)

 これを実行させるには、 v 2.8.16以上が必要です。
 実行させて、CSVファイルを読み込むと、

 こんな感じで日本語も表示できます。日本語になっているのそういう CSVファイルを読み込んだからです。gs:table で自動的に日本語になる訳はありません。念のため(笑)。

 さて、gs:table の解説は、次回に。

 以上、如何でしょうか?