Problem with Sequential File and Arrays
Hey guys! I'm new to this forum, but I am desperately needing some help with this program. I normally post to Experts-Exchange but I'm getting no help there. I'm afraid I'm in over my head with this one. I've been working on this a few days now and I just can't get it working. I've tried to clean it up and separate the logic from the UI (I know you Java guru's hate when it's not seperate)...but any changes in these areas throw up more errors so I apologize if my code is a mess. The program is a mortgage calculator that should read the interest rates and terms for the arrays from an external text file. Then add a graph that displays the change in principal balance over the life of the loan.
Maybe I'm making it into a lot more than it is...but any help to clean up this mess would be greatly appreciated!
Code:
import java.awt.*;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.text.MessageFormat;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Wk5SunniMortgageCalculator extends JFrame implements ActionListener {
int term = 0;
double principal = 0;
double rate = 0;
double monthlyPayment = 0;
double interest = 0;
int notePeriod = 0;
int[] termArray;
double[] rateArray;
private float[] monthlyPrincipal;
private float[] interestPaid;
//reading from sequential file
public void load()
{
Reader fis;
try
{
fis = new InputStreamReader(getClass().getResourceAsStream("data.txt"));
BufferedReader b = new BufferedReader( fis );
String[] line = b.readLine( ).split(",");
termArray = new int[line.length];
for ( int i = 0; i < line.length; i++ )
{
termArray[ i ] = Integer.parseInt(line[i].trim());
}
line = b.readLine( ).split(",");
rateArray = new double[line.length];
for ( int i = 0; i < line.length; i++ )
{
rateArray[ i ] = Double.parseDouble(line[i].trim());
}
b.close();
fis.close();
}
catch ( Exception e1 )
{
e1.printStackTrace( );
}
}
JPanel row1 = new JPanel();
JLabel mortgageLabel = new JLabel("MORTGAGE PAYMENT CALCULATOR", JLabel.CENTER);
JPanel row2 = new JPanel(new GridLayout(1, 2));
JLabel principalLabel = new JLabel("Mortgage Principal $",JLabel.LEFT);
JTextField principalTxt = new JTextField(10);
JPanel row3 = new JPanel(new GridLayout(1, 2));
JLabel termLabel = new JLabel("Mortgage Term (Yrs)",JLabel.LEFT);
JTextField termTxt = new JTextField(10);
JPanel row4 = new JPanel(new GridLayout(1, 2));
JLabel rateLabel = new JLabel("Interest Rate (%)", JLabel.LEFT);
JTextField rateTxt = new JTextField(10);
JPanel row5 = new JPanel(new GridLayout(1, 2));
JLabel presetLabel = new JLabel("Preset Term and Interest Rate:", JLabel.LEFT);
JPanel row6 = new JPanel();
JComboBox choices = new;
JComboBox();
MessageFormat mf = new MessageFormat("{0} years at {1,number,#.##}%");
JLabel choiceLabel = new JLabel(" (choose rate)");
for (int i = 0; i < termArray.length; i++)
{
options.addItem(mf.format(new Object[] { new Integer(termArray [i]), new Double(rateArray[i])}));
}
JPanel row6 = new JPanel(new GridLayout(1, 2));
JLabel monthlyPaymentLabel = new JLabel("Monthly Payment $", JLabel.LEFT);
JTextField monthlyPaymentTxt = new JTextField(10);
//create buttons
JPanel button = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
JButton graphButton = new JButton("Display Graph");
JButton amortizeButton = new JButton("Amortize Payments");
JButton clearButton = new JButton("Clear");
JButton exitButton = new JButton("Exit");
JButton calculateButton = new JButton("Calculate");
//create textarea to display Amortize output
JTextArea displayArea = new JTextArea(10, 45);
JScrollPane scroll = new JScrollPane(displayArea);
public Wk5SunniMortgageCalculator()
{
super ("Mortgage Payment Calculator by S Kemen");
setSize(550, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = getContentPane();
}
public void init()
{
Border rowborder = new EmptyBorder( 3, 10, 3, 10 );
pane.add(row1);
row1.add(mortgageLabel);
row1.setMaximumSize( new Dimension( 10000, row1.getMinimumSize().height));
row1.setBorder( rowborder);
pane.add(row2);
row2.add(principalLabel);
row2.add(principalTxt);
row2.setMaximumSize( new Dimension( 10000, row2.getMinimumSize().height));
row2.setBorder( rowborder);
pane.add(row3);
row3.add(termLabel);
row3.add(termTxt);
row3.setMaximumSize( new Dimension( 10000, row3.getMinimumSize().height));
row3.setBorder( rowborder);
pane.add(row4);
row4.add(rateLabel);
row4.add(rateTxt);
row4.setMaximumSize( new Dimension( 10000, row4.getMinimumSize().height));
row4.setBorder( rowborder);
pane.add(row5);
row5.add(presetLabel);
row5.setMaximumSize( new Dimension( 10000, row4.getMinimumSize().height));
row5.setBorder( rowborder);
pane.add(row6);
row6.add(choiceLabel);
row6.setMaximumSize( new Dimension( 10000, row4.getMinimumSize().height));
row6.setBorder( rowborder);
radioPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 4, 4 ));
radioPanel.add(choices);
pane.add(radioPanel);
radioPanel.setMaximumSize( new Dimension( 10000, radioPanel.getMinimumSize().height));
radioPanel.setBorder( rowborder);
pane.add(row7);
row7.add(monthlyPaymentLabel);
row7.add(monthlyPaymentTxt);
monthlyPaymentTxt.setEnabled(false); //set payment amount uneditable
row7.setMaximumSize( new Dimension( 10000, row5.getMinimumSize().height));
row7.setBorder( rowborder);
//Add buttons
button.add(calculateButton);
button.add(clearButton);
button.add(exitButton);
button.add(amortizeButton);
button.add(graphButton);
pane.add(button);
button.setMaximumSize( new Dimension( 10000, button.getMinimumSize().height));
//scroll text pane for Amortize output
scroll.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
pane.add(scroll);
pane.setLayout(new BoxLayout( pane, BoxLayout.Y_AXIS));
setVisible(true);
setContentPane(pane);
//add listeners for buttons and combo box
choice.addActionListener(this);
clearButton.addActionListener(this);
exitButton.addActionListener(this);
calculateButton.addActionListener(this);
amortizeButton.addActionListener(this);
graphButton.addActionListener(this);
}
private JFrame mFrame = null;
public void actionPerformed(ActionEvent event)
{
Object command = event.getSource();
if(command == calculateButton) //function for Calculate button
{
try
{
principal = Double.parseDouble(principalTxt.getText());
}
catch(NumberFormatException e)
{
//catch null pointer exception if Principal is null
JOptionPane.showMessageDialog(null, "Invaild Entry! Please Try Again", "ERROR", JOptionPane.ERROR_MESSAGE);
}
try
{
//Get input from Term text box, checked first before combo box
term = Integer.parseInt(termTxt.getText());
rate = Double.parseDouble(rateTxt.getText()); //Input from Rate text box
}
//If Term and Rate are null, buttons are checked for input values
catch(NumberFormatException e)
{
//Set rate and term based on which item in the combobox is selected
//Still have to fill in this area for the combo box arrays
if
else
{
//If no option is selected and combo box null, this is an actual error.
JOptionPane.showMessageDialog(null, "Invaild Entry! Please Try Again", "ERROR", JOptionPane.ERROR_MESSAGE);
}
}
interest = rate / 100 / 12; //Monthly interst rate
notePeriod= term * 12; //Number of months over which loan is amortized
//calculation formula
monthlyPayment = (principal * interest) / (1 - Math.pow(1 + interest, -notePeriod));
//formatting variables
DecimalFormat df = new DecimalFormat("\u00A4#,##0.00"); //currency
DecimalFormat pf = new DecimalFormat("#,##0.00%"); //percentages
DecimalFormat mi = new DecimalFormat("#,##0.000%"); //percentages
monthlyPaymentTxt.setText("" + df.format(monthlyPayment));
}
if(command == clearButton) //Function for Clear button
{
principalTxt.setText(null);
monthlyPaymentTxt.setText(null);
rateTxt.setText(null);
termTxt.setText(null);
displayArea.setText(null);
}
if(command == exitButton) //Function for Exit button
{
System.exit(0);
}
if (command == amortizeButton) //Function for Amortize button
{
//Amoritization variables
double loanBalance = notePeriod * monthlyPayment;
double interestPaid = 0; //Interest paid on the loan
double monthlyPrincipal = 0; //Principal in each monthly payment
double principalBalance = principal; //running total of principal after payment
String titles = "Month\t Principal\t\tInterest\t\tBalance\n"; //String for output
displayArea.setText(titles);
displayArea.append(""); //Inserts a blank line
//This loop is used to calculate and display the payment schedule information
for(int counter = 0; counter < term * 12 - 0; counter++) //start outer loop
{
//start inner loop
nterestPaid = principalBalance * interest;
monthlyPrincipal = monthlyPayment - interestPaid;
loanBalance = loanBalance - monthlyPayment;
principalBalance = principalBalance - monthlyPrincipal;
//formatting variables
DecimalFormat df = new DecimalFormat("\u00A4#,##0.00"); //currency
DecimalFormat pf = new DecimalFormat("#,##0.00%"); //percentages
DecimalFormat mi = new DecimalFormat("#,##0.000%"); //percentages
//formatting for output
displayArea.setCaretPosition(0);
displayArea.append((counter +1) + ")\t"+df.format(monthlyPrincipal)+"\t\t"
+df.format(interestPaid)+"\t\t"+df.format(principalBalance)+"\n");
}
}
if (command == graphButton) //Function for Graph button
{
mFrame = new JFrame("Mortgage Payment Graph");
mFrame.getContentPane().add(new GraphPanel(monthlyPrincipal, interestPaid));
mFrame.setSize(800,600);
mFrame.setLocation(200,100);
}
}
class GraphPanel extends JPanel
{
final int
HPAD = 60,
VPAD = 40;
int[] data;
float[] principleData;
float[] interestData;
public GraphPanel(float[] p, float[] i)
{
principleData = p;
interestData = i;
font = new Font("lucida sans regular", Font.PLAIN, 16);
setBackground(Color.white);
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(font);
FontRenderContext frc = g2.getFontRenderContext();
int w = getWidth();
int h = getHeight();
// scales
float xInc = (w - HPAD - VPAD) / (interestData.length - 1);//11f; //distance between each plot
float yInc = (h - 2*VPAD) / 10f;
int[] dataVals = getDataVals(); //min and max values for y-axis
float yScale = dataVals[2] / 10f;
// ordinate (y - axis)
g2.draw(new Line2D.Double(HPAD, VPAD, HPAD, h - VPAD));
// plot tic marks
float x1 = HPAD, y1 = VPAD, x2 = HPAD - 3, y2;
for(int j = 0; j < 10; j++)
{
g2.draw(new Line2D.Double(x1, y1, x2, y1));
y1 += yInc;
}
// labels
String text; LineMetrics lm;
float xs, ys, textWidth, height;
for(int j = 0; j <= 10; j++)
{
text = String.valueOf(dataVals[1] - (int)(j * yScale));
textWidth = (float)font.getStringBounds(text, frc).getWidth();
lm = font.getLineMetrics(text, frc);
height = lm.getAscent();
xs = HPAD - textWidth - 7;
ys = VPAD + (j * yInc) + height/2;
g2.drawString(text, xs, ys);
if(j == 0) g2.drawString("Principal", xs, ys - 15);
}
// abcissa (x - axis)
g2.draw(new Line2D.Double(HPAD, h - VPAD, w - VPAD, h - VPAD));
// tic marks
x1 = HPAD; y1 = h - VPAD; y2 = y1 + 3;
for(int j = 0; j < interestData.length; j++)
{
g2.draw(new Line2D.Double(x1, y1, x1, y2));
x1 += xInc;
}
// labels
ys = h - VPAD;
for(int j = 0; j < interestData.length; j++)
{
text = String.valueOf(j + 1);
textWidth = (float)font.getStringBounds(text, frc).getWidth();
lm = font.getLineMetrics(text, frc);
height = lm.getHeight();
xs = HPAD + j * xInc - textWidth/2;
g2.drawString(text, xs, ys + height);
if( j == (interestData.length - 1)) g2.drawString("Year", (int)w /2 , ys + height + 15);
}
// plot data
float yy2 = 0, yy1 = 0, xx2 = 0, xx1;
x1 = HPAD;
xx1 = HPAD;
yScale = (float)(h - 2*VPAD) / dataVals[2];
for(int j = 0; j < interestData.length; j++)
{
g.setColor(Color.blue);
y1 = VPAD + (h - 2*VPAD) - (principalData[j] - dataVals[0]) * yScale;
g2.fillOval((int)x1, (int)y1 - 2, 5, 5);
if(j > 0)
g2.draw(new Line2D.Double(x1, y1, x2, y2));
x2 = x1;
y2 = y1;
x1 += xInc;
g.setColor(Color.red);
yy1 = VPAD + (h - 2*VPAD) - (interestData[j] - dataVals[0]) * yScale;
g2.fillOval((int)xx1, (int)yy1 - 1, 5, 5);
if(j > 0)
g2.draw(new Line2D.Double(xx1, yy1, xx2, yy2));
xx2 = xx1;
yy2 = yy1;
xx1 += xInc;
}
}
private int[] getDataVals()
{
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
int j = interestData.length -1;
max = (int)principleData[j];
min = (int)interestData[j];
int span = max - min;
return new int[] { min, max, span };
}
}
public static void main (String[] arguments) //Main Method
{
Wk5SunniMortgageCalculator smc = new Wk5SunniMortgageCalculator();
smc.setVisible(true);
smc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
} //End of program
The external file (data.txt) contains the following:
7,5.35
15,5.5
20,5.65
30,5.75
Feel free to criticize or offer advice :o Thank you!