com.jidesoft.swing.Calculator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jide-oss Show documentation
Show all versions of jide-oss Show documentation
JIDE Common Layer (Professional Swing Components)
/*
* @(#)Calculator.java 7/11/2006
*
* Copyright 2002 - 2006 JIDE Software Inc. All rights reserved.
*/
package com.jidesoft.swing;
import com.jidesoft.utils.PortingUtils;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
/**
* Calculator is a component that can do simple arithmetic calculation. Since it extends JPanel, you can use it
* at any place in your application.
*
* To make it more flexible, the Calculator has no text field to display the result. You can create your own
* JTextField or JLabel to display the result. Here is a simple example to create a text field and associate it with
* Calculator.
*
* final JTextField textField = new JTextField();
* textField.setColumns(20);
* textField.setHorizontalAlignment(JTextField.TRAILING);
* Calculator calculator = new Calculator();
* calculator.registerKeyboardActions(textField, JComponent.WHEN_FOCUSED);
* calculator.addPropertyChangeListener(Calculator.PROPERTY_DISPLAY_TEXT, new PropertyChangeListener() {
* public void propertyChange(PropertyChangeEvent evt) {
* textField.setText("" + evt.getNewValue());
* }
* });
* calculator.clear();
*
* With the code above, user can type in directly into text field and do the calculation. If you just want to display
* the result and don't mind if the text field accepts keyboard input, you don't need to call registerKeyboardActions
* method.
*
* All numeric and operator keys work as expected. Here are a few special keys that worth mentioning - 'C', 'c'
* or ESC to clear current result
- '!' to make current displayed number from positive to negative (or from negative
* to positive)
- ENTER is equivalent to '='..
*
* Another interesting way to use Calculator is to use it without using GUI.
*
* Calculator calculator = new Calculator();
* calculator.input('1');
* calculator.input('0');
* calculator.input('*');
* calculator.input('2');
* calculator.input('4');
* calculator.input('=');
* System.out.println("10 * 24 = " + calculator.getDisplayText());
*
* The print out will be "10 * 24 = 240".
*
* There are several methods you can use to get internal state of the Calculator. - {@link #getDisplayText()}:
* to get the result that should be displayed. Please note, this method return a string.
- {@link #getResult()}: to
* get the last calculated result. This method returns a double value.
- {@link #getOperator()}: to get the current
* operator
- {@link #isOverflow()}: to check if there is an overflow. Usually if you try to divide by zero, you will
* get an overflow.
*/
public class Calculator extends JPanel implements ActionListener {
private double _result;
private StringBuffer _op1;
private StringBuffer _op2;
private int _operator = OPERATOR_NONE;
private String _displayText;
private boolean _overflow = false;
private boolean _negationOp1 = true;
private boolean _backspaceOp1 = false;
private boolean _backspaceOp2 = false;
private boolean _clearOperatorPending = false;
private boolean _isFakedEqualPressed = false; // When it is true, it means the focus is lost. So the result should not be updated.
private boolean _resultCalculated = false;
public static final int OPERATOR_NONE = -1;
public static final int OPERATOR_ADD = 0;
public static final int OPERATOR_MINUS = 1;
public static final int OPERATOR_MULTIPLY = 2;
public static final int OPERATOR_DIVIDE = 3;
private AbstractButton _addButton;
private AbstractButton _minusButton;
private AbstractButton _multiplyButton;
private AbstractButton _divideButton;
private AbstractButton _pointButton;
private AbstractButton _equalButton;
private AbstractButton _backspaceButton;
private AbstractButton _clearButton;
private AbstractButton _negativeButton;
private AbstractButton[] _numberButtons;
private char _actualCharPoint;
private NumberFormat _displayFormat;
public static final char CHAR_CLEAR = 'c';
public static final char CHAR_POINT = '.';
public static final char CHAR_ADD = '+';
public static final char CHAR_MINUS = '-';
public static final char CHAR_MULTIPLY = '*';
public static final char CHAR_DIVIDE = '/';
public static final char CHAR_EQUAL = '=';
public static final char CHAR_NEGATIVE = '!';
public static final char CHAR_BACKSPACE = '<';
public static final char CHAR_0 = '0';
public static final char CHAR_1 = '1';
public static final char CHAR_2 = '2';
public static final char CHAR_3 = '3';
public static final char CHAR_4 = '4';
public static final char CHAR_5 = '5';
public static final char CHAR_6 = '6';
public static final char CHAR_7 = '7';
public static final char CHAR_8 = '8';
public static final char CHAR_9 = '9';
public static final String PROPERTY_DISPLAY_TEXT = "displayText";
public static final String PROPERTY_OPERATOR = "operator";
private int _buttonWidth = 24;
private int _buttonHeight = 24;
private int _buttonGap = 2;
/**
* Creates a Calculator
.
*/
public Calculator() {
_op1 = new StringBuffer();
_op2 = new StringBuffer();
_displayFormat = NumberFormat.getNumberInstance();
configureNumberFormat();
initComponents();
registerKeyboardActions(this, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
@Override
public void setLocale(Locale l) {
unregisterKeyboardActions(this);
super.setLocale(l);
_op1 = new StringBuffer();
_op2 = new StringBuffer();
_displayFormat = NumberFormat.getNumberInstance(getLocale());
configureNumberFormat();
_actualCharPoint = getDisplayFormat().format(2.01).charAt(1);
_pointButton.setText("" + _actualCharPoint);
registerKeyboardActions(this, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
/**
* Configures the number format for displaying purpose.
*/
protected void configureNumberFormat() {
_displayFormat.setMaximumFractionDigits(20);
_displayFormat.setMinimumFractionDigits(0);
_displayFormat.setGroupingUsed(false);
}
/**
* Checks if the key event a valid key event that can be accepted by the Calculator.
*
* @param keyEvent the key event.
* @return true if it is a valid key event for the Calculator.
*/
public static boolean isValidKeyEvent(KeyEvent keyEvent) {
char c = keyEvent.getKeyChar();
return (keyEvent.getModifiers() & ~KeyEvent.SHIFT_MASK) != 0 // if it has any modify, ignore it
|| Character.isDigit(c) || isOperator(keyEvent)
|| isEnterOrEqual(keyEvent)
|| c == KeyEvent.VK_PERIOD || c == KeyEvent.VK_COMMA || c == CHAR_CLEAR || Character.toLowerCase(c) == CHAR_CLEAR
|| c == KeyEvent.VK_ESCAPE
|| c == KeyEvent.VK_BACK_SPACE;
}
/**
* Checks if the key event a key event for operators. In the other words, if it is {@link #CHAR_ADD}, {@link
* #CHAR_MINUS}, {@link #CHAR_MULTIPLY} or {@link #CHAR_DIVIDE}, this method will return true.
*
* @param keyEvent the key event.
* @return true if it is a valid key event is an operator.
*/
public static boolean isOperator(KeyEvent keyEvent) {
char c = keyEvent.getKeyChar();
return c == CHAR_ADD || c == CHAR_MINUS || c == CHAR_MULTIPLY || c == CHAR_DIVIDE;
}
/**
* Checks if the key event a key event for enter. In the other words, if it is {@link KeyEvent#VK_ENTER} or {@link
* KeyEvent#VK_EQUALS}, this method will return true.
*
* @param keyEvent the key event.
* @return true if it is a valid key event is an enter key or an equal key.
*/
public static boolean isEnterOrEqual(KeyEvent keyEvent) {
char c = keyEvent.getKeyChar();
return c == KeyEvent.VK_ENTER || c == KeyEvent.VK_EQUALS;
}
/**
* Registers necessary keyboard actions onto the component. Usually the component is a JTextField
.
*
* @param component the component where the key input will be taken and passed to the Calculator
.
* @param condition the condition as defined in {@link JComponent#registerKeyboardAction(java.awt.event.ActionListener,
* javax.swing.KeyStroke, int)}.
*/
public void registerKeyboardActions(JComponent component, int condition) {
boolean isCellEditor = isCellEditor();
component.registerKeyboardAction(this, "" + CHAR_ADD, KeyStroke.getKeyStroke(CHAR_ADD), condition);
component.registerKeyboardAction(this, "" + CHAR_MINUS, KeyStroke.getKeyStroke(CHAR_MINUS), condition);
component.registerKeyboardAction(this, "" + CHAR_MULTIPLY, KeyStroke.getKeyStroke(CHAR_MULTIPLY), condition);
component.registerKeyboardAction(this, "" + CHAR_DIVIDE, KeyStroke.getKeyStroke(CHAR_DIVIDE), condition);
component.registerKeyboardAction(this, "" + CHAR_EQUAL, KeyStroke.getKeyStroke(CHAR_EQUAL), condition);
if (!isCellEditor)
component.registerKeyboardAction(this, "" + CHAR_EQUAL, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), condition);
component.registerKeyboardAction(this, "" + CHAR_0, KeyStroke.getKeyStroke(CHAR_0), condition);
component.registerKeyboardAction(this, "" + CHAR_1, KeyStroke.getKeyStroke(CHAR_1), condition);
component.registerKeyboardAction(this, "" + CHAR_2, KeyStroke.getKeyStroke(CHAR_2), condition);
component.registerKeyboardAction(this, "" + CHAR_3, KeyStroke.getKeyStroke(CHAR_3), condition);
component.registerKeyboardAction(this, "" + CHAR_4, KeyStroke.getKeyStroke(CHAR_4), condition);
component.registerKeyboardAction(this, "" + CHAR_5, KeyStroke.getKeyStroke(CHAR_5), condition);
component.registerKeyboardAction(this, "" + CHAR_6, KeyStroke.getKeyStroke(CHAR_6), condition);
component.registerKeyboardAction(this, "" + CHAR_7, KeyStroke.getKeyStroke(CHAR_7), condition);
component.registerKeyboardAction(this, "" + CHAR_8, KeyStroke.getKeyStroke(CHAR_8), condition);
component.registerKeyboardAction(this, "" + CHAR_9, KeyStroke.getKeyStroke(CHAR_9), condition);
component.registerKeyboardAction(this, "" + _actualCharPoint, KeyStroke.getKeyStroke(_actualCharPoint), condition);
component.registerKeyboardAction(this, "" + CHAR_BACKSPACE, KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), condition);
if (!isCellEditor)
component.registerKeyboardAction(this, "" + CHAR_CLEAR, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), condition);
if (!isCellEditor)
component.registerKeyboardAction(this, "" + CHAR_CLEAR, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
component.registerKeyboardAction(this, "" + CHAR_CLEAR, KeyStroke.getKeyStroke(Character.toUpperCase(CHAR_CLEAR)), condition);
component.registerKeyboardAction(this, "" + CHAR_CLEAR, KeyStroke.getKeyStroke(Character.toLowerCase(CHAR_CLEAR)), condition);
}
/**
* Unregisters the keyboard actions you registered using {@link #registerKeyboardActions(javax.swing.JComponent,
* int)}.
*
* @param component the component.
*/
public void unregisterKeyboardActions(JComponent component) {
boolean isCellEditor = isCellEditor();
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_ADD));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_MINUS));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_MULTIPLY));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_DIVIDE));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_EQUAL));
if (!isCellEditor) component.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_0));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_1));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_2));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_3));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_4));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_5));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_6));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_7));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_8));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(CHAR_9));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(_actualCharPoint));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0));
if (!isCellEditor) component.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(Character.toUpperCase(CHAR_CLEAR)));
component.unregisterKeyboardAction(KeyStroke.getKeyStroke(Character.toLowerCase(CHAR_CLEAR)));
}
protected void initComponents() {
setLayout(new CalculatorLayoutManager());
add(_addButton = createButton("+"));
add(_minusButton = createButton("-"));
add(_multiplyButton = createButton("*"));
add(_divideButton = createButton("/"));
_numberButtons = new AbstractButton[10];
for (int i = 0; i <= 9; i++) {
add(_numberButtons[i] = createButton("" + i));
}
_actualCharPoint = getDisplayFormat().format(2.01).charAt(1);
add(_pointButton = createButton("" + _actualCharPoint));
add(_equalButton = createButton("="));
add(_backspaceButton = createButton(null, new BackspaceIcon()));
add(_negativeButton = createButton(null, new ToggleNegativeIcon()));
add(_clearButton = createButton("C"));
}
/**
* Get the flag indicating if the result was calculated at least once.
*
* @return true if the result was calculated at least once. Otherwise false.
*/
public boolean isResultCalculated() {
return _resultCalculated;
}
/**
* Set the flag indicating if the result was calculated at least once.
*
* @param resultCalculated the flag
*/
public void setResultCalculated(boolean resultCalculated) {
_resultCalculated = resultCalculated;
}
class BackspaceIcon implements Icon {
public BackspaceIcon() {
}
public void paintIcon(Component c, Graphics g, int x, int y) {
Object save = JideSwingUtilities.setupShapeAntialiasing(g);
Color old = g.getColor();
g.setColor(c.getForeground());
g.drawLine(x, y + 3, x + 3, y);
g.drawLine(x, y + 3, x + 3, y + 6);
g.drawLine(x + 3, y + 3, x + 7, y + 3);
g.setColor(old);
JideSwingUtilities.restoreShapeAntialiasing(g, save);
}
public int getIconWidth() {
return 7;
}
public int getIconHeight() {
return 7;
}
}
class ToggleNegativeIcon implements Icon {
public ToggleNegativeIcon() {
}
public void paintIcon(Component c, Graphics g, int x, int y) {
Color old = g.getColor();
Object save = JideSwingUtilities.setupShapeAntialiasing(g);
g.setColor(c.getForeground());
g.drawLine(x, y + 2, x + 6, y + 2);
g.drawLine(x, y + 7, x + 6, y + 7);
g.drawLine(x + 3, y, x + 3, y + 5);
g.setColor(old);
JideSwingUtilities.restoreShapeAntialiasing(g, save);
}
public int getIconWidth() {
return 7;
}
public int getIconHeight() {
return 7;
}
}
/**
* Creates the button that is used in the Calculator. By default, it will create a JideButton. Here is the code. You
* can override it to create your own button. This method is used to create all buttons except the backspace and the
* +/- button. So if you want to override it, it's better to override {@link #createButton(String,
* javax.swing.Icon)} method.
*
* @param text the text on the button.
* @return the button.
*/
protected AbstractButton createButton(String text) {
return createButton(text, null);
}
/**
* Creates the button that is used in the Calculator. By default, it will create a JideButton. Here is the code. You
* can override it to create your own button.
*
* AbstractButton button = new JideButton(text, icon);
* button.setOpaque(true);
* button.setContentAreaFilled(true);
* button.setRequestFocusEnabled(false);
* button.setFocusable(false);
* button.addActionListener(this);
* return button;
*
*
* @param text the text on the button.
* @param icon the icon on the button.
* @return the button.
*/
protected AbstractButton createButton(String text, Icon icon) {
AbstractButton button = new JideButton(text, icon);
button.setOpaque(true);
button.setContentAreaFilled(true);
button.setRequestFocusEnabled(false);
button.setFocusable(false);
button.addActionListener(this);
return button;
}
/**
* Checks if the calculator is in overflow state.
*
* @return true if overflow.
*/
public boolean isOverflow() {
return _overflow;
}
/**
* Sets the overflow flag.
*
* @param overflow the overflow flag.
*/
public void setOverflow(boolean overflow) {
_overflow = overflow;
}
/**
* Inputs a char to the calculator. Please note, not all chars are acceptable. Valid chars are defined in {@link
* Calculator} class as CHAR_XXX constants.
*
* @param c the char input char.
*/
public void input(char c) {
if (CHAR_CLEAR == Character.toLowerCase(c) || CHAR_CLEAR == Character.toUpperCase(c)) {
clear();
return;
}
if (_overflow) {
beep();
return;
}
if (Character.isDigit(c) || _actualCharPoint == c) {
if (_clearOperatorPending) {
setOperator(OPERATOR_NONE);
_op1.setLength(0);
_clearOperatorPending = false;
}
if (getOperator() == OPERATOR_NONE) {
if (_actualCharPoint != c || _op1.indexOf("" + _actualCharPoint) == -1) {
_op1.append(c);
_backspaceOp1 = true;
_backspaceOp2 = false;
setDisplayText(_op1.toString());
}
else {
beep();
}
}
else {
if (_actualCharPoint != c || _op2.indexOf("" + _actualCharPoint) == -1) {
_op2.append(c);
_backspaceOp2 = true;
_backspaceOp1 = false;
setDisplayText(_op2.toString());
}
else {
beep();
}
}
}
else {
switch (c) {
case CHAR_ADD:
operatorPressed(OPERATOR_ADD);
break;
case CHAR_MINUS:
operatorPressed(OPERATOR_MINUS);
break;
case CHAR_MULTIPLY:
operatorPressed(OPERATOR_MULTIPLY);
break;
case CHAR_DIVIDE:
operatorPressed(OPERATOR_DIVIDE);
break;
case CHAR_EQUAL:
calculateResult(true);
_clearOperatorPending = true;
break;
case CHAR_NEGATIVE:
if (_negationOp1) {
negativePressed(_op1);
setDisplayText(_op1.toString());
}
else {
negativePressed(_op2);
setDisplayText(_op2.toString());
}
break;
case CHAR_BACKSPACE:
if (_backspaceOp1) {
backspacePressed(_op1);
setDisplayText(_op1.toString());
}
else if (_backspaceOp2) {
backspacePressed(_op2);
setDisplayText(_op2.toString());
}
else {
beep();
}
break;
}
}
}
private void operatorPressed(int operator) {
if (_op1.length() == 0) { // _op1 does not have input yet, make it 0
_op1.append("0");
}
else if (getOperator() == OPERATOR_NONE || _clearOperatorPending) { // normal process or just pressed =
_op2.setLength(0);
calculateResult(false);
}
else {
if (_op2.length() == 0) { // two operators input continuously
beep();
return;
}
else { // enable 3+3+3
_isFakedEqualPressed = false;
calculateResult(true);
_op1.setLength(0);
_op1.append(getDisplayFormat().format((Double) _result));
_op2.setLength(0);
}
}
setOperator(operator);
_negationOp1 = false;
_clearOperatorPending = false;
}
protected void beep() {
PortingUtils.notifyUser();
}
private void negativePressed(StringBuffer buf) {
if (buf.length() == 0) {
return;
}
if (buf.charAt(0) == CHAR_MINUS) {
buf.deleteCharAt(0);
}
else {
buf.insert(0, CHAR_MINUS);
}
}
private void backspacePressed(StringBuffer buf) {
if (buf.length() == 0) {
return;
}
buf.deleteCharAt(buf.length() - 1);
}
/**
* Update the result as if the equal was pressed. This method can be used while Enter key is pressed and you need
* keep the calculated result.
*/
public void updateResult() {
_isFakedEqualPressed = false;
calculateResult(true);
}
private void calculateResult(boolean equalPressed) {
if (getOperator() == OPERATOR_NONE) {
return;
}
if (_op1.length() == 0) {
beep();
return;
}
if (equalPressed) {
if (_op2.length() == 0) {
_op2.append(_op1);
}
}
else if (_op2.length() == 0) {
return;
}
Double op1;
Double op2;
try {
op1 = getDisplayFormat().parse(_op1.toString()).doubleValue();
op2 = getDisplayFormat().parse(_op2.toString()).doubleValue();
}
catch (ParseException e) {
op1 = 0.0;
op2 = 0.0;
}
if (!_isFakedEqualPressed) {
try {
switch (getOperator()) {
case OPERATOR_ADD:
_result = op1 + op2;
break;
case OPERATOR_MINUS:
_result = op1 - op2;
break;
case OPERATOR_MULTIPLY:
_result = op1 * op2;
break;
case OPERATOR_DIVIDE:
if (op2 == 0) {
_result = Double.NaN;
_overflow = true;
}
else {
_result = op1 / op2;
}
break;
}
}
catch (Exception e) {
_overflow = true;
}
}
if (_overflow) {
setDisplayText("E");
}
else {
setResultCalculated(true);
_op1.setLength(0);
if (_displayFormat != null) {
String displayText = _displayFormat.format(_result);
setDisplayText(displayText);
}
else {
setDisplayText("" + _result);
}
_op1.append(getDisplayText());
_negationOp1 = true;
_backspaceOp1 = true;
_backspaceOp2 = false;
}
}
private void clearOps() {
setOperator(OPERATOR_NONE);
_op1.setLength(0);
_op2.setLength(0);
}
/**
* Clears the internal state and reset the calculator.
*/
public void clear() {
clearOps();
_overflow = false;
_clearOperatorPending = false;
setDisplayText("0");
}
/**
* Gets the last calculated result.
*
* @return the last calculated result.
*/
public double getResult() {
return _result;
}
/**
* Gets the display text.
*
* @return the display text.
*/
public String getDisplayText() {
return _displayText;
}
/**
* Sets the display text and fire property change event on property named {@link #PROPERTY_DISPLAY_TEXT}.
*
* @param displayText the displayed text.
*/
public void setDisplayText(String displayText) {
String old = _displayText;
_displayText = displayText;
firePropertyChange(PROPERTY_DISPLAY_TEXT, old, _displayText);
}
/**
* Gets the current operator.
*
* @return the current operator.
*/
public int getOperator() {
return _operator;
}
/**
* Sets the operator and fire property change event on property named {@link #PROPERTY_OPERATOR}.
*
* @param operator the operator.
*/
public void setOperator(int operator) {
int old = _operator;
if (old != operator) {
_operator = operator;
firePropertyChange(PROPERTY_OPERATOR, new Integer(old), new Integer(operator));
}
}
private class CalculatorLayoutManager implements LayoutManager {
public CalculatorLayoutManager() {
}
public void addLayoutComponent(String name, Component comp) {
}
public void removeLayoutComponent(Component comp) {
}
public Dimension preferredLayoutSize(Container parent) {
return minimumLayoutSize(parent);
}
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(getButtonWidth() * 4 + getButtonGap() * 3, getButtonHeight() * 5 + getButtonGap() * 4);
}
public void layoutContainer(Container parent) {
int x = 0;
int y = 0;
int w = getButtonWidth();
int h = getButtonHeight();
int gap = getButtonGap();
_numberButtons[7].setBounds(x, y, w, h);
x += w + gap;
_numberButtons[8].setBounds(x, y, w, h);
x += w + gap;
_numberButtons[9].setBounds(x, y, w, h);
x += w + gap;
_divideButton.setBounds(x, y, w, h);
x = 0;
y += h + gap;
_numberButtons[4].setBounds(x, y, w, h);
x += w + gap;
_numberButtons[5].setBounds(x, y, w, h);
x += w + gap;
_numberButtons[6].setBounds(x, y, w, h);
x += w + gap;
_multiplyButton.setBounds(x, y, w, h);
x = 0;
y += h + gap;
_numberButtons[1].setBounds(x, y, w, h);
x += w + gap;
_numberButtons[2].setBounds(x, y, w, h);
x += w + gap;
_numberButtons[3].setBounds(x, y, w, h);
x += w + gap;
_minusButton.setBounds(x, y, w, h);
x = 0;
y += h + gap;
_numberButtons[0].setBounds(x, y, w, h);
x += w + gap;
_pointButton.setBounds(x, y, w, h);
x += w + gap;
_negativeButton.setBounds(x, y, w, h);
x += w + gap;
_addButton.setBounds(x, y, w, h);
x = 0;
y += h + gap;
_clearButton.setBounds(x, y, w, h);
x += w + gap;
_backspaceButton.setBounds(x, y, w, h);
x += w + gap;
_equalButton.setBounds(x, y, w * 2 + gap, h);
}
}
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (_addButton == source) {
input(CHAR_ADD);
}
else if (_minusButton == source) {
input(CHAR_MINUS);
}
else if (_multiplyButton == source) {
input(CHAR_MULTIPLY);
}
else if (_divideButton == source) {
input(CHAR_DIVIDE);
}
else if (_equalButton == source) {
_isFakedEqualPressed = e.getActionCommand() != null && e.getActionCommand().equals("Faked");
input(CHAR_EQUAL);
}
else if (_pointButton == source) {
input(_actualCharPoint);
}
else if (_negativeButton == source) {
input(CHAR_NEGATIVE);
}
else if (_backspaceButton == source) {
input(CHAR_BACKSPACE);
}
else if (_clearButton == source) {
input(CHAR_CLEAR);
}
else {
boolean found = false;
for (int i = 0; i <= 9; i++) {
if (_numberButtons[i] == source) {
input(("" + i).charAt(0));
found = true;
break;
}
}
if (!found) {
if (e.getActionCommand() != null && e.getActionCommand().length() > 0) {
fakePressButton(e.getActionCommand().charAt(0));
}
else {
fakePressButton(CHAR_EQUAL);
}
}
}
}
/**
* Press the button. By default, we will trigger the action directly on this button. However subclass can override
* it to call doClick to mimic the user pressing the button.
*
* @param button the button
*/
protected void fakePressButton(AbstractButton button) {
actionPerformed(new ActionEvent(button, 0, null));
}
private void fakePressButton(char c) {
if (c == _actualCharPoint) {
fakePressButton(_pointButton);
return;
}
switch (c) {
case CHAR_CLEAR:
fakePressButton(_clearButton);
break;
case CHAR_BACKSPACE:
fakePressButton(_backspaceButton);
break;
case CHAR_EQUAL:
fakePressButton(_equalButton);
break;
case CHAR_NEGATIVE:
fakePressButton(_negativeButton);
break;
case CHAR_ADD:
fakePressButton(_addButton);
break;
case CHAR_MINUS:
fakePressButton(_minusButton);
break;
case CHAR_MULTIPLY:
fakePressButton(_multiplyButton);
break;
case CHAR_DIVIDE:
fakePressButton(_divideButton);
break;
case CHAR_0:
fakePressButton(_numberButtons[0]);
break;
case CHAR_1:
fakePressButton(_numberButtons[1]);
break;
case CHAR_2:
fakePressButton(_numberButtons[2]);
break;
case CHAR_3:
fakePressButton(_numberButtons[3]);
break;
case CHAR_4:
fakePressButton(_numberButtons[4]);
break;
case CHAR_5:
fakePressButton(_numberButtons[5]);
break;
case CHAR_6:
fakePressButton(_numberButtons[6]);
break;
case CHAR_7:
fakePressButton(_numberButtons[7]);
break;
case CHAR_8:
fakePressButton(_numberButtons[8]);
break;
case CHAR_9:
fakePressButton(_numberButtons[9]);
break;
}
}
/**
* Gets the display format for the number.
*
* @return the display format for the number.
*/
public NumberFormat getDisplayFormat() {
return _displayFormat;
}
/**
* Sets the display format for the number.
*
* @param displayFormat the display format.
*/
public void setDisplayFormat(NumberFormat displayFormat) {
_displayFormat = displayFormat;
}
/**
* Calculates the pending calculation. If the Calculator has both operations and a valid operator, this method will
* do the calculation and set the display text and result.
*/
public void commit() {
if (!_clearOperatorPending) {
actionPerformed(new ActionEvent(_equalButton, 0, "Faked"));
}
}
/**
* Gets the button width.
*
* @return the button width.
*/
public int getButtonWidth() {
return _buttonWidth;
}
/**
* Sets the button width.
*
* @param buttonWidth the new button width.
*/
public void setButtonWidth(int buttonWidth) {
_buttonWidth = buttonWidth;
}
/**
* Gets the button height.
*
* @return the button height.
*/
public int getButtonHeight() {
return _buttonHeight;
}
/**
* Sets the button height.
*
* @param buttonHeight the new button height.
*/
public void setButtonHeight(int buttonHeight) {
_buttonHeight = buttonHeight;
}
/**
* Gets the gap between buttons. Default is 2.
*
* @return the gap between buttons.
*/
public int getButtonGap() {
return _buttonGap;
}
public void setButtonGap(int buttonGap) {
_buttonGap = buttonGap;
}
/**
* If this method return true, ENTER and ESCAPE key will be registered. Otherwise they will not be. The reason we do
* so because the two keys are conflicted with keys in JTable.
*
* @return true or false.
*/
protected boolean isCellEditor() {
return false;
}
public void setInitialValue(String value) {
_op1.setLength(0);
_op1.append(value);
_backspaceOp1 = true;
_backspaceOp2 = false;
setDisplayText(_op1.toString());
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
calculator.input('1');
calculator.input('0');
calculator.input('*');
calculator.input('2');
calculator.input('4');
calculator.input('=');
// System.out.println("10 * 24 = " + calculator.getDisplayText());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy