Home   Archive   Permalink



rebgui spreadsheet not doing much

Hi,
    
I have tried to use the spreadsheet with limited success. In column b1 I put in = a1 * 10 and it gives the right answer but in b2 I put =b1 * 2 and I get "none". Why is that?

posted by:   John     5-May-2014/20:55:15-7:00



Sorry - here is the code:R E B O L [
     title: "RebGUI Spreadsheet Example"
     date: 18-Apr-2010
     file: %rebgui-spreadsheet.r
     author: Nick Antonaccio
     purpose: {
         A tiny demo of RebGUI's sheet widget, with save, load, print
         and data view features.
         Taken from the tutorial at http://re-bol.com
     }
]
    
do load-thru http://re-bol.com/rebgui.r    ; Build#117
    
display "Spreadsheet" [
     x: sheet options [size 3x3 widths [8 8 10]] data [
         A1 32 A2 12 A3 "=a1 + a2" A4 "=1.06 * to-integer a3"
     ]
     return
     button "Save" [
         x/save-data
         save to-file request-file x/data
     ]
     button "Load" [
         x/load-data load to-file request-file
     ]
     button "View" [
         x/save-data
         alert form x/data
     ]
     button "Print" [
         save/png %sheet.png to image! x
         browse %sheet.png ; or call %sheet.png
     ]
]
do-events


posted by:   John     5-May-2014/20:55:57-7:00



Also, what would be involved with the formulas giving an answer as soon as one presses enter IN the cell that the formula is in rather than going into another cell.

posted by:   John     5-May-2014/21:09:43-7:00



In your b2 cell, the value from b1 needs to be evaluated:
    
     =(do b1) * 2
    
To adjust how the cells respond, you'd have to look at the event handler which Ashley created.

posted by:   Nick     6-May-2014/12:12:21-7:00



Thanks Nick

posted by:   John     6-May-2014/12:17:03-7:00



I did as you said regarding the =(do... etc. and it kind of works. However, it removes the parenthesis and don't dare land in a cell that has parenthesis or it will say none when you leave the cell. Very kludgey, I would say. Am I missing something?

posted by:   John     6-May-2014/14:39:41-7:00



In fact, to be charitable both these programs - under rebgui-spreadsheet and the original spreadsheet are jam chocked full of bugs so bad that they hang , stop running and blow up helter skelter. I am surprised anyone would offer them up as "powerful" or anything else.

posted by:   John     6-May-2014/16:12:03-7:00



They're simple widgets - Carl's original (2001) was meant as a demo to show how to use the basics of VID dialect. This article from 2005 explains how it works, so you can adjust and extend it as needed:
    
http://www.devx.com/opensource/Article/27454
    
You can also dive into Ashley's code and make it perform however you want. It's half a page of code John, not Excel (but it still has been useful to me a few times :)

posted by:   Nick     6-May-2014/19:48:04-7:00



What are you trying to accomplish with it? Perhaps it would be worth while to extend and improve - you're the second person who's reminded me about that example recently.

posted by:   Nick     6-May-2014/21:59:43-7:00



BTW,
    
This tiny tweak to Carl's original (in my example at http://easiestprogramminglanguage.com ) eliminates the two problems you mentioned above:
    
R E B O L [Title: "Rebocalc" Authors: ["Carl Sassenrath" "edit by Nick Antonaccio"]]
csize: 100x20 max-x: 8 max-y: 16
pane: []
xy: csize / 2 + 1 * 1x0
yx: csize + 1 * 0x1
layout [
     cell: field csize edge none [enter face compute face/para/scroll: 0x0]
     label: text csize white black bold center
]
char: #"A"
repeat x max-x [
     append pane make label [offset: xy text: char]
     set in last pane 'offset xy
     xy: csize + 1 * 1x0 + xy
     char: char + 1
]
repeat y max-y [
     append pane make label [offset: yx text: y size: csize * 1x2 / 2]
     yx: csize + 1 * 0x1 + yx
]
xy: csize * 1x2 / 2 + 1
cells: tail pane
repeat y max-y [
     char: #"A"
     repeat x max-x [
         v: to-word join char y
         set v none
         char: char + 1
         append pane make cell [offset: xy text: none var: v formula: none]
         xy: csize + 1 * 1x0 + xy
     ]
     xy: csize * 1x2 / 2 + 1 + (xy * 0x1)
]
enter: func [face /local data] [
     if empty? face/text [exit]
     set face/var face/text
     data: either face/text/1 = #"=" [next face/text][face/text]
     if error? try [data: load data] [exit]
     if find [
         integer! decimal! money! time! date! tuple! pair!
     ] type?/word :data [set face/var data exit]
     if face/text/1 = #"=" [face/formula: :data]
]
compute: has [blk] [
     unfocus
     foreach cell cells [
         if cell/formula [
             either cell/text = "formula" [
                 cell/text: join "=" form cell/formula
                 show cell return
             ][
                 if error? cell/text: try [do cell/formula] [
                     cell/text: "ERROR!"
                 ]
             ]
             set cell/var cell/text
             show cell
         ]
     ]
]
lo: layout [
     bx: box second span? pane
     text "Example: type '7' into A1, '19' into B1, '=a1 + b1' into C1"
     text "Type 'formula' into any cell to edit an existing formula (C1)."
]
bx/pane: pane
view center-face lo
    


posted by:   Nick     6-May-2014/22:10:15-7:00



You can pick and choose the features you need. This one adds scroll bars to the example above, to accommodate more rows and columns:
    
R E B O L [Title: "Rebocalc" Authors: ["Carl Sassenrath" "edit by Nick Antonaccio"]]
csize: 100x20 max-x: 20 max-y: 50
pane: []
xy: csize / 2 + 1 * 1x0
yx: csize + 1 * 0x1
layout [
     cell: field csize edge none [enter face compute face/para/scroll: 0x0]
     label: text csize white black bold center
]
char: #"A"
repeat x max-x [
     append pane make label [offset: xy text: char]
     set in last pane 'offset xy
     xy: csize + 1 * 1x0 + xy
     char: char + 1
]
repeat y max-y [
     append pane make label [offset: yx text: y size: csize * 1x2 / 2]
     yx: csize + 1 * 0x1 + yx
]
xy: csize * 1x2 / 2 + 1
cells: tail pane
repeat y max-y [
     char: #"A"
     repeat x max-x [
         v: to-word join char y
         set v none
         char: char + 1
         append pane make cell [offset: xy text: none var: v formula: none]
         xy: csize + 1 * 1x0 + xy
     ]
     xy: csize * 1x2 / 2 + 1 + (xy * 0x1)
]
enter: func [face /local data] [
     if empty? face/text [exit]
     set face/var face/text
     data: either face/text/1 = #"=" [next face/text][face/text]
     if error? try [data: load data] [exit]
     if find [
         integer! decimal! money! time! date! tuple! pair!
     ] type?/word :data [set face/var data exit]
     if face/text/1 = #"=" [face/formula: :data]
]
compute: has [blk] [
     unfocus
     foreach cell cells [
         if cell/formula [
             either cell/text = "formula" [
                 cell/text: join "=" form cell/formula
                 show cell return
             ][
                 if error? cell/text: try [do cell/formula] [
                     cell/text: "ERROR!"
                 ]
             ]
             set cell/var cell/text
             show cell
         ]
     ]
]
lo: layout [bx: box second span? pane]
bx/pane: pane
window-size: 800x450
gui: [
     across
     g: box window-size with [pane: lo pane/offset: 0x0]
     scroller as-pair 16 window-size/y [
         g/pane/offset/y: g/size/y - g/pane/size/y * value show g
     ]
     return
     scroller as-pair window-size/x 16 [
         g/pane/offset/x: g/size/x - g/pane/size/x * value show g
     ]
]
view center-face layout gui
    
The nano-sheets article I linked above shows how to add other features, and I added some row/column sum functions to that example, at http://business-programming.com/business_programming.html#section-8.6
    
If you don't like the way any of those features work, you can make your own changes so that they fit your needs exactly. The whole thing is only a few lines of code.
    
The code for Ashley's sheet widget is at https://rebgui.svn.codeplex.com/svn/widgets/sheet.r

posted by:   Nick     7-May-2014/5:36:15-7:00



If you use my tweak above, what are you trying to do which produces bugs or errors, or which crashes the app?

posted by:   Nick     7-May-2014/6:30:16-7:00



I think it's important to point out that each of these pieces of code does exactly what they were intended to do. Just because they don't operate the way you expect at first glance, doesn't mean they're "jam chocked full of bugs". I added the {either cell/text = "formula"} code in my first example above, because, at some point, I also wanted to be able to secure the formula included in a cell, and still have the option to edit it later. That feature required 3 lines of code.
    
Carl's original example code is minimal, and that simplicity allows it to be quickly modifiable. You can do whatever you want with it. Because of that simplicity, the intended use you complained about earlier is simple to implement, with only the 3 lines I added. The fact that your desired implementation didn't match the structure of the existing code isn't a 'bug' or an 'error' - the existing code just wasn't designed to operate the way you expected. Read the article and dive into the code, and you should be able to tweak it however you want.
    
PS - about it not being 'powerful'. I've used this script to download data from a file stored on a web server, so that a client was able to work with live variable values, and see changes reflected immediately. Adding that feature required 1 line of 'load code. Packaging the script and the Rebol interpreter with iexpress and then emailing the entire 500k package took about a minute. Saving time and energy in that way has been extremely powerful in my life.

posted by:   Nick     7-May-2014/7:05:36-7:00



PPS - the only reason I even used the spreadsheet in the client case above was that user was familiar with spreadsheet operations (that's a problem based on the short history of computing in our culture). If that client had instead been more familiar with the Rebol paradigm, instead of the spreadsheet paradigm (which he was only because of the way computing history has progressed), the solution would have been even simpler. Most of the problems in modern computing are a result of the crazy mess of paradigms and complex tooling which have evolved during its short history.

posted by:   Nick     7-May-2014/7:21:48-7:00



Hi,
The tweak you put in is a HUGE improvement. You can press enter and don't even have to enter the do command and it seems to work well enough to trust a spreadsheet savvy user with. I wanted to have 3 separate views of 3 different spreadsheets simultaneously showing data. You can do this in excel using OLE windows but they are slow and clumsy and you lose a lot of space with the scroll bars and other overhead. I wanted to maybe do this in rebol and possibly I will be able to now.
Thanks so much.

posted by:   John     7-May-2014/18:44:03-7:00



Hi,
Tell me what you think of this observation - it takes a few seconds to initialize a rebol array of 65536 by 256 elements whereas the rebol spreadsheet blows up with 10,000 or so elements and takes forever to initialize and display. It seems to me that the spreadsheet display should just be 1 screen worth of cells and the array could be mapped to the screen and then scrolled though. This seems like it would be a far better way to design this.

posted by:   John     8-May-2014/0:49:32-7:00



In the end, yes, the real answer for any large grid display is generally to render only the cells which are displayed on screen. Redraw only the displayed cells whenever a scroll, jump to cell, or other event alters the screen display, and don't render any off-screen cells.
    
Another quick thought is that REBOL's 'list widget tends to perform better than GUI tables which are manually built from arrays of widgets. Separating the display from the language parsing and field indexing (i.e., the naming of cells a1 b2 etc), I expect would probably work better for medium sized screens (although 10000 cells may still be sluggish).
    
Take a look at http://business-programming.com/business_programming.html#section-17.21 to get a sense of the difference between the 'list widget and rendering 'tables' of separate fields.
    
For example, this table displays 100000 rows X 3 columns without any delay:
    
R E B O L []
x: copy []
repeat i 100000 [append/only x reduce [i i * 7 random "asdfghjkl"]]
slider-pos: 0
view layout [
     across space 0
     the-list: list 255x400 [
         across space 0x0
         text 75 purple
         text 100 bold [editor face/text]
         text 80 red italic
         return box green 255x1
     ] supply [
         count: count + slider-pos
         if none? q: pick x count [face/text: none exit]
         face/text: pick q index
     ]
     scroller 16x400 [
         slider-pos: (length? x) * value
         show the-list
     ]
     key keycode [up] [
         slider-pos: slider-pos - 10
         show the-list
     ]
     key keycode [down] [
         slider-pos: slider-pos + 10
         show the-list
     ]
]

posted by:   Nick     8-May-2014/12:49:34-7:00



In fact, I tried the above code with 1 million rows, 3 columns, and there's still absolutely no delay (once the data block is created). UPDATE: I tried it with 10 million rows, and the display still had no delay.
    
You can explore Carl's code for the 'list widget:
    
editor mold :svv/vid-styles/list

posted by:   Nick     8-May-2014/12:56:02-7:00



As you see in the example above, you can attach action code to every displayed widget in a 'list, and widgets can be of any VID style type. Write a little parser to evaluate the spreadsheet formula syntax you want, combine that with a 'compute function, and you should be able to use the 'list style to create a full blown spreadsheet app with very good performance even with large data sets.

posted by:   Nick     8-May-2014/13:16:01-7:00



Hi,
Ok. I will look over what you have shown here. Also I was thinking that perhaps a 3rd dimension 65536,256,1 could be used to store the formatting and other data for the rows and columns. Just a hasty thought.
Thx again for your generosity.


posted by:   John     8-May-2014/13:38:37-7:00



Here are some more 'list examples and documentation:
    
http://www.compkarori.com/vanilla/display/list+examples

posted by:   Nick     9-May-2014/19:54:54-7:00



Nick, As a learning tool (and, in general, a showcase for a language) a REAL working spreadsheet to tinker with is perhaps without peer.
(1) People can relate to it and yet are still in awe of its usefulness and the mystery of how it could be implemented, having used bigger brothers for decades.
    
(2) spreadsheets used to be called (and I would argue still are) the penultimate microcomputer application; visicalc/supercalc/lotus intrigued and justified businesses buying computers in a way space invaders never could. They were the killer app which really showed micros as a step BEYOND minicomputers.
(3) I remember Alan Kay (yeah, that guy) in a keynote speech, back in probably 1982, making the case for a really programmable spreadsheet as a meta language.
(4) You seem kind of down on spreadsheets as being overused. Well, maybe they are but when a kludge CAN be pulled off in a spreadsheet it probably has an average 1000 to 1 payoff in terms of time invested vs. ANY other generic approach to problem solving.
    
Anyway, I think John (if I read him correctly) has a BIG point. You want to blow serious people away, show them a REAL spreadsheet in rebol and let them play with it. Tinkering is arguably the best way to learn the innards of anything..it makes a contraption approachable. The problem with putting out a broken toy of a spreadsheet to wow people with rebol is it leaves some of wondering if the problem with the endless crashes and seizures is due to the simplicity of the app or the inadequacy of the implementation language. Once upon a time "Fourth Generation" programming languages were all the rage as people looked for a more effective way to develop specialized applications. Fourth Gen languages became a joke, though, as they could NEVER seemingly be used to create a complete, solid application: only a caricature of a real application.
    
In truth there remain, to this day, a huge swath of business and organizational / data manipulation /visualization problems where hacking something out in a spreadsheet *IS* the SMARTEST way to approach a good enough answer.
    
When I threw out my earlier question about the spreadsheet app it was because I thought learning rebol by trying to extend a spreadsheet application an iota at a time was a near perfect choice for me (knowing my limited time and attention span and my motivation strategy). Input error trapping is arguably the FIRST thing an application (and a language being promoted to build said application) should be able to master. That Forth never could seemingly get beyond the trivial to the hardened app was, imo, the main reason it never was taken very seriously by very many. It was just too breakable when you tried to scale. Applications built in it tended to be "toy" apps and seldom anything more.
    
IMHO, of course.

posted by:   steve     16-May-2014/4:53:39-7:00



Steve,
    
The error-prone nature of copying and pasting rows and columns of data, overwriting formulas, improperly referencing cells, relying on the single-user data entry paradigm, as well as the visual grid paradigm, leads to common and well documented problems. Try this search in Google: "how spreadsheets caused worst financial...".
    
Spreadsheets are a great invention, and they've enabled several generations of computer users to do powerfully useful things with computers. The trouble comes when spreadsheets are pushed beyond their intended use, and that happens constantly because they're often the only general purpose computing tool which many users ever learn to use ('when all you have is a hammer...').
    
From my perspective, the very point of Rebol is to provide a small and simple tool which is versatile and powerful in ways that spreadsheets can't be. It's obviously a different paradigm: language as opposed to a visual tool. Building a spreadsheet in Rebol seems like a nice idea because it demonstrates how to create a well known and versatile type of application, but I think that's a confusing message. I'd suggest that a better way to demonstrate to users should be more along the lines of:
    
     1) Look at the capabilities and problems which you may have encountered using spreadsheets.
    
     2) Here's how you do the same thing with Rebol code, and here's how you improve your Rebol app so that it performs better than the speadsheet model (for the purpose which you use a spreadsheet - you don't need to create a better generalized spreadsheet app - just a better app specifically suited to the purpose).
    
     3) And here are a bunch of other useful things you can accomplish easily once you understand how to use this general purpose tool, which aren't possible or practical with spreadsheets.
    
That was one of the points of writing http://business-programming.com . If people learn to use Rebol with the same intent as they do spreadsheets and other 'user' tools, the end result is more productive, and the general capabilities of that user population are far greater. And I do believe that Rebol is easy enough for 'users' to learn - certainly at least for the purposes which spreadsheets are effective - and the potential scope of accomplishment is much wider than that which can be accomplished using spreadsheets. For example, with Rebol you can create a forum like the one we're using :) You can't do that well with spreadsheets. Merchants' Village couldn't have been run with spreadsheets, etc. That's the up side to learning Rebol - the fact that it's easy enough for average 'power' users to learn (in the same ballpark as spreadsheets for those limited purposes) is what makes it truly unique among language tools.

posted by:   Nick     16-May-2014/19:39:38-7:00



Perhaps a good article might be "How to replace your spreadsheet with Rebol code"

posted by:   Nick     16-May-2014/19:43:04-7:00



Maybe a simple initial example with the idea of a worksheet in mind might be something like:
    
R E B O L []
    
sum: func [fld] [attempt [s: 0 foreach num to-block copy fld/text [s: s + (to-decimal num)] s]]
average: func [fld] [attempt [(sum fld) / (length? to-block copy fld/text)]]
maxi: func [fld] [attempt [first maximum-of to-block copy fld/text]]
compound: does [attempt [((1 + (to-decimal rt/text)) ** to-integer yrs/text) * to-decimal p/text]]
    
; Fill columns with random values:
    
random/seed now
x: copy y: copy z: copy ""
loop 10000 [
     append x join random 10000 newline
     append y join random 10000 newline
     append z join random 10000 newline
]
    
view center-face layout [
     style col area 80x350
     style fld field 80
     style txt text 80
     across
     txt "Sum:"     txt "Average:" txt "Maximum:" return
     a: col form x b: col form y    c: col form z    return
     txt "Sum:"     txt "Average:" txt "Maximum:" return
     fld [face/text: sum a show face]
     fld [face/text: average b show face]    
     fld [face/text: maxi c show face]             return
     txt                                            return
     txt txt "Principal:" p: fld "10000"         return
     txt txt "Years:"     yrs: fld "10"            return
     txt txt "Rate:"     rt: fld ".07"         return
     txt txt "TOTAL:" fld [face/text: compound show face]
]

posted by:   Nick     17-May-2014/1:47:18-7:00



A next step may be to read the data values from a Rebol CGI app running on a web server, make the results available to multiple users on your local network (via a TCP connection), send emails to a group of people whenever a set of calculations satisfies a given set of conditions, etc. Doing those things is simple, simple, simple with Rebol. Not so with spreadsheets.

posted by:   Nick     17-May-2014/2:27:58-7:00



Here, I added a sort function, improved the compound function to work with any GUI fields, and generated 50000 rows of random data for each column. The actual worksheet code in this example is less than 25 lines. It works quickly, and I can explain every single thing about how the application works, to a new Reboler, in just a few minutes:
    
R E B O L []
    
sum: func [fld] [attempt [s: 0 foreach num to-block copy fld/text [s: s + (to-decimal num)] s]]
average: func [fld] [attempt [(sum fld) / (length? to-block copy fld/text)]]
maxi: func [fld] [attempt [first maximum-of to-block copy fld/text]]
compound: func [f1 f2 f3] [attempt [((1 + to-decimal f3/text) ** to-integer f2/text) * to-decimal f1/text]]
srt: func [fld] [st: copy "" foreach i sort to-block copy fld/text [insert tail st join i "^/"] head st]
    
; Fill columns with random values:
    
random/seed now
x: copy y: copy z: copy ""
loop 50000 [
     insert tail x join random 10000 newline
     insert tail y join random 10000 newline
     insert tail z join random 10000 newline
]
    
view center-face layout [
     style col area 80x350
     style fld field 80
     style txt text 80
     across
     txt "Sum:"     txt "Average:" txt "Maximum:" return
     a: col form x b: col form y    c: col form z    return
     txt "Sum:"     txt "Average:" txt "Maximum:" return
     fld [face/text: sum a show face]
     fld [face/text: average b show face]    
     fld [face/text: maxi c show face]                return
     btn "Sort" [set-face a srt a]             return
     txt txt "Principal:" p: fld "10000"         return
     txt txt "Years:"     yrs: fld "10"             return
     txt txt "Rate:"     rt: fld ".07"             return
     txt txt "TOTAL:" fld [face/text: compound p yrs rt show face]
]

posted by:   Nick     17-May-2014/10:07:16-7:00



You can implement any error handling you want:
    
sum: func [fld] [
     s: 0
     foreach num to-block copy fld/text [
         if error? try [
             s: s + (to-decimal num)
         ] [
             alert err: join "Error: " num
             return err
         ]
     ]
     s
]

posted by:   Nick     17-May-2014/10:20:53-7:00



This may be a nice addition to http://re-bol.com/starting_computer_programming_with_rebol.html

posted by:   Nick     17-May-2014/10:35:16-7:00



Here are a few more tweaks, and this may be easier to read. Click column headers to sort ascending or descending, error handling in average function, some changes to display:
    
R E B O L [title: "Work Sheet"]
random/seed now
x: copy y: copy z: copy ""
loop 50000 [
     insert tail x join random 50000 newline
     insert tail y join random 50000 newline
     insert tail z join random 50000 newline
]
sum: func [fld] [
     s: 0    
     foreach num to-block copy fld/text [
         if error? try [
             s: s + (to-decimal num)
         ] [
             return join "Error: " num
         ]
     ]
     s
]
average: func [fld] [
     attempt [
         the-sum: sum fld
         if attempt [find the-sum "error"] [return the-sum]
         the-sum / (length? to-block copy fld/text)
     ]
]
maxi: func [fld] [
     attempt [
         first maximum-of to-block copy fld/text
     ]
]
compound: func [f1 f2 f3] [
     attempt [
         (
             (1 + to-decimal f3/text) ** to-integer f2/text
         ) * to-decimal f1/text
     ]
]
ascend: false
srt: func [fld] [
     st: copy ""
     ascend: not ascend
     data: to-block copy fld/text
     sorted: copy either ascend [sort data] [sort/reverse data]
     foreach i sorted [insert tail st join i "^/"]
     head st
]
view center-face layout [
     style col area 100x250
     style fld field 100
     style txt text 100
     across
     txt "Sum:"     [set-face a srt a]
     txt "Average:" [set-face b srt b]
     txt "Maximum:" [set-face c srt c]                 return
     a: col form x b: col form y     c: col form z    return
     txt "SUM:"     txt "AVERAGE:"    txt "MAXIMUM:" return
     fld [face/text: sum a     show face]
     fld [face/text: average b show face]    
     fld [face/text: maxi c     show face]             return
     txt                                                return
     txt txt "Principal:" p: fld "10000"             return
     txt txt "Years:"     yrs: fld "10"                return
     txt txt "Rate:"     rt: fld ".07"             return
     txt txt "TOTAL:" fld [face/text: compound p yrs rt show face]
]

posted by:   NicK     17-May-2014/14:17:04-7:00



Here I added some buttons to save and load your work:
    
R E B O L [title: "Work Sheet"]
random/seed now
x: copy y: copy z: copy ""
loop 50000 [
     insert tail x join random 50000 newline
     insert tail y join random 50000 newline
     insert tail z join random 50000 newline
]
sum: func [fld] [
     s: 0    
     foreach num to-block copy fld/text [
         if error? try [
             s: s + (to-decimal num)
         ] [
             return join "Error: " num
         ]
     ]
     s
]
average: func [fld] [
     attempt [
         the-sum: sum fld
         if attempt [find the-sum "error"] [return the-sum]
         the-sum / (length? to-block copy fld/text)
     ]
]
maxi: func [fld] [
     attempt [
         first maximum-of to-block copy fld/text
     ]
]
compound: func [f1 f2 f3] [
     attempt [
         (
             (1 + to-decimal f3/text) ** to-integer f2/text
         ) * to-decimal f1/text
     ]
]
ascend: false
srt: func [fld] [
     st: copy ""
     ascend: not ascend
     data: to-block copy fld/text
     sorted: copy either ascend [sort data] [sort/reverse data]
     foreach i sorted [insert tail st join i "^/"]
     head st
]
view center-face gui: layout [
     style col area 100x250
     style fld field 100
     style txt text 100
     across
     txt "Sum:"     [set-face a srt a]
     txt "Average:" [set-face b srt b]
     txt "Maximum:" [set-face c srt c]                 return
     a: col form x b: col form y     c: col form z    return
     txt "SUM:"     txt "AVERAGE:"    txt "MAXIMUM:" return
     fld [face/text: sum a     show face]
     fld [face/text: average b show face]    
     fld [face/text: maxi c     show face]             return
     txt                                                return
     txt txt "Principal:" p: fld "10000"             return
     txt txt "Years:"     yrs: fld "10"                return
     txt txt "Rate:"     rt: fld ".07"             return
     txt txt "TOTAL:" fld [face/text: compound p yrs rt show face] return
     txt txt btn "Save" [
         write %worksheet.dat rejoin [
             mold a/text mold b/text mold c/text
             mold p/text mold yrs/text mold rt/text
         ]
     ]
     btn "Load" [
         if error? try [dat: load %worksheet.dat] [return]
         set-face a dat/1 set-face b dat/2 set-face c dat/3
         p/text: dat/4 yrs/text: dat/5 rt/text: dat/6
         show gui
     ]
]


posted by:   Nick     17-May-2014/14:34:56-7:00



I added the 'worksheet' example to the tutorial at http://re-bol.com/starting_computer_programming_with_rebol.html

posted by:   Nick     20-May-2014/9:13:47-7:00



I wonder if I could interject a question about that nano-sheets article.
    
I read it, and looked at the code for the simpler sample, and generally understand it except for one thing. I am confused about why the generated layout code has items like "cell with [var: 'A1]" and if that is related to this code:
    
cells: copy []
foreach face lay/pane [
    if 'cell = face/style [    append cells face]
]
    
where all the cell objects are collected into the "cells" block.
    
I assumed that the "cell with [var: 'A1]" code exists to give the cell a name, an alternative to {cell "A1"} which one would code if one were making the layout by hand instead of generating it.
    
I assumed that gathering the cells into the "cells" block is done so that one can iterate through the block called "cells" with a foreach loop.
    
However, the confusing point is, each "cell" face is a big thing, and doesn't collecting them into the "cells" block make them exist in two places, namely, the "cells" block and the "lay" layout? And if they exist in two places, how does doing stuff to a cell in the "cells" block, and then showing it, make it change in the "lay" layout where it is visible on the screen?    
    
Thank you.

posted by:   Steven White     20-May-2014/16:58:14-7:00



I got up and walked around a bit, and I think I might know the answer to my own question, and might have driven home in my head a key point about REBOL. The "append cells face" is not an instruction to take a copy of one of the cell objects from the layout and append it to the end of the "cells" block, thus making the object exist in two places. It is only my third-generation programming language bias that makes me assume that is what is happening. The "cells" object does not contain copies of all the cell faces from the layout. The "cells" block is a block containing the same faces as are found in the layout. They probably are references, but that might not even matter. It can be "black-boxed" so to speak. The cell faces are assembled in the "cells" block, and they exist in the layout, and they are the same, and that's that. Making a block like that is just something that REBOL can do. REBOL does not have to match some idea in my head of what a programming language is supposed to do. That kind of thinking probably is what has made REBOL so hard for me to grasp over the years.

posted by:   Steven White     20-May-2014/17:23:49-7:00