Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


Nano-Sheets: A Small But Mighty Spreadsheet Engine in REBOL  : Page 3

Even in today's big-computing environment, not everything useful has to be big. This article shows you how to build a tiny and basic—but powerful—GUI spreadsheet engine in REBOL, using fewer than 1500 bytes of code.




Application Security Testing: An Integral Part of DevOps

Analyzing the Code
The Nano-Sheets code begins with a few definitions that control the size of the cells and the overall sheet itself. The cell size is in pixels; the sheet size in cells. They are both REBOL pair! values.

csize: 100x20 size: 8x16

There are a few helper functions to make things easier and clearer in the main generation loop. The meaning of col-lbl and cell-name should be pretty obvious, but mk-var might not be; it creates a variable name dynamically so you don't have to declare variables statically for every cell.

col-lbl: func [col] [form to char! 64 + col] cell-name: func [x y] [join col-lbl x y] mk-var: func [x y] [to lit-word! cell-name x y]

The sheet definition starts out with some static elements that set the spacing and layout orientation, and then define a couple of styles used in the UI, much as you might use CSS to define styles for use in an HTML document.

sheet: copy [ space 1x1 across style cell field csize edge none with [formula: none] [enter face compute face/para/scroll: 0x0] style label text csize white black bold center ]

Next is the real magic. The two nested loops add elements to the sheet layout spec. If you've ever written a CGI app to dynamically generate a table in HTML, you'll recognize that this is the same concept. The big difference is that these items will become active cells when they are rendered, and will be bound to a variable that represents them for use in formulas.

repeat y 1 + size/y [ repend sheet ['label (csize / 2x1) either 1 = y [""] [form y - 1]] repeat x size/x [ append sheet compose/deep either 1 = y [[label (col-lbl x)]] [ [cell with [var: (mk-var x y - 1)]] ] ] append sheet 'return ]

Setting Cell Values and Triggering Recalculations
The spreadsheet calls the enter function when a cell loses focus. Its job is to evaluate what a user entered, decide if it's a formula, and set the value for the variable bound to the cell. Formulas, as in other spreadsheets, are identified by a leading equal sign (=). The spreadsheet coerces text entered in the cell to the most appropriate internal data type, so calculations operate in an intuitive way (e.g. $100 * 3 = $300).

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] ]

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date