From robert@slag.capmkt.com Fri Aug 15 00:59:51 1997 Date: Thu, 14 Aug 1997 21:59:21 -0700 From: Robert Lum MIME-Version: 1.0 To: Mark Andrew Austin Subject: Re: Spreadsheet Program in Engineering Class. Content-Type: multipart/mixed; boundary="------------167EB0E72781E494446B9B3D" Content-Length: 31500 This is a multi-part message in MIME format. --------------167EB0E72781E494446B9B3D Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Mark Andrew Austin wrote: > This semester I am planning to teach Java to senior > level undergraduate engineering students at the > University of Maryland, College Park. I was wondering > if I could use the source code to your spreadsheet > program as a good example of what's possible, and for > groups of students to extend it's functionality. Dear Mark, This is interesting. From your person web page it seems that you graduated from UC Berkeley two years before I entered. Not only that, but you are also from New Zealand. Yes, you may use the spreadsheet's source code for your class and it, with a small html driver page have been included as attachments to this letter. I should add that the source code was never intended for public consumption, and although correct, does not do justice to the best object design principles. On another but related topic. Would you be interested in formalising a public domain spreadsheet project? Your students could add their accumulated efforts over the years to enhance the spreadsheet, be able to attach their names to a public domain project and learn about large project management. This would require a rewrite of the basic spreadsheet on my part to be more modular but can be done and something I was planning to do in the future anyway. Robert --------------167EB0E72781E494446B9B3D Content-Type: text/html; charset=us-ascii; name="spreadsheet.html" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="spreadsheet.html" Robert's Online Spreadsheet!

Robert's Online Spreadsheet!

Cell syntax

Mathematical functions

Comparision functions

Boolean functions

Conditional functions

Written by Dr. Robert Lum at robertl@intrepid.com
--------------167EB0E72781E494446B9B3D Content-Type: text/plain; charset=us-ascii; name="spreadsheet.java" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="spreadsheet.java" /* * @(#)SpreadSheet.java 1.5 96/12/06 * * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved. * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */ /* * Copyright (c) 1995-1997 Alef Corporation. All Rights Reserved. * * Alef grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Alef. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. ALEF AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL ALEF OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF ALEF HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */ import java.applet.*; import java.awt.*; import java.io.*; import java.net.*; import java.util.*; public class spreadsheet extends Applet { Font inputFont; Color cellColor; Color inputColor; int cellWidth; int offset = 45; int cellHeight = 15; int rowLabelWidth = 17; int rows; int columns; int selectedRow = -1; int selectedColumn = -1; InputField inputArea; Cell cells[][]; Cell current = null; Button clear_sheet; public synchronized void init() { String rs; cellColor = Color.white; inputColor = new Color(100, 100, 225); inputFont = new Font("Courier", Font.BOLD, 12); rs = getParameter("rows"); if (rs == null) rows = 9; else rows = Integer.parseInt(rs); if(rows < 1) rows = 9; if(99 < rows) rows = 99; rs = getParameter("cols"); if (rs == null) columns = 5; else columns = Integer.parseInt(rs); if(columns < 1) columns = 5; if(26 < columns) columns = 26; cellWidth = (size().width - rowLabelWidth) / columns; cells = new Cell[rows][columns]; char l[] = new char[1]; for(int i = 0; i < rows; i++) for(int j = 0; j < columns; j++) { cells[i][j] = new Cell(this, Color.lightGray, Color.black, cellColor, cellWidth - 2, cellHeight - 2); l[0] = (char)((int)'a' + j); rs = getParameter("" + new String(l) + (i+1)); if(rs != null) cells[i][j].setValue(rs); } inputArea = new InputField(null, this, columns * cellWidth + rowLabelWidth, cellHeight - 1, inputColor, Color.white); Button clear = new Button("Clear"); setLayout(new FlowLayout(FlowLayout.LEFT)); add(clear); resize(columns * cellWidth + rowLabelWidth, ((rows + 1) * cellHeight) + cellHeight + offset); } public void stop() { } public void start() { } public void destroy() { } public void setCurrentValue(String val) { if(selectedRow < 0 || rows <= selectedRow || selectedColumn < 0 || columns <= selectedColumn) return; cells[selectedRow][selectedColumn].setValue(val); repaint(); } public void update(Graphics g) { int i, j; int cx, cy; char l[] = new char[1]; g.setColor(inputColor); g.setFont(inputFont); g.fillRect(0, offset, columns * cellWidth + rowLabelWidth, cellHeight); for(i = 0; i < rows + 1; i++) { cy = (i + 2) * cellHeight + offset; g.setColor(getBackground()); g.draw3DRect(0, cy, columns * cellWidth + rowLabelWidth, 1, true); if(0 < i) { g.setColor(Color.red); g.drawString("" + i, 2, cy - 3); } } for(i = 0; i < columns + 1; i++) { cx = i * cellWidth; g.setColor(getBackground()); g.draw3DRect(cx + rowLabelWidth, cellHeight + offset, 1, (rows + 1) * cellHeight, true); if(i < columns) { g.setColor(Color.red); l[0] = (char)((int)'a' + i); g.drawString(new String(l), cx + rowLabelWidth + (cellWidth / 2), 2 * cellHeight - 3 + offset); } } for(i = 0; i < rows; i++) for(j = 0; j < columns; j++) { cx = (j * cellWidth) + 2 + rowLabelWidth; cy = ((i+2) * cellHeight) + 2 + offset; if(cells[i][j] != null && cells[i][j].needRedisplay) cells[i][j].paint(g, cx, cy); } if(inputArea != null) inputArea.paint(g, 1, 1 + offset); } public void recalculate() { for(int i = 0; i < rows; i++) for(int j = 0; j < columns; j++) if(cells[i][j] != null && cells[i][j].type == Cell.FORMULA) { cells[i][j].setRawValue(evaluateFormula(cells[i][j].parseRoot)); cells[i][j].needRedisplay = true; } repaint(); } public double evaluateFormula(Node n) { double val = 0.0; Node temp; if(n == null) return val; switch (n.type) { case Node.OP: case Node.PRE: val = evaluateFormula(n.left); switch (n.op) { case '+': val += evaluateFormula(n.right); break; case '*': val *= evaluateFormula(n.right); break; case '-': temp = n.right; while(temp != null && temp.type == Node.OP && temp.op == '-') { val -= evaluateFormula(temp.left); temp = temp.right; } if(temp != null && temp.type == Node.OP && temp.op == '+') { val -= evaluateFormula(temp.left); val += evaluateFormula(temp.right); } else val -= evaluateFormula(temp); break; case '/': temp = n.right; while(temp != null && temp.type == Node.OP && temp.op == '/') { val /= evaluateFormula(temp.left); temp = temp.right; } if(temp != null && temp.type == Node.OP && temp.op == '*') { val /= evaluateFormula(temp.left); val *= evaluateFormula(temp.right); } else val /= evaluateFormula(temp); break; } break; case Node.VALUE: return n.value; case Node.CELL: if(0 <= n.row && n.row < rows && 0 <= n.column && n.column < columns && cells[n.row][n.column] != null) return cells[n.row][n.column].value; case Node.FUNC: if(n.func.compareTo("Abs") == 0) if(1 <= n.args.size()) val = Math.abs(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Acos") == 0) if(1 <= n.args.size()) val = Math.acos(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Asin") == 0) if(1 <= n.args.size()) val = Math.asin(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Atan") == 0) if(1 <= n.args.size()) val = Math.atan(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Ceil") == 0) if(1 <= n.args.size()) val = Math.ceil(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Cos") == 0) if(1 <= n.args.size()) val = Math.cos(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Exp") == 0) if(1 <= n.args.size()) val = Math.exp(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Floor") == 0) if(1 <= n.args.size()) val = Math.floor(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Log") == 0) if(1 <= n.args.size()) val = Math.log(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Max") == 0) if(2 <= n.args.size()) val = Math.max(evaluateFormula((Node)n.args.elementAt(0)), evaluateFormula((Node)n.args.elementAt(1))); if(n.func.compareTo("Min") == 0) if(2 <= n.args.size()) val = Math.min(evaluateFormula((Node)n.args.elementAt(0)), evaluateFormula((Node)n.args.elementAt(1))); if(n.func.compareTo("Pow") == 0) if(2 <= n.args.size()) val = Math.pow(evaluateFormula((Node)n.args.elementAt(0)), evaluateFormula((Node)n.args.elementAt(1))); if(n.func.compareTo("Random") == 0) val = Math.random(); if(n.func.compareTo("Round") == 0) if(1 <= n.args.size()) val = Math.round(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Sin") == 0) if(1 <= n.args.size()) val = Math.sin(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Sqrt") == 0) if(1 <= n.args.size()) val = Math.sqrt(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Tan") == 0) if(1 <= n.args.size()) val = Math.tan(evaluateFormula((Node)n.args.elementAt(0))); if(n.func.compareTo("Lt") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) < evaluateFormula((Node)n.args.elementAt(1))) val = 1.0; if(n.func.compareTo("Le") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) <= evaluateFormula((Node)n.args.elementAt(1))) val = 1.0; if(n.func.compareTo("Gt") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) > evaluateFormula((Node)n.args.elementAt(1))) val = 1.0; if(n.func.compareTo("Ge") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) >= evaluateFormula((Node)n.args.elementAt(1))) val = 1.0; if(n.func.compareTo("Eq") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) == evaluateFormula((Node)n.args.elementAt(1))) val = 1.0; if(n.func.compareTo("Ne") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) != evaluateFormula((Node)n.args.elementAt(1))) val = 1.0; if(n.func.compareTo("And") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) != 0.0 && evaluateFormula((Node)n.args.elementAt(1)) != 0.0) val = 1.0; if(n.func.compareTo("Or") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) != 0 || evaluateFormula((Node)n.args.elementAt(1)) != 0) val = 1.0; if(n.func.compareTo("Not") == 0) if(1 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) == 0) val = 1.0; if(n.func.compareTo("If") == 0) if(2 <= n.args.size()) if(evaluateFormula((Node)n.args.elementAt(0)) != 0) val = evaluateFormula((Node)n.args.elementAt(1)); else if(3 <= n.args.size()) val = evaluateFormula((Node)n.args.elementAt(2)); } return val; } public synchronized void paint(Graphics g) { int i, j; int cx, cy; char l[] = new char[1]; g.setColor(inputColor); g.setFont(inputFont); g.fillRect(0, offset, columns * cellWidth + rowLabelWidth, cellHeight); for(i = 0; i < rows + 1; i++) { cy = (i + 2) * cellHeight + offset; g.setColor(getBackground()); g.draw3DRect(0, cy, columns * cellWidth + rowLabelWidth, 1, true); if(0 < i) { g.setColor(Color.red); g.drawString("" + i, 2, cy - 3); } } for(i = 0; i < columns + 1; i++) { cx = i * cellWidth; g.setColor(getBackground()); g.draw3DRect(cx + rowLabelWidth, cellHeight + offset, 1, (rows + 1) * cellHeight, true); if(i < columns) { g.setColor(Color.red); l[0] = (char)((int)'a' + i); g.drawString(new String(l), cx + rowLabelWidth + (cellWidth / 2), 2 * cellHeight - 3 + offset); } } for(i = 0; i < rows; i++) for(j = 0; j < columns; j++) { cx = (j * cellWidth) + 2 + rowLabelWidth; cy = ((i+2) * cellHeight) + 2 + offset; if(cells[i][j] != null) cells[i][j].paint(g, cx, cy); } inputArea.paint(g, 1, 1 + offset); } public boolean mouseDown(Event evt, int x, int y) { int newselectedRow; int newselectedColumn; if(y < 2 * cellHeight + offset) newselectedRow = -1; else newselectedRow = ((y - 2 * cellHeight - offset) / cellHeight); if(x < rowLabelWidth) newselectedColumn = -1; else newselectedColumn = (x - rowLabelWidth) / cellWidth; if(0 <= newselectedRow && newselectedRow < rows && 0 <= newselectedColumn && newselectedColumn < columns) { selectedRow = newselectedRow; selectedColumn = newselectedColumn; if(current != null) current.deselect(); current = cells[selectedRow][selectedColumn]; inputArea.setText(new String(current.printString)); current.select(); requestFocus(); } repaint(); return true; } public boolean keyDown(Event evt, int key) { inputArea.keyDown(key); if(key == 10) { selectedRow = -1; selectedColumn = -1; if(current != null) current.deselect(); inputArea.setText(""); } return true; } public boolean action(Event evt, Object obj) { if (evt.target instanceof Button) { String label = (String)obj; if (label.equals("Clear")) { if(current != null) current.deselect(); for(int i = 0; i < rows; i++) for(int j = 0; j < columns; j++) cells[i][j].setValue(""); selectedRow = -1; selectedColumn = -1; inputArea.setText(""); repaint(); } return true; } if (evt.target instanceof TextField) { System.out.println("Name"); return true; } return false; } public String getAppletInfo() { return("Robert's Online SpreadSheet! by Dr. Robert Lum"); } } class Cell { public static final int LABEL = 0; public static final int FORMULA = 1; Node parseRoot; boolean needRedisplay; boolean selected = false; int type = Cell.LABEL; String valueString = ""; String printString = ""; double value = 0.0; Color bgColor; Color fgColor; Color highlightColor; int width; int height; spreadsheet app; public Cell(spreadsheet app, Color bgColor, Color fgColor, Color highlightColor, int width, int height) { this.app = app; this.bgColor = bgColor; this.fgColor = fgColor; this.highlightColor = highlightColor; this.width = width; this.height = height; needRedisplay = true; } public void setRawValue(double f) { valueString = new Double(f).toString(); value = f; } public String parseFormula(String formula, Node node) { char op; Node right; Node left; if(formula == null || formula.length() == 0) return formula; String restformula = new String(formula).trim(); restformula = parseAddend(restformula, node); if(restformula == null || restformula.length() == 0) return restformula; switch(op = restformula.charAt(0)) { case '+': case '-': restformula = parseFormula(restformula.substring(1), right = new Node()); left = new Node(node); node.type = Node.OP; node.op = op; node.left = left; node.right = right; break; default: break; } return restformula.trim(); } public String parseAddend(String formula, Node node) { char op; Node right; Node left; if(formula == null || formula.length() == 0) return formula; String restformula = new String(formula).trim(); restformula = parseMultiplicand(restformula, node); if(restformula == null || restformula.length() == 0) return restformula; switch(op = restformula.charAt(0)) { case '*': case '/': restformula = parseAddend(restformula.substring(1), right = new Node()); left = new Node(node); node.type = Node.OP; node.op = op; node.left = left; node.right = right; break; default: break; } return restformula.trim(); } public String parseMultiplicand(String formula, Node node) { if(formula == null || formula.length() == 0) return formula; String restformula = new String(formula).trim(); char c = restformula.charAt(0); if('0' <= c && c <= '9') { int i; double value; boolean dot = true; try { value = Double.valueOf(restformula).doubleValue(); } catch (NumberFormatException e) { value = 0.0; }; for(i = 0; i < restformula.length(); i++) { c = restformula.charAt(i); if('0' <= c && c <= '9') continue; if(c == '.' && dot) { dot = false; continue; } break; } node.type = Node.VALUE; node.value = value; restformula = restformula.substring(i).trim(); return restformula; } if('a' <= c && c <= 'z') { int i; int row; int column = c - 'a'; restformula = restformula.substring(1); row = 0; for(i = 0; i < restformula.length(); i++) { c = restformula.charAt(i); if('0' <= c && c <= '9') { row = 10 * row + c - '0'; continue; } break; } node.row = row - 1; node.column = column; node.type = Node.CELL; restformula = restformula.substring(i).trim(); return restformula; } if('A' <= c && c <= 'Z') { Node temp; int i = restformula.indexOf('('); if(i == -1) return restformula; node.type = Node.FUNC; node.func = new String(restformula.substring(0, i)); node.args = new Vector(); restformula = restformula.substring(i + 1); while(restformula != null && restformula.length() != 0) { restformula = parseFormula(restformula, temp = new Node()); node.args.addElement(temp); if(restformula == null || restformula.length() == 0) break; if(restformula.charAt(0) == ',') { restformula = restformula.substring(1).trim(); continue; } if(restformula.charAt(0) == ')') restformula = restformula.substring(1).trim(); break; } return restformula; } if(c == '(') { restformula = parseFormula(restformula.substring(1), node); if(restformula == null || restformula.length() == 0) return restformula; if(restformula.charAt(0) == ')') restformula = restformula.substring(1).trim(); if(node.type == Node.OP) node.type = Node.PRE; return restformula; } return restformula; } public void setValue(String s) { needRedisplay = true; printString = new String(s); if(s != null && s.length() != 0) if(s.charAt(0) == '=') { type = Cell.FORMULA; parseFormula(s.substring(1), parseRoot = new Node()); value = 0.0; } else { type = Cell.LABEL; try { value = Double.valueOf(s).doubleValue(); } catch(NumberFormatException e) { value = 0.0; }; } else { type = Cell.LABEL; value = 0.0; } app.recalculate(); } public void select() { selected = true; needRedisplay = true; app.repaint(); } public void deselect() { selected = false; needRedisplay = true; app.repaint(); } public void paint(Graphics g, int x, int y) { int char_count = width / 8; if (selected) g.setColor(highlightColor); else g.setColor(bgColor); g.fillRect(x, y, width, height); if(printString != null) { switch (type) { case Cell.LABEL: g.setColor(fgColor); if(char_count < printString.length()) g.drawString(printString.substring(0, char_count), x, y + (height / 2) + 5); else g.drawString(printString, x, y + (height / 2) + 5); break; case Cell.FORMULA: g.setColor(Color.blue); if(char_count < valueString.length()) g.drawString(valueString.substring(0, char_count), x, y + (height / 2) + 5); else g.drawString(valueString, x, y + (height / 2) + 5); break; } } else { g.setColor(fgColor); g.drawString("", x, y + (height / 2) + 5); } needRedisplay = false; } } class Node { public static final int OP = 0; public static final int VALUE = 1; public static final int CELL = 2; public static final int FUNC = 3; public static final int PRE = 4; int type; Node left; Node right; int row; int column; double value; char op; String func; Vector args; public Node() { type = Node.VALUE; left = null; right = null; row = -1; column = -1; value = 0; op = 0; func = new String(); args = new Vector(); } public Node(Node n) { type = n.type; left = n.left; right = n.right; row = n.row; column = n.column; value = n.value; op = n.op; func = new String(n.func); args = new Vector(); for(Enumeration e = n.args.elements(); e.hasMoreElements(); ) args.addElement(new Node((Node)e.nextElement())); } } class InputField { final int maxchars = 50; Applet app; String sval; char buffer[]; int nChars; int width; int height; Color bgColor; Color fgColor; public InputField(String initValue, Applet app, int width, int height, Color bgColor, Color fgColor) { this.width = width; this.height = height; this.bgColor = bgColor; this.fgColor = fgColor; this.app = app; buffer = new char[maxchars]; nChars = 0; if (initValue != null) { initValue.getChars(0, initValue.length(), this.buffer, 0); nChars = initValue.length(); } sval = initValue; } public void setText(String val) { for(int i = 0; i < maxchars; i++) buffer[i] = 0; if(val == null) { sval = new String(""); nChars = 0; buffer[0] = 0; } else { val.getChars(0, val.length(), buffer, 0); nChars = val.length(); sval = new String(buffer).substring(0, nChars); } } public void paint(Graphics g, int x, int y) { g.setColor(bgColor); g.fillRect(x, y, width, height); g.setColor(fgColor); if(sval != null) g.drawString(sval + "_", x, y + (height / 2) + 3); else g.drawString("_", x, y + (height / 2) + 3); } public void keyDown(int key) { switch (key) { case 8: // delete --nChars; if(nChars < 0) nChars = 0; buffer[nChars] = 0; sval = new String(new String(buffer).substring(0, nChars)); break; case 10: // return break; default: if(nChars < maxchars) { buffer[nChars++] = (char)key; sval = new String(new String(buffer).substring(0, nChars)); } break; } ((spreadsheet)app).setCurrentValue(sval); app.repaint(); } } --------------167EB0E72781E494446B9B3D--